Example workflows
End-to-end tool sequences for building a story, building a run, importing an existing codebase and fixing drift.
These are the calls an agent makes on the hosted server, in order, with real parameter shapes. Ids are examples. Every tool except list_projects and create_project also takes project_id, shown once per workflow and then left out.
For every parameter, see Tools & resources.
Build one story
You say: "Build PB-42."
1. Find the project.
// list_projects
{}Pick the project by name. If you have several and didn't name one, the agent asks. It names the workspace it is reading from.
2. Start the story.
// start_story
{
"project_id": "8b6f2c1e-4d3a-4e8b-9a71-2c5d0e6f9b14",
"story_id": "PB-42"
}The response has the criteria with their ids, the plan, design references, version and warnings. Read the warnings first. They say whether another session is changing the same files, whether criteria have no test yet, and whether built stories share files with this plan.
If the call is refused because the project needs an approved plan, write one and stop until a person approves it:
// save_plan
{
"story_id": "PB-42",
"expected_version": 7,
"steps": [
{ "text": "Add the reset-token table and migration", "files": ["db/migrations/0042_reset_tokens.sql"] },
{ "text": "Send the reset email from the auth service", "files": ["src/auth/reset.ts"] },
{ "text": "Add the reset form and route", "files": ["src/app/reset/page.tsx"] }
],
"risk": "Changes how sessions are invalidated after a reset",
"questions": [{ "text": "Should reset links expire after one use?", "options": ["Yes", "No"] }]
}3. Build it, in the repository. Use the story key in the branch name: get_story returns a suggested_branch.
4. Save the tests as you write them, linked to the criteria they prove. criterion_ids must be full ids.
// save_tests
{
"story_id": "PB-42",
"tests": [
{
"title": "sends a reset email for a known address",
"criterion_ids": ["c3a9e7b2-1f04-4c8e-b6d5-9e2a71f0c4d8"],
"file": "src/auth/__tests__/reset.test.ts",
"full_name": "reset > known address > sends a reset email"
}
]
}5. Report each criterion. Short id prefixes work here.
// report_criteria
{
"story_id": "PB-42",
"results": [
{ "criterion_id": "c3a9e7b2", "status": "pass", "detail": "Email sent with a single-use link; test passes" },
{ "criterion_id": "5d10f8aa", "status": "fail", "detail": "Expired links still load the form" }
]
}If an id names no criterion or more than one, nothing is saved and the refusal lists the valid ids. Fix the id and send the whole report again.
6. Fix and re-report until every must criterion passes.
7. Complete it, with the pull request.
// complete_story
{
"story_id": "PB-42",
"summary": "Password reset by emailed single-use link. Tokens expire after use; sessions are invalidated on reset.",
"implemented_files": ["db/migrations/0042_reset_tokens.sql", "src/auth/reset.ts", "src/app/reset/page.tsx"],
"pr_url": "https://github.com/acme/app/pull/318"
}If a must criterion is still failing or unreported, the response lists it and nothing changes. Otherwise the story is done, its claim is released, and the PR is stamped with the IntentDocs footer, or the response gives you the footer line to add. The response ends with the next story in the release.
A person then reviews and approves the story in IntentDocs.
When a must criterion keeps failing
After a few real attempts, don't force it through. Raise a blocker and stop:
// raise_blocker
{
"story_id": "PB-42",
"summary": "Reset emails don't arrive in production",
"attempting": "Sending reset emails through the transactional mail provider",
"failing": "The provider rejects the sender domain in production; works in staging",
"decision_needed": "Verify the production sender domain, or switch reset emails to the existing support address?",
"criterion_id": "c3a9e7b2-1f04-4c8e-b6d5-9e2a71f0c4d8",
"attempts": 3
}Don't call complete_story afterwards. The story waits for the owner's decision.
Build a run
You say: "Build R-7."
1. Read the run to see what is in it and whether it is approved.
// get_run
{
"project_id": "8b6f2c1e-4d3a-4e8b-9a71-2c5d0e6f9b14",
"run": "R-7"
}If run.status is draft, stop: a person approves it on its run page.
2. Take the next story.
// next_in_run
{ "run": "R-7" }The response is what start_story returns, plus "run": { "key": "R-7", "position": 2, "of": 5 }. The run's approval covers the build gate for each story in it.
3. Build it, then save_tests, report_criteria and complete_story with the pr_url, as in Build one story.
4. Call next_in_run again. Repeat until the response has a state instead of a story:
{
"run": "R-7",
"state": "complete",
"message": "R-7 is complete — every story is built. Stop here; a person reviews them."
}Stop on any state: complete, paused, stopped, cancelled, full or waiting. If next_run is present, the next phase is waiting for a person to approve it. Don't start it yourself.
Several agents can work the same run at once. Each next_in_run hands a different story to each session, up to the run's limit.
Import an existing codebase
You say: "Set up IntentDocs for this repository."
1. Write a brownfield report. The agent reads the codebase and writes Markdown with schema_version: 1 in front-matter and these ## sections: Product summary, Tech stack, Architecture decisions, Existing features, Data model, Constraints & invariants. Each bullet under Existing features is one capability, such as "Users can reset their password via emailed link".
2. Seed the vision.
// set_vision
{
"project_id": "8b6f2c1e-4d3a-4e8b-9a71-2c5d0e6f9b14",
"report": "---\nschema_version: 1\n---\n\n## Product summary\n...\n\n## Existing features\n- Users can sign up with email\n- Users can reset their password via emailed link\n..."
}Only users can be derived from a codebase, from the Product summary. The response lists the other four under missing_constitution_keys. If the project already had an answer the report would change, the response has requires_confirmation: true and writes nothing until you call again with confirm: true.
3. Ask the person for the other four answers, then save them:
// set_vision
{
"answers": {
"problem": "Small clinics lose bookings because patients can't reschedule online.",
"switch": "A missed appointment that a reminder would have saved.",
"first": "Online rescheduling with SMS reminders.",
"proof": "Fewer no-shows in the first month."
}
}When status is complete, the vision gate is open.
4. Create the stories from the same report:
// create_stories
{ "report": "---\nschema_version: 1\n---\n\n## Product summary\n..." }Each Existing features bullet becomes a story under "Existing functionality (from brownfield report)". If the map already has stories, the response has requires_confirmation: true and a stories_preview. Show it to the person, then call again with "confirm": true.
5. Check the result with list_stories or get_status. Stories describing what is already built have no criteria yet. Add them with add_criteria before building on top of them.
Fix drift
The spec of a built story can change after it was built, or CI can start failing its tests.
1. Find drifted stories.
// get_status
{ "project_id": "8b6f2c1e-4d3a-4e8b-9a71-2c5d0e6f9b14" }Look for "spec changed since built" and "CI regressions". get_session_context lists the first under stories.spec_changed_since_built.
2. Read the story.
// get_story
{ "story_id": "PB-17" }spec_changed_since_built shows what moved. ci_regressed marks criteria failing in CI. tests_predate_code means the results are older than the latest code change.
3. If only the evidence is stale, re-run the tests against the current code and report again:
// report_criteria
{
"story_id": "PB-17",
"results": [{ "criterion_id": "9e41b0c2", "status": "pass", "detail": "Re-run on the current main: passes" }]
}4. If the spec moved, ask for a proposal. Nothing is written.
// propose_drift_fix
{ "story_id": "PB-17" }The verdict is update_spec (the spec changes lock in what was built) or rework (the code needs to change). Show it to the person. They decide in IntentDocs.
5. If they send it back, the story becomes needs_rework, and get_story shows their review_notes. Build it again like any story: start_story, fix, save_tests, report_criteria, complete_story.
6. If the criteria themselves are wrong, correct them before reporting. update_criterion changes one and keeps its results. To replace the whole set, preview first:
// preview_criteria_replacement
{
"story_id": "PB-17",
"criteria": [
{ "text": "Given a booked slot, when the patient reschedules, then the old slot is freed", "priority": "must" },
"Rescheduling sends a confirmation SMS"
]
}If the preview has an evidence_warning, reported results would be lost. Confirm with the person, then call replace_criteria with the same criteria and the story's expected_version.