- name
- direct
- description
- Set a redesign direction for an existing website. Analyzes the user's intent, picks a palette and visual direction, and writes the target spec (PRODUCT.md, DESIGN.md, DESIGN.json) plus a reasoning trace at stardust/direction.md. Use when the user asks to redesign a site, refresh the design, set a new design direction, define a redesign target, or invokes `$stardust direct` (`/stardust:direct` in Claude Code).
- license
- Apache-2.0
- compatibility
- Requires Node 22+, Playwright with Chromium resolvable from the project, playwright-cli on PATH, and the impeccable skill (github.com/pbakaus/impeccable) installed alongside stardust.
# stardust:direct
Resolve the user's freeform redesign intent into a complete **target
specification**: project-root `PRODUCT.md` and `DESIGN.md` (impeccable
format), a `DESIGN.json` sidecar with the divergence audit trail, and a
`stardust/direction.md` with the full reasoning trace.
`direct` produces the spec against which `prototype` and `migrate`
operate. It never writes prototypes or migrates pages — those are
downstream sub-commands.
## Inputs
- `<phrase>` — optional positional. The user's freeform intent
("make it better", "more Linear less Salesforce", "feel more premium
on a small screen"). If omitted, ask the user for one.
- `--re-direct` — optional. Replace the current direction with a new
one. Triggers stale-flagging on prototyped / approved / migrated
pages per `skills/stardust/reference/state-machine.md`. Default
behaviour without the flag is additive: if a direction already
exists, the agent asks before replacing.
- `--rebrand` — optional. Force rebrand mode (full divergence-seed
roll, no Mode A inheritance). Without it the default is
brand-faithful whenever the captured signal is `signal-strong`
(§ Mode-detection precedence).
- `--prep` — optional. Run in **migrate-prep mode**: confirm the
type catalog, finalize the module catalog, capture color
reservations and brand-level metadata defaults, re-evaluate
direction against the wider crawl. See § Prep mode below.
Typically invoked via the `prepare-migration` orchestrator.
- `--add-variant <name>` — optional. Add a new variant against
the existing direction without re-running intent reasoning or
mode detection. Writes `DESIGN-<name>.{md,json}` at the
project root and appends a per-variant section to
`stardust/direction.md`; existing prototypes are **not**
stale-flagged. See § Add-variant mode below.
## Setup
1. Run the master skill's setup
(`skills/stardust/SKILL.md` § Setup) — hard impeccable dep check,
context loader, state read.
2. Verify `stardust/state.json` exists and contains at least one
`extracted` page. If not, stop and recommend
`$stardust extract <url>` first.
3. Read `stardust/current/_brand-extraction.json`. If absent, stop —
extract did not complete brand-surface extraction; re-run extract.
3b. **Cross-site brand inputs** (when present). `state.json.designSource`
(design-donor mode: Mode A pins bind to the donor's derived
system) and `_brand-extraction.json.origins[]` (sibling-property
evidence: widens what can be amplified, not what is pinned).
Read `reference/cross-site-brand-inputs.md` for the pin and
evidence rules; surface the active mode in the plan.
4. Read `stardust/direction.md` if present. If a prior direction
exists and `--re-direct` was not passed, ask whether the user wants
to refine the existing direction or replace it.
5. **Validate provenance** (prep mode only). When `--prep` is
active, run the provenance validation per
`reference/prep-mode.md` before typing or module detection.
6. **Classify the captured brand signal.** Read
`_brand-extraction.json` and stamp one of:
- `signal-strong` — palette has ≥ 3 distinct colors (after
near-duplicate clustering and excluding pure black/white if they
are the only entries) **AND** at least one captured type family
is named in `type.headingFamily.name` or `type.bodyFamily.name`.
This is the common case for any extracted commercial site.
- `signal-thin` — palette has 2 colors OR no captured type family
OR `type.scaleAudit.kind === "ad-hoc"` with fewer than 3
distinct heading sizes. The brand exists but cannot fully
anchor a refresh.
- `signal-absent` — palette has 1 color or 0, or
`_brand-extraction.json._provenance.notes` flags the extraction
as failed / login-walled / iframe-dominated.
The classification feeds the Mode-detection precedence in Phase 2.
Surface the classification in the plan when it would change the
default mode.
## Procedure
### Phase 1 — Reasoning
Run the full intent-reasoning procedure from
`skills/stardust/reference/intent-reasoning.md`. Steps 1-6: restate
the phrase in dimensional vocabulary, identify movement, identify
gaps, ask **at most two** clarifying questions, map to an impeccable
command sequence, show the plan to the user.
Worked examples in
`skills/stardust/reference/intent-examples.md` calibrate the style.
Hard ceiling on questions: two per turn, no exceptions.
**Zero movement is not a direction — hand off to `replica`.** Before
restating, check whether the phrase pins every axis unchanged: "exact
replica", "same design", "pixel-perfect", "faithful", "keep the current
design", "1:1", "re-platform only", "preserve verbatim", or
`ia-fidelity: verbatim` with palette, type and density all pinned. That
is a same-design migration and `direct` has nothing to decide: write a
one-paragraph note to `stardust/direction.md` ("zero-movement phrase —
same-design migration; the direction is the mechanical promotion in
`replica` Phase 2"), stamp `state.json.flow: "replica"` if unset
(`../stardust/reference/state-machine.md` § Flow keys), and stop with
"run `$stardust replica <url>`". Never continue into a redesign
direction, a `--prep` module catalog or a plan on such a phrase — under
hands-off included: "ask nothing" below never means "proceed on a
replica phrase". (Recorded: `direct` invoked with "exact replica —
preserve verbatim" kept going; 2,207 pages were published at 24–28 %
pixel diff, four to five times the replica pass bar.)
**Hands-off mode** (per `skills/stardust/SKILL.md` § Hands-off mode,
`state.json.handsOff: true`): ask nothing and wait for nothing — after
the zero-movement check above, which hands-off does not skip.
Derive every answer the questions would have collected from the
captured evidence — density and ia-fidelity from their documented
defaults and trigger conditions, audience and register from the
captured surface — and record each as a named assumption in
`direction.md` § Movements (e.g. `density: balanced (hands-off
default — multi-audience floor fired)`). The plan is still written;
execution proceeds without the confirmation gate. Question budgets
and gates below that say "ask the user" resolve the same way: derive,
stamp the assumption, proceed.
#### Density tuning (one-shot, only when unmoved)
When the user's phrase does **not** move the `density` axis (per
`reference/intent-dimensions.md` § 4), and the resolved register is
`brand`, ask one short follow-up — count it within the two-question
ceiling:
> Density tuning — (a) airy (NYT-Opinion-tier breathing, ~96px
> section padding), (b) balanced (calm but compact, ~64–72px),
> (c) packed (data-dense, ~40–48px). Default for brand-register
> sites with multi-audience IA is **(b) balanced**; pick (a) only
> when the page is editorial-led with deep per-section density.
If the user answers, stamp the chosen tier in `direction.md` §
Movements as `density: <tier>`. If unanswered, default to
**balanced** (not airy) for brand register and stamp
`density: balanced (default)`.
Skip this question entirely when:
- The user's phrase already moved `density` (any of "make it
denser", "more breathing room", "compact", "tight", "spacious"
count as movement).
- The register is `product` (default `packed` per § 4).
- The register is `ambiguous` and resolving it earlier in the
reasoning is the higher-value question — defer density to the
next turn rather than burning a question slot.
Phase 4 reads the stamped tier to set `spacing.sectionPadding`;
it never re-asks.
#### IA-fidelity tuning (one-shot, only when unmoved)
When the user's phrase does **not** auto-pin `ia-fidelity` (per
`reference/intent-dimensions.md` § 9 — i.e. none of *"verbatim"*,
*"same IA"*, *"keep the structure"*, *"swap the surface"*,
*"don't rethink the IA"* and none of *"reimagine"*, *"rethink"*,
*"deeper redesign"*, *"what if"* appear), ask one short follow-up
— count it within the two-question ceiling:
> IA fidelity — (a) verbatim (same section sequence, same content
> beats; variants explore surface only: color, type, density,
> motion), or (b) reimagined (variants may demote / promote / drop
> sections, move IA priorities, take "what if" positions on the
> spine of the page).
> Default (b) for the typical refresh; pick (a) when the customer
> asked to keep their site structurally identical and only swap
> the surface.
If the user answers, stamp the chosen tier in `direction.md` §
Movements as `ia-fidelity: <tier>`. If unanswered, default to
**reimagined** and stamp `ia-fidelity: reimagined (default)`.
Skip this question entirely when:
- The user's phrase already auto-pinned the axis (any trigger phrase
in § 9 — *"same IA, swap the surface"* → verbatim;
*"what if we rethought the home page"* → reimagined).
- An existing `direction.md` is being refined (the active tier holds
unless the user explicitly re-pins).
Phase 4 stamps the tier into `iaPriorities[].mutability`;
downstream `prototype` reads it.
Pair this question with the density-tuning question when both are
unmoved — *"two things to pin before we resolve: (1) density …, (2)
IA fidelity …"* — to stay within the two-question ceiling. If
resolving register (brand vs product) is also outstanding, prioritise
register first; defer one of density / ia-fidelity to the next turn.
Wait for the user's confirmation (`"go"`, or a correction to the
plan) before moving on.
### Phase 2 — Resolve the divergence inputs
Once the plan is confirmed, resolve the divergence-toolkit inputs
from `skills/stardust/reference/divergence-toolkit.md`. Before
rolling the seed, run the mode-detection precedence below to decide
whether the seed needs rolling at all.
#### Mode-detection precedence (run first)
The default mode for `direct` is determined by whether an extracted
brand surface exists with usable signal — **not** by the user's
freeform phrase alone. Ambiguous refresh phrases ("make it modern",
"stunning new version", "design fatigue cure") are migration-shaped
asks, not rebrand triggers. The precedence is asymmetric on purpose:
the safer mode (Mode A — brand-faithful) catches ambiguous phrases;
the riskier rebrand mode requires the user to name it.
1. **Site migration / refresh — DEFAULT.** When the captured brand
signal stamped in § Setup step 6 is `signal-strong`, Mode A is
active by default. The user's phrase moves *expressive*,
*distinctiveness*, *tone*, and *density* axes inside Mode A — but
palette and type are pinned to the captured surface, and the
image-reuse contract (below) holds. **Signature preservation also
holds:** a captured signature hero medium (background video /
canvas / Lottie / scroll-motion, elevated as
`_brand-extraction.json#voice.heroMedium`) or a site-wide motif is
reproduced, not flattened — per `skills/stardust/reference/
intent-dimensions.md` § 8b, and exempt from the `surprise` budget.
Surface in the plan:
*"Brand-faithful mode active — palette and type pinned to the
captured brand surface. Pass `--rebrand` to override."*
2. **Rebrand — explicit opt-in.** Mode A is overridden when **any**
of the following triggers fire:
- The user's phrase contains an explicit rebrand signal: any of
`rebrand`, `new brand`, `clean slate`, `start over`,
`from scratch`, `replace the brand`, `not brand-faithful`,
`editorial reimagination`, `completely new`, `redo the brand`.
- The `--rebrand` flag is passed.
- Captured signal is `signal-absent` (no usable inheritance).
Surface this case as an automatic switch with reason; the user
can correct.
In rebrand mode, run the standard divergence-seed roll per
"Default mode (no constraints)" below. Surface in the plan:
*"Rebrand mode active — full divergence-seed roll. Mode A
bypassed because <reason>."*
3. **Brand-faithful + targeted exploration.** When the user requests
N variants (e.g. *"3 variants"*, *"4 directions"*) and Mode A is
active, the variant role contract in `reference/multi-variant.md`
applies (trigger: § Phase 2.6). Variant A is locked to **strict Mode A** (palette and
type pinned, IA preserved, every improvements-list item applied).
Variants B+ may amplify one **captured** trait (a motif, a photo
treatment, an IA priority the current site underplays) but
cannot:
- introduce a font outside the captured surface,
- introduce a color outside the captured palette,
- shift the register from PRODUCT.md.
4. **Signal-thin fallback.** When captured signal is `signal-thin`,
Mode A activates but warns: *"Captured brand surface is thin —
{reason}. Variants will inherit what is available; some
dimensions will need to be filled by the divergence toolkit."*
The user may either re-run extract with a wider crawl
(`--cap 25`) or proceed with reduced fidelity.
After mode-detection completes, run the existing mode definitions
below (Mode A procedure, Mode B anchor-reference precedence, Mode C
ground-family override) as applicable.
#### Mode A — Brand-faithful mode
Triggered automatically when the captured brand signal is
`signal-strong` and no rebrand-mode override fired (see
§ Mode-detection precedence above), OR when the user pinned **both**
type and palette (via explicit phrase: "keep typography and palette",
"preserve the existing brand", "brand-faithful redesign"; or via
constraints listing both as anchors).
In this mode, direct does **not** roll the type or palette
dimensions of the seed — they are already locked.
The mode procedure:
1. Record `font_deck.name = "brand-inherited"` and
`font_deck.picked_by = "user-constraint"`. Do not invoke
`reference/palette-picker.md`.
2. Record `palette.source = "inherited from _brand-extraction.json"`
and `palette.picked_by = "user-constraint"`. Apply role-renaming
per toolkit § 4 if the inherited names violate the brand-native
rule (this is still useful — role renaming is presentational,
not a divergence choice).
3. **Still roll** the seed for the **non-locked** dimensions
(decade, register, ground-family-as-applicable per Mode C
below). These dimensions still drive divergence — the visual
register and the era can shift even when type and palette are
pinned.
4. Auto-emit the `brand_faithful_inversions[]` block in
`extensions.divergence` per
`reference/direction-format.md` § Brand-faithful inversions.
The list is mostly mechanical (see § Brand-faithful inversions
in direction-format.md for the canonical patterns).
5. Surface in the user report which dimensions had teeth and
which were inert:
```
Divergence (brand-faithful mode):
decade ✓ rolled → 2025-now
craft ✓ rolled → Riso print
register ✓ rolled → Memoir-adjacent
ground-family inherited → stark-white (brand-native)
font deck inherited → existing site stack
palette inherited → existing 5-color set
```
6. **Image-reuse contract.** Captured images are reused via their
public URLs (or the local copies in
`stardust/current/assets/media/` written by extract Phase 2)
**at the same semantic position** as on the source site. Hero
stays hero. Story-tile portrait stays story-tile portrait.
Program-card image stays program-card image. Background-motif
image stays background motif.
This is part of brand-faithful inheritance: swapping a captured
portrait for a placeholder, or demoting the hero photo to a
thumbnail, erases the brand's most load-bearing trust signal.
The only legitimate ways to deviate from semantic
position-preservation under Mode A:
- The captured image is broken (404, blocked by `referrer-policy`,
CORS-walled, or recorded with `localPath: null` and a
`downloadError`).
- The brand-review surfaced the image as a tension (e.g.
`T-stock-photography` when added — flagging the captured
image as obviously templated stock that the brand team would
replace anyway).
- The improvements list (Phase 2.5) explicitly notes a crop or
positioning fix for that image — in which case the same
image is reused at the corrected crop or position.
Synthesised placeholders are forbidden under Mode A. When a
captured image cannot be reused, the prototype shape brief
declares the gap explicitly and the rendered prototype shows a
placeholder-with-signature element so reviewers see the gap
rather than a fabricated photo.
The user can correct the mode at the plan-confirmation gate (e.g.
"actually let me move the palette" or "actually rebrand it")
before it locks.
#### Mode A+ — Brand-adjacent refinement (bounded, evidence-gated)
The middle tier between Mode A's hard pins and `--rebrand`: when
the improvements list (Phase 2.5) names a captured type or color
weakness with evidence, bounded same-classification upgrades are
permitted — each audited in `extensions.divergence.
brand_adjacent_refinements[]`, never active by default. Read
`reference/mode-a-plus.md` before applying any refinement.
#### Mode B — Anchor-reference precedence
When the user provides anchor references (Q1/Q2 answers like
"Pentagram nonprofits, This American Life, NYT Opinion longform"),
those references **already imply** seed dimensions (Pentagram →
decade `2025-now` editorial; This American Life → register
`Memoir`-adjacent). Do not roll dimensions the references already
imply.
**Agent-sourced anchors (default when the user provides none).**
Mode B no longer waits for the user to name references: run the
reference-research procedure
(`skills/stardust/reference/reference-research.md`) to source 3–5
real-world anchors matched to the brand's category, register, and the
resolved direction movement. Researched anchors carry the same
implied-dimension weight as user-provided ones and are recorded as
`picked_by: "reasoned: <anchor>"` with the full citation in
`extensions.divergence.references_used[]`. User-provided references
always outrank researched ones on conflict. When research is
unavailable (ladder exhausted per reference-research.md § 1), Mode B
degrades to the deterministic roll for the un-implied dimensions.
Precedence rule:
1. If anchor references are present, extract their implied
dimensions:
- **Decade** from era of the references (Pentagram → 2025-now;
vintage Penguin → 1960s).
- **Craft** from medium of the references (TAL → audio editorial
≠ a craft per se, but Bandcamp → web-print hybrid; Riso-print
anthology → Riso).
- **Register** from cultural reference set (Memoir, Tabloid,
Catalogue, etc.).
- **Ground-family** from typical ground of those references
(NYT Opinion → cream/parchment; Pentagram nonprofit →
stark-white or monochrome-tint).
2. Mark each implied dimension as
`picked_by = "anchor-reference: <ref-name>"`.
3. Roll the seed only for **un-implied** dimensions.
4. Record the anchor → dimension mapping in
`extensions.divergence.seed.anchors[]`.
عرض على GitHub