Visual decisions and default visualization

Paul's design, three pieces:

serve-question.mjs: the world decision presented as a themed page instead
of a text prompt. The script serves an impeccable-styled option board
(assigned direction leading with THE ROLL badge, dealt challengers as
alternates carrying their QUALITY BAR cards, re-roll and steer built in),
prints the URL, opens the browser, and blocks until the user chooses;
the answer lands on stdout as ANSWER JSON, so the shell call itself is
the wait and no harness machinery is needed. Local images are served by
the ephemeral server; nothing leaves the machine.

generate-image.mjs + context.mjs IMAGE_GEN_AVAILABLE: when an OpenAI key
is in the environment, context reports that image generation works even
without a harness-native tool (gpt-image-2, billed to the user's key,
stated before first use; Google skipped by decision). Harness-native
tools always win when present.

new-work.md: visualize-before-build is now the default whenever any
image generation exists, not a codex.md special case; the attended
presentation prefers the visual decision page and falls back to the
structured question tool. Evals keep the unattended path untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-07-21 16:43:21 -07:00
co-authored by Claude Fable 5
parent 4da6729075
commit 5612cdf45b
5 changed files with 348 additions and 2 deletions
+16
View File
@@ -1127,6 +1127,7 @@ async function cli() {
appendSurfaceBriefContext(parts, ctx);
parts.push(buildResolvedContextDirective(ctx, cliOptions, { targetExists }));
appendDetectorFallback(parts, ctx);
appendImageGenDirective(parts);
if (shouldWarnMissingTarget(ctx, targetProvided, targetExists)) {
parts.push(buildMissingTargetDirective());
}
@@ -1141,6 +1142,7 @@ async function cli() {
appendSurfaceBriefContext(parts, ctx);
parts.push(buildResolvedContextDirective(ctx, cliOptions, { targetExists }));
appendDetectorFallback(parts, ctx);
appendImageGenDirective(parts);
if (shouldWarnMissingTarget(ctx, targetProvided, targetExists)) {
parts.push(buildMissingTargetDirective());
}
@@ -1243,6 +1245,20 @@ function automaticHookMode(ctx) {
return 'none';
}
// Image generation availability: harness-native tools always win, but when the
// environment carries an OpenAI key the API fallback works everywhere. The
// flag only reports capability; generate-image.mjs states cost before use.
function appendImageGenDirective(parts) {
if (!process.env.OPENAI_API_KEY) return;
const scriptsPath = path.dirname(fileURLToPath(import.meta.url));
parts.push([
'IMAGE_GEN_AVAILABLE: An OpenAI key is present, so image generation works even without a harness-native image tool:',
`\`node ${scriptsPath}/generate-image.mjs --prompt "..." --out <file>\` (gpt-image-2, billed to the user's key; say so before the first render).`,
'Prefer the harness-native image tool when one exists. Visualizing a direction before building it measurably strengthens the result.',
].join(' '));
}
// reference/craft-floor.md carries the detector-blind reflexes on every build,
// so the only gap left here is the mechanical pass. A hook covers it, per-edit
// or Stop; a session without one has to run the detector by hand. The detector