Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions apps/cli/ai/skills/creative-direction/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
---
name: creative-direction
description: Expand a vague site brief into a rich content and structure plan. Infer site type, choose appropriate pages and sections, commit to a fitting design direction, and briefly tell the user what you're building — then build it without asking.
user-invokable: false
---

# Creative Direction

When building a new WordPress site from a brief or vague prompt, use this skill to expand the brief into a rich content plan before writing any files. The goal: a user who types "a site for a bar" gets a site as complete and functional as one described with a detailed spec — because you make the right assumptions for them.

## Step 0 — Gauge the Brief

Before expanding, read what the user gave you and pick the right mode:

| Signal | Mode |
|--------|------|
| Site type is clear, content is thin ("a site for a bar") | **Auto-expand** — proceed to Step 1 |
| Site type is ambiguous ("a site for my business") | **Ask one question** to resolve it, then proceed to Step 1 |
| User already described pages, sections, or copy | **Skip this skill** — build what they asked for |
| User said "minimal", "one page", or "just a placeholder" | **Skip this skill** |

**The one question rule**: if you need to ask, ask a single, specific question that resolves the ambiguity (e.g. *"What kind of business is this for?"*). Do not ask multiple questions. Once you have the answer, proceed.

## Step 1 — Detect the Site Type

From the site name and prompt, infer what kind of site this is. Use your judgment freely — the following are common patterns, not an exhaustive list:

- **Bar / Nightclub / Venue** — bar, club, lounge, pub, tavern, speakeasy, nightlife
- **Restaurant / Café / Bakery** — restaurant, café, bistro, diner, bakery, brunch, eatery
- **Coffee Shop** — coffee, roastery, espresso, specialty/third-wave café
- **Portfolio (Photo / Design / Art)** — photographer, designer, artist, illustrator, studio
- **Agency / Creative Studio** — agency, studio, consulting, branding, digital
- **SaaS / Tech Product** — app, software, platform, tool, saas, product
- **Fitness / Gym / Yoga** — gym, fitness, yoga, pilates, crossfit, wellness, studio
- **Salon / Spa / Beauty** — salon, spa, beauty, barbershop, nail, aesthetics
- **Non-profit / Cause** — foundation, charity, org, cause, community
- **Professional Services** — law, dental, medical, clinic, accounting, finance
- **Personal Blog / Magazine** — blog, journal, magazine, editorial

For anything not on this list, reason by analogy: what kind of site does this business actually need?

## Step 2 — Expand Into Pages and Sections

Based on the site type, decide which pages and home-page sections to create. **Do not default to a minimal one-page placeholder** when the type clearly warrants more. The examples below are starting points — treat them as inspiration, not prescriptions. Adapt freely based on the site name and any details the user gave.

### Bar / Nightclub / Venue
**Pages**: Home, Menu (drinks & food), Events, Gallery, Contact + Hours
**Home sections**: hero (full-bleed, mood-setting), featured events teaser, menu highlight, gallery strip, reservation CTA
**Forms**: reservation/book-a-table (Jetpack contact form), newsletter signup
**Design signal**: dark & atmospheric; bold typography; energy

### Restaurant / Café / Bakery
**Pages**: Home, Menu, Reservations, Gallery, About, Contact
**Home sections**: hero with signature dish, menu teaser, about/story, gallery, reservation CTA
**Forms**: reservation form, contact form
**Design signal**: warm, inviting; food-photography-driven; approachable

### Coffee Shop
**Pages**: Home, Menu, Our Story, Locations, Contact
**Home sections**: hero, signature drinks highlight, story/craft section, locations map teaser, newsletter
**Forms**: newsletter signup, contact
**Design signal**: artisanal; hand-crafted feel; warm neutrals or bold brand color

### Portfolio (Photographer / Designer / Artist)
**Pages**: Home, Work/Portfolio (grid), About, Services, Contact
**Home sections**: full-bleed hero work, selected projects grid, brief about, services teaser, contact CTA
**Forms**: contact/inquiry form
**Design signal**: let the work breathe; minimal chrome; bold typography for name/headline

