The schemas every prompt must respect
Five contracts hold the workflow together: the file that bridges the workflow to the host project (app.md), the template that seeds it (app.template.md), the per-host workflow-params file (_code_workflow/config.json), the file that scopes a single job (JOB.md), and the chat shape every dispatched stage returns to the orchestrator (STAGE_HANDOFF).
APP_CONTRACT — what app.md must contain
app.md is the only project-specific file the workflow reads (D-21, D-36). Every prompt under _processes/** opens with the literal directive "Read app.md first." and stops if the file is missing or is the bootstrap placeholder. Post-D-36, app.md describes the host project only; workflow-internal parameters moved out to _code_workflow/config.json.
The 12 section concerns
| # | Concern | Must answer |
|---|---|---|
| 1 | Identity | Project name and short description. |
| 2 | Canonical context files | Pointers to the project's pre-existing top-level rules / doc-map files. |
| 3 | Tech stack | Backend, frontend, database, containers, key libraries. |
| 4 | Directory map | Where source code, docs, tests, fixtures, configuration live. |
| 5 | Coding patterns | The project's settled conventions (DI, naming, base classes, etc.). |
| 6 | Security rules | What every change must respect (input validation, credentials policy, etc.). |
| 7 | Common commands | Build, cache, migrate, deploy commands the agents must run. |
| 8 | Test framework | Framework name + how to invoke it. Used by the test stage. |
| 9 | Documentation conventions | Where docs live and the rules for updating them. Used by the document stage. |
| 10 | Domain glossary | Project-specific terms agents need to know. |
| 11 | Never-do list | Hard prohibitions for any agent acting on this project. |
| 12 | Agent reading rules | Host-routing rules: which host docs each kind of work / each stage must read before acting. Pointer-first. Added per D-39. |
A separate Sub-agent runtimes section was once a candidate concern in the pre-D-36 contract; it was removed entirely when workflow-internal runtime declarations moved to _code_workflow/config.json. The genuine 12th concern is Agent reading rules (D-39).
How it's enforced
- The app-init agent is the sole consumer of the 12-concern contract — it reads
_processes/00_app/APP_CONTRACT.md, draftsapp.mdfrom_processes/00_app/app.template.md, and validates that every concern is present before writing. - The orchestrator, extend, and promote agents reduce the check to two lines (D-36):
app.mdexists, and is not the bootstrap placeholder. If either check fails, the agent stops and reports — never tries to repairapp.mditself. Remediation: paste_processes/00_app/app-init.prompt.mdinto Claude Code (primary), or follow_docs/how-to-port.md(manual fallback). - Sub-agent runtime availability is validated separately by reading
_code_workflow/config.json → runtimes. - This is decision R-13 (with the D-36 reduction).
_code_workflow/ to a new project, rewrite app.md (and create config.json from config.example.json), and the entire workflow runs. No code change in _processes/.
Source: _processes/00_app/APP_CONTRACT.md (moved from _processes/_shared/schemas/ by D-36).
app.template.md — the starting point for app.md
A paste-as-starting-point template the init agent reads when drafting a host's app.md (D-36). Pre-D-36 the skeleton was embedded inside APP_CONTRACT.md → ## Skeleton; D-36 extracted it into its own file so init has a dedicated template artifact, mirroring _processes/_shared/templates/ for JOB, PROGRESS, PLAN, NOTES.
- Read by: init agent only — drafts
app.mdby filling out the template's host-fact slots. - Schema: the same 12 H2 host-fact section concerns as APP_CONTRACT.
- Never: contains the old
## Sub-agent runtimesheading (workflow param; lives inconfig.jsonnow).
Source: _processes/00_app/app.template.md (new file, D-36).
_code_workflow/config.json — workflow runtime params
A small per-host JSON file holding workflow-internal parameters that are not host facts — specifically, which sub-agent runtimes are available in the current developer's environment (D-36). The file is gitignored; the schema is documented by the checked-in _code_workflow/config.example.json.
Schema
{
"runtimes": {
"claude": true,
"codex": false
}
}
- Closed vocabulary for keys:
claudeandcodex. Every declared runtime must carry an explicit boolean — absence cannot silently mean "no". - Written by: the init agent, which empirically probes each runtime —
clauderecordstrueunconditionally;codexruns a trivialcodex execavailability probe and recordstrueonly if it returns successfully. - Read by: the orchestrator (§B step 7), its creation/bootstrap step (§6c), and extend when adding stages that require optional runtimes — each refuses to proceed when a required runtime is
false. - Re-probing: run
_processes/00_app/app-update.prompt.md(or copyconfig.example.jsonand edit by hand) when the runtime set changes.
app.md (D-36) — app.md describes the project. config.json describes the developer's machine. The split lets app.md remain a clean host-facts-only file, while runtime availability moves to a gitignored file with a checked-in example.
Source: _code_workflow/config.example.json; _processes/00_app/app-init.prompt.md and _docs/DECISIONS.md → D-36.
JOB_CONTRACT — what JOB.md must contain
Every job has exactly one JOB.md at the root of its folder. This is the scoping contract and mandate: it states what the job is, how it should run, and what success looks like.
Document layout
JOB.md is one markdown document with two top-level halves:
- A structured header (closed-set fields the agents parse).
- A free-text mandate body (prose; no required sub-sections).
Required header fields
# <slug> — <title>
**Workflow version:** 0.15
**Type:** <type>
**Preset:** <preset path or short name>
**Created:** <YYYY-MM-DD>
**Status:** <queue name — informational only>
**Base branch:** <base branch, default main>
**Target branch:** <feature/<slug>, or N/A>
## Git
- Create branch: yes|no
- Validate against main: yes|no
- Commit: yes|no
- Push: yes|no # standalone step between commit and PR (D-82)
- PR: yes|no
- PR target branch: branch-name|blank # merge-INTO target; blank ⇒ production (0.14, D-63)
## Stages
- [ ] clarify
- [ ] brainstorm
- [ ] plan
...
- [ ] review (disabled)
- [ ] validate
## Approval gates
- after_creation: yes|no
- after_clarify: yes|no
- after_brainstorm: yes|no
- before_plan: yes|no
- before_execution: yes|no
- before_commit: yes|no
- before_pr: yes|no
## Per-stage config
### KISS mode
- Enabled: yes # optional; job-level, feature-only; omitted when off (D-77)
### Brainstorm
- Mode: dual_consolidate|solo|none
- Agents: claude|codex|claude, codex
- Consolidator: claude|codex # dual_consolidate only; default claude (D-30)
### Plan
- Multi-phase: yes|no
### Test
- Unit: yes|no
### Validate
- Agent: claude|codex # runtime validate dispatches to; default claude (D-38)
### Document
- Internal: yes|no
### Loop-back
- Max iterations: 3 # optional; absent = default 3; per-job loop-back cap (D-59)
# counts accepted rounds of either route — full or light-fix (D-83)
## Expected artifacts
- <path or description>
## Git semantics (0.14, D-63) — Base branch = the branch the job branch is cut FROM (default main); the header's Target branch = the job branch itself; PR target branch = the branch the PR merges INTO (blank ⇒ production). Commit: yes / PR: yes are honoured by the shared git landing (_processes/_shared/git-landing.md): post-validate in the orchestrator's §I Completion for pipeline jobs, inline for action-layer jobs — one commit per landing, gated by before_commit / before_pr, remote-aware fallback off GitHub, and the workflow never merges a PR. Validity rules: PR: yes requires Commit: yes and Push: yes (both refused at creation/bootstrap). Push (D-82) is a standalone landing step between commit and PR: it pushes the job branch to origin on every remote host, whether or not a PR is requested — before D-82 the only push was a sub-step of the GitHub PR path, so jobs on other hosts were never pushed. An absent Push: line resolves by PR (PR: yes ⇒ yes), so pre-D-82 jobs land unchanged and no version bump was needed. Off GitHub the PR itself is surfaced as a credential-free PR-creation link from the host table (Azure DevOps pullrequestcreate, GitHub/GHE compare URL, generic instruction otherwise).
Closed vocabularies
| Field | Allowed values |
|---|---|
| Stages (pipeline) | clarify · brainstorm · plan · execute · test · document · review · validate (canonical order — review precedes validate since 0.12, D-59) |
| Layers / shapes (D-45) | layer: pipeline · action · operation; shape: pipeline · singlet · orchestrator · op-card (action is a layer, not a stage) |
| Approval gates | after_creation · after_clarify · after_brainstorm · before_plan · before_execution · before_commit · before_pr |
| Brainstorm mode | dual_consolidate · solo · none |
| Brainstorm consolidator | claude · codex — dual_consolidate only; default claude; independent of the two writer runtimes (D-30). |
| Validate agent | claude · codex — only when validate is enabled; default claude; dispatched to a Claude general-purpose sub-agent, or run via codex exec, respectively (D-38, D-56). |
| Action kind | security · find_issues · doc_drift · revalidate · custom · operation_record — only on action-layer / operation-record jobs (D-44, D-45; revalidate added in 0.13 per D-61 — the whole-app/scoped soundness sweep audit kind). |
| Type | feature · bug · brainstorm · doc_revalidate · app_plan (layer pipeline) · audit · quick_fix · doc_upkeep · doc_create · codereview_fix (layer action) · operation op-cards app-init · app-update · app-install · claude-agents-md-files · promote · extend · quick_fix_collab (+ reserved non-intake operation_record) (D-44–D-50; claude-agents-md-files D-66/D-67; app_plan D-76) |
Stage handoff Completion | done · partial · blocked · awaiting_user_input (D-29) |
workflow.yaml. Every consumer in v1 is an LLM; structured markdown headings are sufficient.
Source: _processes/_shared/schemas/JOB_CONTRACT.md; History: _processes/_shared/schemas/JOB_CONTRACT.history.md
STAGE_HANDOFF — the chat shape every dispatched stage returns
Since 0.11 (D-56, superseding D-40) the orchestrator is a pure conductor — it dispatches every enabled stage as a sub-agent and writes the shared job-root state itself. Each dispatched stage (clarify, plan, execute, test, document, validate, plus the brainstorm and review helpers) returns this structured handoff, which the orchestrator verifies against the artifacts on disk before recording it in PROGRESS.md. (D-56 restored this name from the D-40-era HELPER_HANDOFF.md and widened the Stage vocabulary back to all eight stages.)
Required fields
| Field | Type | Meaning |
|---|---|---|
Stage | clarify · brainstorm · plan · execute · test · document · review · validate | Which dispatched stage produced the handoff (D-56 widened this back to all eight stages). |
Completion | done | partial | blocked | awaiting_user_input | How the helper exits. awaiting_user_input is normal workflow (not a fault, not a user-visible stop): the helper returns a Questions for user block, and the orchestrator relays via AskUserQuestion then re-dispatches (D-29). |
Artifacts | List of paths (job-relative) | Files the stage produced or updated. The orchestrator verifies each exists on disk. |
Decisions to record | List of one-line strings | Each entry becomes one line under PROGRESS.md → Decisions. |
Blockers | List of one-line strings | Non-empty list = orchestrator stops the run. |
Handoff narrative | One sentence | Becomes one line under PROGRESS.md → Handoff notes. |
Optional / conditional fields
| Field | When used | Meaning |
|---|---|---|
Verdict | clarify, test, validate, review; consolidate when relevant | Mirrors the stage artifact's closed-vocabulary verdict. |
Next action hint | any stage | Optional sentence the orchestrator may write as the next action. |
Notes for downstream | any stage | Forward-looking notes the orchestrator commits to root note.md. |
Key findings | any stage | Durable sourced discoveries the orchestrator commits to root key-findings.md. |
Loop-back request | review BLOCKED_PENDING_REWORK or validate FAIL | Structured re-entry request consumed by the orchestrator's loop-back engine. |
Rework classification | review only, and only meaningful with BLOCKED_PENDING_REWORK (D-83) | Optional Candidate route (light-fix · full-loop) / Finding IDs (1–2 R<NNN> blockers) / Reason. A routing claim, never an authorization: the orchestrator validates it itself against seven conditions before choosing the light-fix route, and anything absent, malformed, over-broad or unverifiable falls back to the unchanged full loop-back. |
Questions for user | required when Completion: awaiting_user_input | Questions the orchestrator relays, then injects back into the same stage on re-dispatch. |
Proposed JOB.md Mandate-body rewrite | clarify only | Full proposed Mandate-body replacement; clarify stays read-only and the orchestrator applies it. |
Stage start time / Stage end time | any stage (0.15, D-70) | The stage's self-measured start / end as an ISO-8601 UTC Z instant. Optional report-only: the orchestrator prefers a well-formed field, else falls back to its own dispatch/verify boundary stamp — it owns the clock and writes the ## Timing rows (sole-writer invariant intact). |
Phase times | execute only (0.15, D-70) | A list of phase <N>: <start> → <end> per-phase spans refining the nested execute timing rows; each entry validated/falls back independently. |
Example handoff
Stage: brainstorm
Completion: done
Artifacts:
- 02_brainstorm/consolidated.md
Decisions to record:
- Adopted the unified main-runner approach over the two-prompt split
- Folded in 2 user-locked answers on the cache-eviction policy
Blockers: (none)
Handoff narrative: Consolidated the Claude + Codex brainstorms; one contested
decision relayed to the user and folded in before the write.
User-question relay (D-29)
When a dispatched helper needs a user decision before it can produce its final artifact, it returns Completion: awaiting_user_input with a Questions for user block (numbered id, one-paragraph prompt, optional options, optional recommendation). The orchestrator asks the user verbatim, captures the answers, and re-dispatches the same helper to the same runtime with a fenced user_answers block injected:
```user_answers
- id: Q1
prompt: <verbatim prompt from the prior handoff>
answer: <verbatim user response>
```
The .lock stays in place; the loop iterates (cumulative across rounds, no fixed cap) until the stage returns Completion: done. Dispatched stages never invoke their runtime's own question facility. The relay is not a user-visible stop (only approval gates are). Used by clarify on ambiguity, the brainstorm consolidate helper, and the Codex review/validate helper — every case routes back through the orchestrator's own AskUserQuestion (D-56).
Why single-writer
If both the orchestrator and dispatched helpers wrote PROGRESS.md, the file would collect duplicate lines, conflicting [x] marks, and stale Next action text — and resume would become fragile. Single ownership eliminates the entire class of bug.
Source: _processes/_shared/schemas/STAGE_HANDOFF.md
## Timing — honest wall-clock time tracking (0.15, D-70)
Since 0.15 (D-70) every job records honest wall-clock time tracking in PROGRESS.md. For the whole job and each timed sub-task — every pipeline stage, plus each execute phase nested under it — the workflow records a start and end instant (ISO-8601 UTC Z), a derived duration in the compact Xh Ym Zs form (zero units omitted, seconds always shown), and an overall Job: total. It surfaces two ways at once: each completed ## Stages line gains a compact (HH:MM:SSZ → HH:MM:SSZ, <dur>) parenthetical after the existing — YYYY-MM-DD, and a new roll-up ## Timing section (after ## Stages) lists every sub-task's full instants + duration plus the Job: row.
## Stages
- [x] clarify — 2026-06-23 (09:14:32Z → 09:18:05Z, 3m 33s)
...
## Timing
- Job: 2026-06-23T09:12:00Z → 2026-06-23T11:40:18Z (2h 28m 18s wall-clock)
- clarify: 2026-06-23T09:14:32Z → 2026-06-23T09:18:05Z (3m 33s)
- execute: 2026-06-23T09:40:00Z → 2026-06-23T10:55:00Z (1h 15m 00s)
- phase 1: 2026-06-23T09:40:00Z → 2026-06-23T10:02:00Z (22m 00s)
- phase 2: 2026-06-23T10:02:00Z → 2026-06-23T10:55:00Z (53m 00s)
- validate: 2026-06-23T11:30:00Z → 2026-06-23T11:40:18Z (10m 18s)
The Job: span is honest wall-clock — it includes any time the job sat paused at an approval gate, so it exceeds hands-on time by design. The orchestrator is the authoritative clock (date -u +'%Y-%m-%dT%H:%M:%SZ' at each dispatch/verify boundary) and the sole writer of the block; stages only report their times through the optional STAGE_HANDOFF time fields (Stage start time / Stage end time / Phase times), which the orchestrator prefers when well-formed and otherwise falls back to its own boundary stamp. On a re-run (question-relay re-dispatch, resume, loop-back re-open) the orchestrator preserves the first recorded start, overwrites only the end, and recomputes the duration. Action-layer jobs carry an orchestrator-written shape-scaled block (a Job: row, plus per-phase rows for audit and per-fix rows for quick_fix where cheap); operation-record jobs carry a Job-only row the authoring ops agent self-stamps within the D-54 carve-out.
- [x] clarify — 2026-06-23, no parenthetical) is valid with unknown times, and an absent ## Timing block is valid. Times are never back-filled onto already-4_done/ or pre-0.15 jobs; the migration is purely additive (bump the version line).
Source: _processes/_shared/schemas/JOB_CONTRACT.md (§ ## Timing); _docs/DECISIONS.md → D-70.