Planning files
scope.md, its Phases table, tickets, PRDs, and the handoff: the planning files Carol reads.
Carol v0.1.22
A Zurdo PRD covers one run's worth of work. Anything bigger is an initiative: one destination, split into phases that each deliver one PRD. Carol reads an initiative from a directory of plain Markdown files.
Layout
docs/
└── billing/ # the initiative; its name is the directory name
├── scope.md # destination, decisions, and the Phases table
├── tickets/
│ ├── tax-rules.md # a research question
│ └── refund-policy.md # a grilling question for a human
├── design/
│ └── refunds.md # a design record; a phase's Design cell points into it
├── contracts/
│ └── refund-api.md # a promise one phase makes another (optional)
├── prds/
│ ├── prd-01-invoices.md # a Zurdo PRD, one per phase
│ └── prd-02-refunds.md
└── handoff.md # where the last session stopped (optional)
These files are the source of truth, and your tracker is only a projection of them. Carol never edits them from tracker state. The engine commands are the one exception: carol specify fills a row's PRD cell and sets it to running, in a pull request you review.
Initiatives live under docs/ by default. Set [paths] initiatives to use another directory. Carol finds an initiative by looking for <dir>/<name>/scope.md.
A PRD under docs/<initiative>/prds/ belongs to that initiative: carol publish links its epic to the scope issue, and carol board uses the initiative's board. A PRD stored anywhere else still works, but you pass --scope and --project yourself.
scope.md
# Scope: Billing
## Destination
Customers get itemised invoices and self-serve refunds. Done when …
## Notes
- Payments go through the existing Stripe account.
## Decisions so far
- Invoices are generated on the server, never in the browser.
## Phases
| Phase | Title | PRD | Status | Depends on | Design |
|-------|-------|-----|--------|------------|--------|
| phase-01 | Invoices | docs/billing/prds/prd-01-invoices.md | done | | |
| phase-02 | Refunds | docs/billing/prds/prd-02-refunds.md | running | phase-01 | design/refunds.md#Self-serve refunds |
| phase-03 | Dunning | | researching | phase-01, contract:refund-api | |
## Not yet specified
- Whether refunds over $500 need a second approver.
## Out of scope
- Multi-currency.
| Part | Rule |
|---|---|
# Scope: <title> | Required. The title names the scope issue and the initiative's board. |
## Destination | Its first sentence is the one-line summary carol status prints. |
## Notes, ## Decisions so far, ## Not yet specified, ## Out of scope | Copied into the scope issue. Any other ## section stays local. |
## Phases | One row per phase. A row is any table line whose first cell starts with phase-. |
The Phases table
| Column | Holds |
|---|---|
| Phase | The id, phase-NN. Other columns and files refer to it. |
| Title | The phase's name, as the scope issue shows it. |
| PRD | The PRD's path, empty until it's written. |
| Status | planned, researching, ready, running or done. Anything else is a parse error (exit 2). |
| Depends on | Optional. Phase ids this phase waits on, separated by commas or spaces, and contract:<name> entries. |
| Design | Optional. design/<topic>.md#<heading>: the design-record section the phase is specified from. |
The status is your judgment of where the phase stands. Carol never sets it from tracker state, but carol status flags a row conflict: a phase still researching after its blocking tickets are resolved, or a ready phase an open ticket still blocks.
Depends on must name phases in the same table. An unknown id is a parse error, in every command. carol propose blocks a phase's proposal by the phases it depends on. A contract:<name> entry names a file under contracts/ whose consumer is this phase. Once both sides agree to it, the contract stands in for the provider phase. See Contracts.
Design is what carol specify drafts the PRD from. Under carol watch, an accepted row without one gets a design session that fills it in a pull request (see The engine loop). The file must be under design/ and end in .md, and the heading after # must match a heading in it exactly. A malformed cell is an error. Neither optional column is rendered into the scope issue, and both appear per phase in carol status --format json.
Tickets
A ticket is a question that must be answered before a phase can be specified. There are two kinds. A research ticket can be answered by reading code or docs, by you or by an agent. A grilling ticket needs a decision from a human.
---
type: research
question: Which tax rules apply to EU invoices issued from the US entity?
status: open
blocks: [phase-03]
blocked-by: []
---
## Question
What we need to know, and what an answer must include.
## Findings
Filled in when the ticket is resolved.
| Key | Values |
|---|---|
type | research or grilling |
question | One line. It becomes the issue title. |
status | open or resolved |
blocks | Phase ids this ticket blocks |
blocked-by | Names (file names without .md) of tickets that must be resolved first |
The ticket's name is its file name. The ## Findings section is published only after the ticket is resolved. The next carol ticket or carol scope then posts the findings as a comment and closes the issue, once.
Under carol watch, an acceptor's carol:accepted on an open research ticket's issue starts an agent session that writes the findings and opens them as a pull request. An open grilling ticket gets its question posted on its issue, once, and waits for your answer. See Tickets in the loop.
PRDs
An initiative's PRDs are ordinary Zurdo PRDs. Write them with the same grammar and the zurdo-prd-author skill, and check them with zurdo validate before publishing. Carol parses the PRD itself to build the epic and task issues. It uses the task id, title, description, acceptance criteria and hints, and the Effort, Depends-on, Skills, Max-Attempts, and Agent-timeout metadata. A PRD that Carol can't parse is a usage error (exit 2) before anything is planned, so a malformed PRD can never be half-published.
A PRD that carol specify drafted with zurdo scaffold carries Zurdo's unreviewed-scaffold marker. zurdo validate --strict fails on it until you review the draft with zurdo-prd-author. See The engine loop.
The handoff
handoff.md is the one file a session leaves behind when it stops before the initiative is finished. It records where things stand and names one next action. It's a hint about the state of the work, not a store for anything durable: decisions belong in scope.md, and run outcomes belong in zurdo's run state.
---
initiative: billing
stopped_at: 2026-10-05T18:40:00Z
station: run-and-sync
phase: phase-02
by: agent
---
# Handoff: Billing
## Stopped at
## Done this session
## In flight
## Waiting on a human
## Next action
## Uncommitted
## Watch out
All seven sections are required, in this order. A section with nothing to say holds None., and ## Next action holds exactly one action.
The station is the kind of work due next. It doesn't measure progress.
| Station | The next work is… |
|---|---|
scope | Shaping or revising scope.md |
research | Answering open tickets |
phase-prd | Writing the PRD for a ready phase |
publish | carol publish and carol board |
run-and-sync | zurdo run, then carol sync |
phase-review | zurdo report, zurdo review, and deciding what's next |
carol handoff check validates the file's structure, and carol status tells you whether the work has moved on since it was written.
Next: Sync to your tracker