### Agency / Creative Studio
**Pages**: Home, Services, Work/Case Studies, Team, About, Contact
**Home sections**: hero value prop, services overview, selected work, team teaser, client logos, contact CTA
**Forms**: project inquiry form, contact
**Design signal**: confident; editorial; distinctive brand identity

### SaaS / Tech Product
**Pages**: Home (all-in-one landing), Pricing, About, Contact
**Home sections**: hero + one-line value prop, key features (3-up or 4-up), how-it-works, testimonials/social proof, pricing teaser, FAQ, final CTA
**Forms**: newsletter/waitlist signup, contact
**Design signal**: clean, modern; strong CTA hierarchy; trust signals prominent

### Fitness / Gym / Yoga Studio
**Pages**: Home, Classes/Schedule, Memberships & Pricing, Trainers, About, Contact
**Home sections**: hero (energy/motion), classes preview, membership tiers, trainer spotlight, testimonials, CTA
**Forms**: class booking / free trial signup, contact
**Design signal**: energetic or calm (match the discipline); strong photography

### Salon / Spa / Beauty
**Pages**: Home, Services & Pricing, Team, Gallery, Book Now, Contact
**Home sections**: hero, services overview, team highlights, gallery strip, booking CTA
**Forms**: booking/appointment form, contact
**Design signal**: luxe or friendly; clean; beauty imagery

### Non-profit / Cause
**Pages**: Home, Mission/About, Programs, Team, Get Involved/Donate, Contact
**Home sections**: mission statement hero, impact stats, programs overview, team, call to donate/volunteer
**Forms**: donation CTA (link to external), volunteer/contact form
**Design signal**: hopeful, trustworthy, human-centered

### Professional Services (Law / Medical / Dental / Accounting)
**Pages**: Home, Services, Team/Credentials, Testimonials, Contact
**Home sections**: hero (credibility-first), services grid, team highlight, testimonials, contact CTA
**Forms**: appointment / consultation request form
**Design signal**: authoritative, clean, trustworthy; conservative palette

### Personal Blog / Magazine
**Pages**: Home (recent posts), About, Category archives, Contact
**Home sections**: featured post hero, recent posts grid, about blurb, newsletter
**Forms**: newsletter signup, contact
**Design signal**: editorial; typography-driven; readable

## Step 3 — Pick a Design Direction

Commit to an aesthetic that genuinely fits the site name and type. Use the name as a creative brief — the right answer is different every time. Some examples of how a name can point to a direction:

- *"Boogie Bar"* → dark & moody; jazz/funk energy; amber + deep black; retro headlines
- *"Morning Light Bakery"* → warm, handcrafted; cream + terracotta; flowing serif display
- *"Apex Fitness"* → high-contrast; kinetic; strong sans-serif; black + electric accent
- *"Root Studio"* (yoga) → organic, grounded; earth tones; soft, breathing layout
- *"Hartley & Associates"* (law) → authoritative, minimal; navy + gold; refined serif

These are illustrations, not a template. Read the name.

## Step 4 — Brief the User in ≤4 Lines

Before building, tell the user what you decided in 2–4 short lines:

> *"Building a 5-page site for Boogie Bar: Home, Menu, Events, Gallery, and Contact. Dark & moody aesthetic with jazz-inspired typography and an amber/black palette. Includes a reservations form and a newsletter signup."*

Then proceed — **do not ask for approval on the brief itself**. You may have already asked a clarifying question in Step 0; the brief is not a second round of questions. Build it.

## What "Rich Content" Means

When generating page content, go beyond placeholder copy:

- **A bar**: write actual cocktail names and descriptions, real-sounding event nights ("Jazz Thursdays", "Trivia Night"), a gallery section
- **A bakery**: name actual pastries and breads; write a "baker's story" paragraph; include seasonal specials
- **A portfolio**: write a compelling headline and 3–5 project card stubs with realistic titles
- **A SaaS**: write feature names and one-liners, realistic pricing tiers, 2–3 testimonial quotes

Use the site name as context. Make it feel like a real site for that specific business, not a generic template.

## When to Skip This Skill

