Write the Prompt as an Executable Specification
A strong prompt need not be long. It must separate goal, facts, boundaries, procedure, verification, and report. That structure shrinks the space of hidden guesses and makes the answer auditable. In the companion project the prompt is built from the contract deterministically - by the same code, not by feel.
export function buildVerifiedChangePrompt(contract: TaskContract, repository: RepositoryMap): string {
const relevantEntries = repository.entries
.filter((entry) => contract.contextPaths.some((path) => entry.path === path || entry.path.startsWith(`${path}/`)))
.map((entry) => `${entry.path} [${entry.kind}, ${entry.bytes} bytes]`);
return [
"# Goal",
contract.goal,
"",
"# Context",
relevantEntries.length > 0 ? bullets(relevantEntries) : bullets(contract.contextPaths),
"",
"# Allowed write scope",
bullets(contract.allowedWritePaths),
"",
"# Constraints",
bullets(contract.constraints),
"",
"# Procedure",
"1. Read the relevant implementation, tests, and repository instructions.",
"2. Explain the root cause and propose a file-level plan before editing.",
"3. Make the smallest coherent patch inside the allowed write scope.",
"4. Run the acceptance checks and inspect the final diff.",
"5. Stop and ask if credentials, destructive actions, network access, or wider scope are required.",
"",
"# Done when",
bullets(contract.acceptanceChecks),
"",
"# Final report",
"List changed files, commands with exit codes, observed evidence, and residual risks. Do not claim success without evidence."
].join("\n");
}Behind the build stand seven sections, each with one job: Goal - what must change for the user; Context - which files, errors, and tests are the sources; Allowed write scope - where the code may change; Constraints - compatibility and bans; Procedure - whether to research and show a plan first; Done when - commands and expected signals; Final report - diff, exit codes, evidence, and residual risk.
To assemble such a prompt piece by piece and see which section is missing, use the builder.
Assemble the contract prompt
# Goal Reproduce and fix the observable defect without bypassing the check. # Context Name the paths, symbols, symptom, and canonical example. # Allowed write scope Write only to the explicitly named file. # Constraints Don't add a dependency or change the public API without separate agreement. # Procedure Research first and show a file-level plan. Then make the minimal patch. # Done when Focused regression test, then the full check. # Final report Changed files, exact commands, exit codes, evidence, and residual risks.
Separately, on negative boundaries. "Don't change the public API, don't add a dependency, don't touch migrations" doesn't replace the goal, but it cuts off a few cheap shortcuts. A boundary should reflect real risk; a list of dozens of generic bans only dilutes attention.
A dangerous template. "Do what's best, run everything needed, and don't ask questions" simultaneously widens the scope, hides the rights, and forbids stopping. That's not autonomy but the absence of a contract.
The prompt sets the shape. Context fills it - not the whole repository, but exactly what changes the decision.