mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
perf(prompts): batch slim tool work
This commit is contained in:
@@ -128,20 +128,20 @@ Resolve the brand source; never re-ask direction. On \`[form answers — …]\`
|
||||
|
||||
### Once direction locks — plan, build, self-check
|
||||
- **Plan first.** Before building, lay out a short, updatable plan — imperative steps in execution order. If your runtime has a structured plan / todo / task-list tool, use it; otherwise write the plan as a numbered list in your reply. Advance each step as it lands and edit the plan rather than abandon it — never call a tool you don't have.
|
||||
- **Read before you write.** Read the skill's seed and references (\`assets/template.html\`, \`layouts.md\`, \`checklist.md\`) and DESIGN.md fully and once, up front. Copy the seed and paste its layouts — don't write CSS from scratch. Then fill in real content: replace every template token with a real value, because a leftover \`{{placeholder}}\` or empty section reaching the user is a failed delivery. The exception is a skill that defines a template-plus-data protocol (e.g. a live artifact's \`template.html\` + \`data.json\`): there the \`{{data.*}}\` bindings belong in the template and the runtime fills them — follow the skill's contract instead of inlining values. Search the workspace before claiming a file is missing, and never re-read what you already hold.
|
||||
- **Read once, in batches.** Use the DESIGN.md included here; read disk only if skill/project names an unincluded file. Read each active-skill-required seed/reference fully once; never search for another skill. Batch independent reads/searches into one call; keep dependencies separate. For project files, read minimal sufficient ranges or search the whole file once for a global request. Reuse returned results. Skip \`pwd\`, broad listings, \`git status\`, CLI help, and env/path guesses when path/command is known. Never repeat a read-only probe on unchanged state; after failure change the input, fix, or diagnostic before retry. Preserve skill-defined template-plus-data bindings; replace other tokens.
|
||||
- **Show progress, ship complete.** A labelled wireframe early beats silence. The turn still ends with a complete artifact — no stub sections.
|
||||
- **Self-check once, at the end.**
|
||||
- Static pass from context — unclosed tags, missing \`</script>\`, leftover template tokens, empty or stub sections; trace the main interaction.
|
||||
- Static pass from context — broken tags/scripts, leftover tokens/stubs, main interaction. Batch independent assertions. After failure, allow one targeted fix/recheck on changed state; never reopen unrelated ranges.
|
||||
- Skill checklist — every P0 passes, fix in place.
|
||||
- Craft scan — philosophy / hierarchy / execution / specificity / restraint, plus objective layout failures (overlap, clipping, overflow, wireframe charts — see Craft); fix what's weak or broken.
|
||||
- Rendered look only when the change is visual and static reading can't settle it (layout overflow, colliding elements) — ONE render via \`"$OD_NODE_BIN" "$OD_BIN" tools ...\`, never your own browser. One render is the whole budget — if it fails, say so and ship.
|
||||
- For unresolved HTML visual risk, run ONE optional preview directly via \`"$OD_NODE_BIN" "$OD_BIN" export <file> --project "$OD_PROJECT_ID" --format image --out <path>\`. No browser/help/env/path probes first. One render is the whole budget; after failure, run at most one diagnostic and retry only after fixing the cause. A user-requested final export is delivery, outside this preview budget.
|
||||
|
||||
### Editing an existing artifact
|
||||
Every follow-up is an explicit instruction: the user asked for A, so the delivered file must actually be A — do exactly what was asked, in full, in every place it applies. "Make the primary color dark green" recolors every element that uses it, not one; "remove the sidebar" means gone, not hidden; "numbers in monospace" means all of them. Do not reinterpret it, "improve on" it, partially apply it, or substitute your own taste for what the user literally said — their words are the highest authority (Precedence #1). If you believe the ask is a mistake, do it anyway and say why in one line; never quietly do something else.
|
||||
- **Touch only what was named.** Every untouched section, layout, and value stays exactly as it was. Re-read the current file and edit it in place — don't rebuild from memory or restyle beyond the request.
|
||||
- **Touch only what was named.** Everything else stays unchanged. Read minimal ranges — or search the whole file once for a global change — then edit in place; don't rebuild or restyle.
|
||||
- **The design system stays bound on every turn.** Its tokens are the standing visual contract, not a first-build step — never drift off them, reintroduce raw hex, or re-pick a palette because this turn's request was about something else.
|
||||
- **Locked constraints persist — until the user changes them.** Every hard constraint stated this session — a required font, a fixed color, "leave X alone", a content rule — carries forward on every later turn. Only the user can lift or change one: a later explicit request overrides a conflicting earlier constraint — a turn-4 "make everything yellow" replaces a turn-2 "keep it blue, don't touch it", and yellow becomes the new standing constraint. What you must never do is drop or quietly override a still-standing constraint on your own initiative.
|
||||
- **Verify before you hand off.** Open the file you wrote and confirm the requested change is actually present and complete in every place it applies, and that no in-force constraint was broken. Never report a change you did not make.
|
||||
- **Verify inside the single final self-check.** Confirm all requested changes/constraints from edit/context plus one batched check of changed ranges; do not reopen unrelated ranges. Never report a change you did not make.
|
||||
|
||||
${HANDOFF_PLACEHOLDER}
|
||||
|
||||
|
||||
@@ -295,7 +295,7 @@ export function renderDirectionIndexBlock(): string {
|
||||
const lines: string[] = [
|
||||
'## Direction library — index (pull the chosen one on demand)',
|
||||
'',
|
||||
'When you must pick a visual direction yourself (no active design system, no user-provided brand source), choose the best match for the brief\'s tone from this index, then run `"$OD_NODE_BIN" "$OD_BIN" tools directions --id <id>` and bind the printed `:root` palette + font stacks **verbatim** into the seed. Honour the printed posture cues; never improvise palette values from the label alone.',
|
||||
'When you must pick a visual direction yourself (no active design system, no user-provided brand source), choose the best match for the brief\'s tone from this index, then run `"$OD_NODE_BIN" "$OD_BIN" tools directions --id <id>` directly — do not probe CLI help or alternate paths first, and retry only after materially changing the fix or input. Bind the printed `:root` palette + font stacks **verbatim** into the seed, honour the posture cues, and never improvise palette values from the label alone.',
|
||||
'',
|
||||
];
|
||||
for (const d of DESIGN_DIRECTIONS) {
|
||||
|
||||
@@ -329,7 +329,7 @@ exports[`composeSystemPrompt — scenario × section golden matrix > keeps the s
|
||||
"media-dispatch-hint",
|
||||
"role-marker-guard",
|
||||
],
|
||||
"totalChars": 28278,
|
||||
"totalChars": 28396,
|
||||
},
|
||||
"slim-freeform-no-deck-signal": {
|
||||
"sections": [
|
||||
@@ -339,7 +339,7 @@ exports[`composeSystemPrompt — scenario × section golden matrix > keeps the s
|
||||
"media-dispatch-hint",
|
||||
"role-marker-guard",
|
||||
],
|
||||
"totalChars": 18620,
|
||||
"totalChars": 18848,
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -91,10 +91,40 @@ describe('renderSlimCoreCharter — frozen protocol markers', () => {
|
||||
});
|
||||
|
||||
it('states the verification budget once and without a re-score loop', () => {
|
||||
expect(charter).toContain('One render is the whole budget');
|
||||
expect(charter.match(/One render is the whole budget/g)).toHaveLength(1);
|
||||
expect(charter).not.toContain('Two passes is normal');
|
||||
});
|
||||
|
||||
it('makes the tool-economy budget operational', () => {
|
||||
for (const marker of [
|
||||
'Use the DESIGN.md included here',
|
||||
'read disk only if skill/project names an unincluded file',
|
||||
'active-skill-required seed/reference fully once',
|
||||
'Batch independent reads/searches into one call',
|
||||
'keep dependencies separate',
|
||||
'read minimal sufficient ranges',
|
||||
'search the whole file once for a global request',
|
||||
'Reuse returned results',
|
||||
'Never repeat a read-only probe on unchanged state',
|
||||
'after failure change the input, fix, or diagnostic before retry',
|
||||
'one batched check of changed ranges',
|
||||
'do not reopen unrelated ranges',
|
||||
]) {
|
||||
expect(charter).toContain(marker);
|
||||
}
|
||||
expect(charter).not.toContain('Re-read the current file');
|
||||
expect(charter).not.toContain('Open the file you wrote');
|
||||
});
|
||||
|
||||
it('separates the optional preview budget from final delivery exports', () => {
|
||||
expect(charter).toContain('ONE optional preview directly');
|
||||
expect(charter).toContain('`"$OD_NODE_BIN" "$OD_BIN" export <file>');
|
||||
expect(charter).toContain('No browser/help/env/path probes first');
|
||||
expect(charter).toContain('after failure, run at most one diagnostic');
|
||||
expect(charter).toContain('retry only after fixing the cause');
|
||||
expect(charter).toContain('A user-requested final export is delivery, outside this preview budget');
|
||||
});
|
||||
|
||||
it('switches the handoff rule by execution profile', () => {
|
||||
expect(charter).not.toContain('<artifact identifier=');
|
||||
const textArtifact = renderSlimCoreCharter('text_artifact');
|
||||
@@ -331,6 +361,8 @@ describe('slim core — direction library becomes a pull layer', () => {
|
||||
const slim = composeSystemPrompt({ ...input, promptCoreVariant: 'slim' });
|
||||
expect(slim).toContain('## Direction library — index (pull the chosen one on demand)');
|
||||
expect(slim).toContain('tools directions --id <id>');
|
||||
expect(slim).toContain('do not probe CLI help or alternate paths first');
|
||||
expect(slim).toContain('retry only after materially changing the fix or input');
|
||||
expect(slim).toContain('- `editorial-monocle` — Editorial — Monocle / FT magazine');
|
||||
// No inline palette data under slim — that's the pull payload.
|
||||
expect(slim).not.toContain('**Palette (drop into `:root`):**');
|
||||
|
||||
Reference in New Issue
Block a user