- User already provided detailed content (specific pages, copy, sections described)
- User explicitly said "keep it minimal", "one page", or "just a placeholder"
- Redesigning or updating an existing site
6 changes: 4 additions & 2 deletions apps/cli/ai/system-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ For any request that involves a WordPress site, you MUST first determine which s
Then continue with:

1. **Get site details**: Use site_info to get the site path, URL, and credentials.
2. **Plan the design**: Before writing any code, review the site spec (from the \`site-spec\` skill) and load the \`visual-design\` skill to plan the visual direction: layout, colors, typography, and spacing.
2. **Plan the design**: Before writing any code, review the site spec (from the \`site-spec\` skill). If the brief is vague — site type clear but pages, sections, and copy not yet specified — load the \`creative-direction\` skill to expand the brief and commit to a content/structure plan without asking for approval (skip it if the user gave a detailed spec or asked for minimal). Then load the \`visual-design\` skill to plan the visual direction: layout, colors, typography, and spacing.
3. **Write theme/plugin files**: For a brand new theme, call \`scaffold_theme\` first — it drops an unopinionated block-theme baseline (style.css with only the theme header, theme.json with appearanceTools only, functions.php with frontend + editor style enqueue, default templates and parts, empty assets/fonts and patterns dirs) and activates it by default. Then use Write and Edit to fill the scaffold (one part/template/file per turn). For plugins or for editing an existing theme, use Write and Edit directly under the site's wp-content/themes/ or wp-content/plugins/ directory.
4. **Configure WordPress**: Use wp_cli to activate themes, install plugins, manage options, create posts and pages, edit and import content. The site must be running. Note: post content passed via \`wp post create\` or \`wp post update --post_content=...\` need to be pre-validated for editability, follow the \`block-content\` skill, checked with validate_html_blocks, and validated/fixed with validate_and_fix_blocks. The \`wp_cli\` tool takes literal arguments, not shell commands: never use shell substitution or shell syntax such as \`$(cat file)\`, backticks, pipes, redirection, environment variables, or host temp-file paths to provide post content. Pass the literal content directly in \`--post_content=...\`, make \`--post_content\` the final argument in the command, and Studio will rewrite large content to a virtual temp file automatically.
5. **Check and fix block validity**: Run validate_html_blocks on block content first. If it reports invalid core/html blocks, rewrite only those blocks as editable core or plugin blocks and call validate_html_blocks again. Then call validate_and_fix_blocks with filePath whenever the content lives in a file. If validate_and_fix_blocks says an auto-fix was applied, the file already contains the fixed block content; do not manually replace markup or call validation again unless you intentionally change block markup afterward. Use the diff only to inspect class/nesting changes and update CSS selectors if needed. For inline content, use any returned fixed block content exactly as the replacement content.
Expand Down Expand Up @@ -218,4 +218,6 @@ For any site creation, redesign, landing page, homepage, layout, style, CSS, typ

For any page/post content, template or template-part content, block markup, block-theme layout, full-width section, or \`core/html\` use, load the \`block-content\` skill before writing markup or validating block content.

For forms, ecommerce, events, LMS, galleries/slideshows, embeds, SEO/performance plugin choices, or any feature that core WordPress blocks do not cleanly provide, load the \`plugin-recommendations\` skill before installing plugins or writing plugin-provided block markup.`;
For forms, ecommerce, events, LMS, galleries/slideshows, embeds, SEO/performance plugin choices, or any feature that core WordPress blocks do not cleanly provide, load the \`plugin-recommendations\` skill before installing plugins or writing plugin-provided block markup.

For new sites built from a vague brief — site type clear (e.g. "a site for a bar") but pages, sections, or copy not yet specified — load the \`creative-direction\` skill before deciding pages, sections, or design direction. If the brief is already detailed, or the user asks for "minimal" or "one page", skip this skill.`;
108 changes: 108 additions & 0 deletions apps/cli/ai/tests/creative-direction-skill.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { describe, expect, it } from 'vitest';
import { findSkill, loadSkills } from '../skills';
import { buildSystemPrompt } from '../system-prompt';

describe( 'creative-direction skill', () => {
describe( 'discoverability', () => {
it( 'is listed among available skills', () => {
const names = loadSkills().map( ( s ) => s.name );
expect( names ).toContain( 'creative-direction' );
} );

it( 'has a description', () => {
const skill = findSkill( 'creative-direction' );
expect( skill?.description ).toBeTruthy();
expect( skill?.description.length ).toBeGreaterThan( 20 );
} );

it( 'is not user-invokable (internal skill)', () => {
// Creative direction is loaded by the agent automatically, not typed by users.
// Verify the frontmatter doesn't mark it as user-invokable.
const skill = findSkill( 'creative-direction' );
// The skill body is everything after the frontmatter — user-invokable: true
// would appear in the raw file but is stripped from body by parseSkillFile.
// We test intent via the description not advertising it as a slash command.
expect( skill?.description ).not.toMatch( /slash command|type \//i );
} );
} );

describe( 'skill body content', () => {
it( 'has a Step 0 that selects the expansion mode', () => {
const skill = findSkill( 'creative-direction' );
// Step 0 should distinguish auto-expand, guided (one question), and skip paths
expect( skill?.body ).toMatch( /step 0/i );
expect( skill?.body ).toMatch( /auto.?expand|auto.?expan/i );
expect( skill?.body ).toMatch( /one question/i );
expect( skill?.body ).toMatch( /skip this skill/i );
} );

it( 'limits guided mode to a single clarifying question', () => {
const skill = findSkill( 'creative-direction' );
// Must not fan out into a multi-question wizard
expect( skill?.body ).toMatch( /one question rule|single.*question|ask.*one/i );
} );

it( 'covers site-type detection', () => {
const skill = findSkill( 'creative-direction' );
expect( skill?.body ).toContain( 'Bar' );
expect( skill?.body ).toContain( 'Restaurant' );
expect( skill?.body ).toContain( 'SaaS' );
expect( skill?.body ).toContain( 'Portfolio' );
} );

it( 'includes per-type content plans with pages and forms', () => {
const skill = findSkill( 'creative-direction' );
// Bar type should specify concrete pages and a reservations form
expect( skill?.body ).toContain( 'Menu' );
expect( skill?.body ).toContain( 'Events' );
expect( skill?.body ).toContain( 'Gallery' );
expect( skill?.body ).toContain( 'reservations' );
} );

it( 'instructs the agent to brief the user before building', () => {
const skill = findSkill( 'creative-direction' );
expect( skill?.body ).toMatch( /brief the user|tell the user/i );
expect( skill?.body ).toMatch( /do not ask for approval|proceed.*without asking/i );
} );

it( 'includes a skip condition for detailed prompts', () => {
const skill = findSkill( 'creative-direction' );
expect( skill?.body ).toMatch( /when to skip/i );
expect( skill?.body ).toMatch( /detailed content|keep it minimal/i );
} );

it( 'instructs the agent to use the site name as a design prompt', () => {
const skill = findSkill( 'creative-direction' );
expect( skill?.body ).toMatch( /name.*creative|name.*brief|use.*name/i );
} );
} );

describe( 'system prompt integration', () => {
it( 'is referenced in the local site workflow', () => {
const prompt = buildSystemPrompt();
expect( prompt ).toContain( 'creative-direction' );
} );

it( 'is invoked during the design planning step', () => {
const prompt = buildSystemPrompt();
// Verify the creative-direction skill reference appears in the workflow
// context (Plan the design step), not just anywhere in the prompt.
const planStep = prompt.match( /\*\*Plan the design\*\*[^\n]*/ )?.[ 0 ] ?? '';
expect( planStep ).toContain( 'creative-direction' );
} );

it( 'is NOT referenced in the remote site workflow', () => {
// Remote sites use the REST API workflow — creative direction is local only.
const prompt = buildSystemPrompt( {
remoteSite: { name: 'Test Site', url: 'https://test.wordpress.com', id: 123 },
} );
expect( prompt ).not.toContain( 'creative-direction' );
} );

it( 'instructs the agent to proceed without asking for approval', () => {
const prompt = buildSystemPrompt();
const planStep = prompt.match( /\*\*Plan the design\*\*[^\n]*/ )?.[ 0 ] ?? '';
expect( planStep ).toContain( 'without asking for approval' );
} );
} );
} );