Skip to content

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
  1. Part 1: from an empty folder to an endpoint in dev

    One Python service, one spec, a local cluster.

  2. 1Create the system“Create a taskboard system with one Python service for a task API, in public repos”/system:new taskboard.yaml --public3 min

    Typed in the recording

    /system:new taskboard.yaml --public

    You 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 runs cplat system new.
    • Renders the gitops-app and the Python service from their templates, creates both GitHub repos and pushes them.
    • Protects main on both, links the service to the gitops repo (.platform-app.yml), and opens one PR that adds the service to system.yaml.

    Result

    Two repos that already build, test, scan and publish an image, and a list of next steps (including the GITOPS_TOKEN secret that lets dev follow main).

    Evidence

  3. 2Merge and start a local cluster“Merge the PR once its CI is green, then start a local cluster”devbox run cluster-up2 min

    Typed in the recording

    Merge PR #2 once its CI is green, then run cluster-up

    Claude does

    • Waits for the PR's CI and merges it.
    • Runs devbox run cluster-up in the gitops repo: a k3d cluster with ArgoCD and the Gateway API, then the root Application.
    • Waits for the API repo's first main build to publish its image, then checks that Argo reports the app Synced and Healthy.

    Result

    /health, /ready and /docs answer 200.

    Evidence

  4. 3Expose the API“Make the API reachable from my browser”/component:set demo-taskboard-api --expose2 min

    Typed in the recording

    yes, expose it and merge the PR once CI is green

    Claude does

    Runs /component:set demo-taskboard-api --expose: one PR that adds the route and the expose flag to system.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 with expose from the start skips it.

    Evidence

  5. 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 min

    Typed 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.md with 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 /tasks and GET /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 → 422 in the standard validation format

    Result

    11 acceptance criteria (AC-001.1 … AC-001.11), two of them smoke-tagged for the running service.

    Evidence

  6. 5Approve the spec“Approve the spec”/component:spec approve 001

    Typed in the recording

    Approve spec 001 now? → Approve

    Claude 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

  7. 6Ship the spec“Build it and get it running in dev”/component:ship 00117 min

    Typed in the recording

    /component:ship 001

    Claude does

    • architect: design.md and 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 and main CI (about 4 minutes).

    Evidence

  8. 7An escalation, as it happened“Accept the formatter's change to the tests, it is formatting only”/component:ship 001

    Typed in the recording

    /component:ship 001 accept the lint-fix change, it is formatting only

    Why 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

  9. 8Deploy to devNothing to type: the run goes on by itself/component:ship 001 (continues)3 min

    Typed 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

    • The pin PR waited for a manual approval of its checks, a GitHub rule for bot-opened PRs on public repos (#368, fixed).
    • The dev smoke was skipped with "could not read the gitops-app" (#369, fixed: retried and the error is named).

    Result

    Dev runs the new image, Argo Synced and Healthy.

    Evidence

  10. 9Use it“Create a task with a due date in dev and list all tasks”curl -X POST $U/tasks … ; curl $U/tasks< 1 min

    Typed in the recording

    curl -X POST $U/tasks … ; curl $U/tasks

    Result

    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

  11. Part 2: a database and a web UI

    One system spec across three repos: Postgres instead of memory, and a Next.js web UI.

  12. 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 min

    Typed in the recording

    Add a web UI to the taskboard: a Next.js website in a public repo, part of this system

    Claude does

    • Picks /component:new from the sentence: a public Next.js repo from the web-nextjs template, main protected by its CI checks, linked to the gitops repo.
    • Picks /component:add next: one PR that adds the web UI to system.yaml, exposed on the local Gateway, with API_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 its main. Claude prints the exact command; creating a token stays with you.

    Evidence

  13. 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 min

    Typed in the recording

    Keep tasks in a Postgres database instead of memory, and let people see and create tasks in the web UI

    Claude 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 503 and 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

  14. 12Plan it across the repos“Plan it across the repos”/system:plan 0014 min

    Typed in the recording

    Plan it across the repos

    Claude 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 503 with 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

  15. 13Ship it to dev“Merge the plan PR once its CI is green, then ship it to dev”/system:ship 001≈ 30 min

    Typed in the recording

    Merge the plan PR once its CI is green, then ship it to dev

    Claude does

    • gitops: /resource:add postgres and uses: [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 503 and 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 bootstrap by 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

  16. 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

  17. 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 min

    Typed 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.The web UI in dev: the heading Tasks, two tasks (one from the smoke test, and Ship part 2 of the demo due 2026-11-10), and the form with Title, Due date and Add task.

    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 same id and created_at.

    Result

    Tasks survive a restart. In part 1 the same restart emptied the list.

    Evidence

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.