Watch a real run
Two recorded runs of one system, one after the other. Part 1 (steps 1–9) goes from an empty folder to a new endpoint answering in dev on a local cluster. Part 2 (steps 10–15) adds a Postgres database and a Next.js web UI with one system spec shipped across three repos. Every step is one sentence in Claude Code: say what you want in your own words and Claude runs the matching slash command, or type the command yourself. Each step shows both. Open a step to jump the recording there and see what was typed, what Claude asked, what it did and the result. Each step links to the real artifacts in the public demo repos demo-taskboard-api, demo-taskboard-web and demo-taskboard-gitops, so you can check every claim.
- ≈ 85 minof work for both parts, every wait cut
- 8 + 10questions Claude asked before writing the two specs
- 3 reposAPI, web UI and gitops, changed by one system spec
- 1 resourcePostgres, declared once in system.yaml; tasks survive a restart
- 13real pull requests in the public demo repos
Part 1: from an empty folder to an endpoint in dev
One Python service, one spec, a local cluster.
1Create the system“Create a taskboard system with one Python service for a task API, in public repos”
/system:new taskboard.yaml --public3 minTyped in the recording
/system:new taskboard.yaml --publicYou type
A four-line manifest and one command in Claude Code.
system: demo-taskboard owner: ika100 visibility: public components: - {name: demo-taskboard-api, description: Task API, type: service, lang: python}Claude does
- Previews the run with
--dry-run, then runscplat system new. - Renders the gitops-app and the Python service from their templates, creates both GitHub repos and pushes them.
- Protects
mainon both, links the service to the gitops repo (.platform-app.yml), and opens one PR that adds the service tosystem.yaml.
Result
Two repos that already build, test, scan and publish an image, and a list of next steps (including the
GITOPS_TOKENsecret that lets dev followmain).Evidence
- Previews the run with
2Merge and start a local cluster“Merge the PR once its CI is green, then start a local cluster”
devbox run cluster-up2 minTyped in the recording
Merge PR #2 once its CI is green, then run cluster-upClaude does
- Waits for the PR's CI and merges it.
- Runs
devbox run cluster-upin the gitops repo: a k3d cluster with ArgoCD and the Gateway API, then the root Application. - Waits for the API repo's first
mainbuild to publish its image, then checks that Argo reports the app Synced and Healthy.
Result
/health,/readyand/docsanswer 200.Evidence
3Expose the API“Make the API reachable from my browser”
/component:set demo-taskboard-api --expose2 minTyped in the recording
yes, expose it and merge the PR once CI is greenClaude does
Runs
/component:set demo-taskboard-api --expose: one PR that adds the route and the expose flag tosystem.yaml. Merges it after CI; Argo syncs about 20 s later.Result
A URL on the local Gateway:
http://demo-taskboard-api.demo-taskboard-dev.localhost:8088. Only needed for this demo; a component declared withexposefrom the start skips it.Evidence
4Write the spec“I want to create and list tasks, each with a title and an optional due date, kept in memory”
/component:spec "tasks: create and list tasks …"4 minTyped in the recording
/component:spec "tasks: create and list tasks with a title and an optional due date, kept in memory"Claude does
The product-manager agent drafts
spec.mdwith acceptance criteria. It never guesses a decision that is yours: it asks, with a suggested answer for each question.Claude asks, you answer
- Resource path →
POST /tasksandGET /tasks - Maximum title length → 200 characters
- Surrounding whitespace → trimmed, a blank title is rejected
- Due date format → date only,
YYYY-MM-DD - Due dates in the past → accepted
- List order → oldest first
- Cap on tasks kept in memory → none
- Invalid requests →
422in the standard validation format
Result
11 acceptance criteria (
AC-001.1…AC-001.11), two of them smoke-tagged for the running service.Evidence
- Resource path →
5Approve the spec“Approve the spec”
/component:spec approve 001Typed in the recording
Approve spec 001 now? → ApproveClaude does
Marks the spec approved, opens the spec PR and merges it once CI is green. Approval is the one decision the build waits for.
Evidence
6Ship the spec“Build it and get it running in dev”
/component:ship 00117 minTyped in the recording
/component:ship 001Claude does
- architect:
design.mdand a plan of three tasks (schemas, in-memory store, endpoints), each covering named criteria. - tester: acceptance tests for all 11 criteria, committed first and confirmed failing.
- coders: tasks 1 and 2 in parallel worktrees, then task 3, until the tests pass.
- reviewer: checks every criterion against tests and code and writes
verification.md. - Quality, tests and security gates, then the PR, merged after one green CI round.
Result
11 of 11 criteria met, 96 % coverage, PR merged;
main's CI builds and publishes the image. The time includes PR andmainCI (about 4 minutes).Evidence
- architect:
7An escalation, as it happened“Accept the formatter's change to the tests, it is formatting only”
/component:ship 001Typed in the recording
/component:ship 001 accept the lint-fix change, it is formatting onlyWhy it stopped
The formatter rewrote the committed acceptance tests (
timezone.utc→UTC). The build may not decide on its own that a changed test is harmless, so it stopped and asked. Accepting it resumed the run.Since then
Fixed: the tester formats the tests before committing them, so this stop no longer happens.
Evidence
8Deploy to devNothing to type: the run goes on by itself
/component:ship 001 (continues)3 minTyped in the recording
/component:ship 001 (deploy)Claude does
- The service's CI asks the gitops repo to pin dev to the new image; a pin PR opens and merges after its checks.
- Waits until Argo runs the new image, then runs the dev smoke tests for the smoke-tagged criteria.
What went wrong
Result
Dev runs the new image, Argo Synced and Healthy.
Evidence
9Use it“Create a task with a due date in dev and list all tasks”
curl -X POST $U/tasks … ; curl $U/tasks< 1 minTyped in the recording
curl -X POST $U/tasks … ; curl $U/tasksResult
The new endpoint answers in dev: a task with a due date is created and listed next to one without.
$ curl -s -X POST $U/tasks -H 'content-type: application/json' \ -d '{"title": "Ship the demo", "due_date": "2026-11-10"}' {"id":"3d6f8784-…","title":"Ship the demo","due_date":"2026-11-10",…}Evidence
Part 2: a database and a web UI
One system spec across three repos: Postgres instead of memory, and a Next.js web UI.
10Add a web UI“Add a web UI to the taskboard: a Next.js website in a public repo, part of this system”
/component:new demo-taskboard-web --type website · /component:add7 minTyped in the recording
Add a web UI to the taskboard: a Next.js website in a public repo, part of this systemClaude does
- Picks
/component:newfrom the sentence: a public Next.js repo from theweb-nextjstemplate,mainprotected by its CI checks, linked to the gitops repo. - Picks
/component:addnext: one PR that adds the web UI tosystem.yaml, exposed on the local Gateway, withAPI_URL=http://demo-taskboard-api. - Merges that PR after its six checks pass.
Your one manual step
A fine-grained token for the new repo (
GITOPS_TOKEN, Contents read and write on the gitops repo), so dev follows itsmain. Claude prints the exact command; creating a token stays with you.Evidence
- Picks
11One spec for the whole system“Keep tasks in a Postgres database instead of memory, and let people see and create tasks in the web UI”
/system:spec "…" → /system:spec approve 0019 minTyped in the recording
Keep tasks in a Postgres database instead of memory, and let people see and create tasks in the web UIClaude does
In the gitops repo, the product-manager agent writes one system spec for all three repos. It asks before it decides anything that is yours, with a suggested answer each time.
Claude asks, you answer
- Replace the API's "a restart empties the list" criterion → yes
- Database unreachable → the API answers
503and reports not ready - One database per environment → yes
- The task list replaces the starter page → yes
- Texts, date format, no sign-in for now → as suggested
- Tasks kept in memory at the switch → dropped
- Backups → a separate spec, before the first prod release
- A cap on the list → none
Result
15 acceptance criteria across the API, the web UI and the gitops repo, published as a draft PR, approved and merged.
What went wrong
Publishing had to wait for GitHub's API limit (5,000 points an hour per account), used up by two local consoles polling every 30 s. Stopping them fixed it.
Evidence
12Plan it across the repos“Plan it across the repos”
/system:plan 0014 minTyped in the recording
Plan it across the reposClaude does
- The planner assigns every criterion to a repo and orders them: the gitops repo first (declare Postgres, give the API its
DATABASE_URL), then the API; the web UI in parallel. - Writes the contract between them: the API keeps its fields and answers
503with a fixed message when the database is down; the web UI calls it only from the server, with a 5 s timeout. - Checks the plan (every criterion covered, no cycles) and merges it, so every agent builds from the reviewed version.
Evidence
- The planner assigns every criterion to a repo and orders them: the gitops repo first (declare Postgres, give the API its
13Ship it to dev“Merge the plan PR once its CI is green, then ship it to dev”
/system:ship 001≈ 30 minTyped in the recording
Merge the plan PR once its CI is green, then ship it to devClaude does
- gitops:
/resource:add postgresanduses: [postgres]on the API, one PR, merged on green CI. - web and API, each through its own ship in parallel: a repo spec, a plan, failing acceptance tests first, code until they pass, review, PR, merge on green CI, pin to dev.
- The API replaces its in-memory store with Postgres (schema created under a lock), answers
503and not-ready while the database is down, and recovers by itself. - Finally
/instance:verify dev: the smoke tests of both components pass against dev.
What went wrong
- Both PRs waited for GitHub's API limit once more before they could open.
- The web repo's first token could not write to the gitops repo, so its pin to dev failed with 403; a new token fixed it.
- The local cluster predated the new Postgres operator: one
devbox run bootstrapby a person. The platform never applies to a cluster by itself. - Resuming the web ship after the question in the next step lost the record of its merged PR, so its deploy check refused. The platform filed that as #408 by itself; dev was verified directly instead.
Result
Dev runs both new builds against a healthy Postgres; API smoke 4 of 4, web smoke 1 of 1. The web build itself took 16 minutes from its spec to done.
Evidence
- gitops:
14A question only you can answer“Yes, remove the starter content and keep the header and footer. Then continue the ship.”
/system:ship 001 (resumes)Typed in the recording
Yes, remove the starter content and keep the header and footer. Then continue the ship.Why it stopped
The web repo's own spec had an open question: remove the template's starter content (hero, cards, "Get started") entirely and keep header and footer? The ship does not guess a decision that is yours, so it stopped and asked; the answer resumed it.
Evidence
15Use it, and restart it“I just added a task in the web UI. Restart the API in dev and show that the task is still there.”
browser · kubectl rollout restart · GET /tasks2 minTyped in the recording
I just added the task 'Ship part 2 of the demo' in the web UI. Restart the API in dev and show that the task is still there.In the browser
The task list replaces the starter page at
http://demo-taskboard-web.demo-taskboard-dev.localhost:8088; a task added with the form appears at once.
Claude does
Leaves the restart to you: the demo repo's rules keep agents away from
kubectl, so it prints the exact command. After the restart a new API pod returns the same task with the sameidandcreated_at.Result
Tasks survive a restart. In part 1 the same restart emptied the list.
Evidence
About the timing
Section titled “About the timing”Every time on this page is working time: the waiting is cut. Part 1 takes about 30 minutes of work (agents about 17, CI about 7), part 2 about 55 (the web UI’s build alone took 16). The recording shows both in 7 minutes.
The runs themselves waited on things outside the platform’s work: GitHub’s API limit (used up by two local consoles), a token that could not write, a one-time operator bootstrap, CI queues and answers that came late. Each is named in its step. The measured baselines keep the full measured times, waits included.
What was edited: waiting is cut, the folder-trust dialogs, a fumbled dialog and a mistyped first curl are removed, and the host name in the status bar is blanked. Nothing else is changed; the questions in steps 7 and 14 are part of the runs. Part 1 was recorded with asciinema on 2026-11-03 with sdlc-foundry 5.6.0, part 2 on 2026-11-04 with 5.7.0; in part 2, Claude Code typed the sentences on the user’s behalf in the same recorded terminal.