Agent Output Schemas
Every PACE agent produces a structured YAML artifact validated against a JSON Schema. These artifacts are stored in .pace/day-N/ and passed as inputs to downstream agents.
Story Card (PRIME)
File: .pace/day-N/story-card.yaml
day: 1agent: PRIMEtheme: "User model and password hashing"stories: - title: "Secure user creation" acceptance_criteria: - "User.create() stores bcrypt-hashed password" - "User.verify_password() returns True for correct password" out_of_scope: - "OAuth / social login"| Field | Type | Description |
|---|---|---|
day | integer | Day number |
agent | string | Always "PRIME" |
theme | string | Day theme from plan.yaml |
stories | list | One or more story objects |
stories[].title | string | Story title |
stories[].acceptance_criteria | list[string] | Testable conditions |
stories[].out_of_scope | list[string] | Explicitly deferred items |
Handoff Note (FORGE)
File: .pace/day-N/handoff.yaml
day: 1agent: FORGEcommit: "a3f9c12d8e4b..."approach: "Added User dataclass with bcrypt password hashing via passlib."risk: "bcrypt rounds set to 12 — acceptable for auth latency."dependencies: "passlib[bcrypt] added to requirements.txt"built: "src/models/user.py — User.create(), User.verify_password()"edge_cases_tested: - "Wrong password returns False" - "Empty password raises ValueError"known_gaps: []tdd_red_phase_confirmed: trueiterations_used: 18Fields written by FORGE (via complete_handoff tool):
| Field | Type | Description |
|---|---|---|
commit | string | Full git commit SHA of the implementation |
approach | string | Narrative of the implementation strategy |
risk | string | Known risks or trade-offs in this implementation |
dependencies | string | New packages or services introduced |
built | string | Files and public symbols created or modified |
edge_cases_tested | list[string] | Edge cases explicitly covered by tests |
known_gaps | list[string] | Acceptance criteria deferred or not fully met |
Fields injected by the framework (not generated by the LLM):
| Field | Type | Description |
|---|---|---|
day | integer | Day number |
agent | string | Always "FORGE" |
tdd_red_phase_confirmed | boolean | true when confirm_red_phase was called; false when tdd_enforcement is off |
iterations_used | integer | Number of LLM calls made before complete_handoff fired. Use this to tune forge.max_iterations. |
Gate Report (GATE)
File: .pace/day-N/gate-report.yaml
day: 1agent: GATEcriteria_results: - criterion: "User.create() stores bcrypt-hashed password" result: PASS evidence: "tests/test_user_model.py::test_create_hashes_password PASSED" - criterion: "CI pipeline green" result: PARTIAL evidence: "CI not yet configured — mapped to out_of_scope"blockers: []deferred: - "CI pipeline — not yet configured in this sprint"gate_decision: SHIPhold_reason: ""| Field | Type | Values | Description |
|---|---|---|---|
day | integer | — | Day number |
agent | string | "GATE" | — |
criteria_results | list | — | One entry per acceptance criterion |
criteria_results[].criterion | string | — | Exact criterion text |
criteria_results[].result | string | PASS, PARTIAL, FAIL | Verdict for this criterion |
criteria_results[].evidence | string | — | Test name, log line, CI URL, or code reference |
blockers | list[string] | — | Human-readable description of each FAIL |
deferred | list[string] | — | PARTIAL items mapped to out_of_scope |
gate_decision | string | SHIP, HOLD | Day decision |
hold_reason | string | — | Actionable instruction for FORGE when HOLD |
Sentinel Report (SENTINEL)
File: .pace/day-N/sentinel-report.yaml
day: 1agent: SENTINELfindings: - check: "Hardcoded secrets in source files" result: PASS evidence: "Secret pattern scan returned no results" - check: "HTTP timeout on external API calls" result: ADVISORY evidence: "src/clients/payment.py:42 — requests.get() with no timeout parameter"advisories: - "No timeout on requests.get() in payment.py:42 — add timeout=30"blockers: []sentinel_decision: ADVISORYhold_reason: ""| Field | Type | Values | Description |
|---|---|---|---|
day | integer | — | Day number |
agent | string | "SENTINEL" | — |
findings | list | — | One entry per security/SRE check |
findings[].check | string | — | What was checked |
findings[].result | string | PASS, ADVISORY, FAIL | Check verdict |
findings[].evidence | string | — | File path, line number, or test name |
advisories | list[string] | — | Non-blocking findings (one per ADVISORY result) |
blockers | list[string] | — | Exploitable vulnerabilities (one per FAIL result) |
sentinel_decision | string | SHIP, HOLD, ADVISORY | Day decision |
hold_reason | string | — | Actionable instruction for FORGE when HOLD |
Conduit Report (CONDUIT)
File: .pace/day-N/conduit-report.yaml
day: 1agent: CONDUITfindings: - check: "Action version pinning" result: ADVISORY evidence: ".github/workflows/ci.yml uses actions/checkout@master" - check: "Test gate in CI" result: PASS evidence: "ci.yml job 'test' runs pytest before any deploy step"advisories: - "actions/checkout@master in ci.yml — pin to @v4"blockers: []conduit_decision: ADVISORYhold_reason: ""| Field | Type | Values | Description |
|---|---|---|---|
day | integer | — | Day number |
agent | string | "CONDUIT" | — |
findings | list | — | One entry per DevOps check |
findings[].check | string | — | What was checked |
findings[].result | string | PASS, ADVISORY, FAIL | Check verdict |
findings[].evidence | string | — | Workflow file name, step name, Makefile target |
advisories | list[string] | — | Non-blocking findings |
blockers | list[string] | — | Broken CI or leaked secrets (FAIL) |
conduit_decision | string | SHIP, HOLD, ADVISORY | Day decision |
hold_reason | string | — | Actionable instruction for FORGE when HOLD |
Cycle Cost Record
File: .pace/day-N/cycle.md
Written by the orchestrator on SHIP (after all agents pass). Contains the total pipeline cost for the day.
day: 1cycle_cost_usd: 2.8431forge_cost_usd: 2.3105generated_at: "2026-03-13T05:47:11Z"| Field | Type | Description |
|---|---|---|
day | integer | Day number |
cycle_cost_usd | float | Total cost of the full PRIME → FORGE → GATE → SENTINEL → CONDUIT pipeline for this day |
forge_cost_usd | float | FORGE-only cost (subset of cycle_cost_usd) |
generated_at | string | ISO-8601 UTC timestamp when the cycle completed |
Run Attempts Log
File: .pace/day-N/attempts.yaml
Appended to after every pipeline run (SHIP or HOLD), including retries. Provides a complete cost history for each day, making retry costs visible in PROGRESS.md.
- run: 1 date: "2026-03-13T04:12:33Z" cost_usd: 3.4821 outcome: HOLD hold_reason: "GATE HOLD: CI timed out waiting for check-runs"- run: 2 date: "2026-03-13T05:47:11Z" cost_usd: 3.1054 outcome: SHIP| Field | Type | Description |
|---|---|---|
run | integer | Attempt number (1-based) |
date | string | ISO-8601 UTC timestamp for this attempt |
cost_usd | float | Full LLM spend for this run (all agents) |
outcome | string | SHIP or HOLD |
hold_reason | string | First 120 characters of the hold reason (only present on HOLD) |
PROGRESS.md shows $X.XX (Nx) in the Actual Cost column when N > 1, and the Cost Summary includes “Total actual (incl. retries)” and “Wasted on retries” rows.
Decision semantics
| Decision | Meaning | Day advances? |
|---|---|---|
SHIP | No failures or advisories | Yes |
ADVISORY | No failures, but concerns worth tracking | Yes (advisory stored) |
HOLD | At least one blocking failure | No (FORGE must fix) |
For GATE specifically, PARTIAL in criteria_results means a criterion was not fully met but maps to an out_of_scope item — GATE can still issue SHIP or ADVISORY if all non-deferred criteria pass.