Skip to content

Your First Product with BoB

The week above /requirement. In BoB in One Day you handed the loop one requirement. Real products do not start with a requirement. They start with an idea. This week you take one small product from an idea to a tagged release: a vision, two capabilities, four requirements, a groomed cluster, a flight plan, two days of loop runs (some in parallel), and a release with a retrospective. Every command below comes from the product week explanation, which also covers why each layer exists.

← Tutorials · docs home

hello-links, a link shortener on Cloudflare Workers. POST /api/links with a URL returns a short code, and opening /<code> redirects to the URL. By Friday it also has a bearer token protecting the API and a visit count for each link.

The product is deliberately small, so the loop can finish two requirements in a day at Level 3. It is also real enough that the vision has something to say: who it is for, and what it will never do.

By Friday evening you will have:

  • docs/vision.md, the product’s written reason for existing;
  • two capability issues, each closed as completed because every requirement under it closed;
  • four requirement issues, closed by the loop, each linked Part of its capability;
  • a flight plan issue with every item checked;
  • an integration branch merged to main in one step;
  • a v0.1.0 tag, a CHANGELOG.md and a GitHub Release;
  • a retrospective, plus one decision and one lesson issue.
  • Finish BoB in One Day first. This tutorial assumes you have run bob init, /requirement and /warp-drive once and have read a chunk report.
  • Node.js and npm, for the Workers scaffold and the release tooling.
  • A Cloudflare account is optional. The whole week runs against the local dev server (wrangler dev), and nothing is deployed.
  • tmux, for the parallel runs on Thursday. bob fork checks for it and names anything missing before it touches your repository.
  • About an hour of your time each day. Most of Wednesday and Thursday is the loop working while you do something else.

Issue numbers below assume a brand-new repository: the capabilities are #1 and #2, the requirements #3 to #6, and the flight plan #7. If yours differ, use the numbers your commands print.


Monday — the vision and the capabilities

Section titled “Monday — the vision and the capabilities”

Scaffold a Workers project, then let one command, bob ready --new, give it a GitHub repository and wire it to BoB: the steps you took one at a time in BoB in One Day.

Terminal window
bob doctor
cd ~/projects
npm create cloudflare@latest hello-links
cd hello-links
bob ready --new
git push -u origin HEAD

When npm create cloudflare asks, choose the Hello World example, Worker only, TypeScript, yes to git, and no to deploying.

What you should see.

  • bob doctor ends with a verdict line. Fix any drift it names before going on.
  • The scaffolder creates hello-links/ with wrangler.jsonc, src/index.ts and a first commit.
  • bob ready --new creates the private hello-links repository and links it (--new because the directory already has files), wires .claude/, detects the stack from the Workers config and lands the manifest, then puts the project on bob viz. It ends with READY, the bob viz URL and the next command. git push publishes the first commit.

What just happened. Provisioning read the code, not a questionnaire. The Workers config told it which registry items this project needs, so the Cloudflare tooling is already linked before you write a line.

Checkpoint. bob ready prints READY, and gh repo view shows the hello-links repository.

Open Claude Code in the project (claude -a3) and run:

/vision

/vision asks you questions: why the product exists, who uses it, where it is going, what principles it keeps, and what it will not do. Answer briefly and honestly. For hello-links, one owner shortening their own links, a good non-goal is “no user accounts, no public sign-up”.

What you should see. A new docs/vision.md with sections for the why, the users, the principles, the non-goals and a roadmap. The capabilities section is empty, because none exist yet.

What just happened. The vision is a living document in the repository, not an issue. It is never closed. Later commands read it: /capability traces each capability back to it, and /groom notices when the vision implies something the tracker does not have yet.

Checkpoint. docs/vision.md exists and names at least one non-goal. Commit it (git add docs/vision.md && git commit -m "docs: vision" && git push).

A capability is one user-visible ability. hello-links has two:

/capability Short links
/capability Manage links

Run them one at a time. For each one, /capability asks for user stories and success metrics, then offers to write the requirements straight away. Say not yet: you will write them tomorrow, once both capabilities exist.

What you should see.

  • Two issues, #1 Short links and #2 Manage links, each labelled cap, a priority (p2-high is fine) and an area: label derived from the title: area:short-links and area:manage-links.
  • Each body lists user stories, success metrics and an empty requirements checklist.

What just happened. The capability sits between the vision and the work. It is too big to build in one go and too specific to be a vision. Its area: label matters later: every requirement you file under it inherits the label, so a whole capability can be groomed, planned and run as one unit.

Checkpoint. gh issue list --label cap shows exactly two open issues, each with an area: label.

Terminal window
gh issue edit 1 --add-label approved
gh issue edit 2 --add-label approved
gh issue list --label cap

What you should see. gh issue list --label cap lists both capabilities, now also labelled approved.

What just happened. Approving a capability is a scope decision: this ability belongs in the product, so break it into requirements. It is not an instruction to build. The loop never picks up a capability, only approved requirements. That is why approving both on Monday is safe: nothing runs until you approve the work under them.

Checkpoint. Both capabilities are open and labelled cap and approved. docs/vision.md is committed.


Tuesday — requirements, a groom and a flight plan

Section titled “Tuesday — requirements, a groom and a flight plan”

In Claude Code, file one requirement per line, each with its parent and, where it applies, what it waits for:

/requirement Create a short link (POST /api/links). Part of #1.
/requirement Follow a short link (GET /:code, 302 or 404). Part of #1. Depends on #3.
/requirement Protect the API with a bearer token. Part of #2.
/requirement Count visits and show them (GET /api/links/:code). Part of #2. Depends on #4 and #5.

/requirement drafts the acceptance criteria from your one line and shows them to you. Tighten any criterion you could not test. For “Create a short link”, a good criterion is “a POST with an invalid URL returns 400 and stores nothing”. When it asks whether the requirement is approved, say yes.

What you should see.

  • Issues #3 to #6, each labelled req, a priority, approved, and the area: label inherited from its capability.
  • Each body ends with Part of #1 or Part of #2. #4 and #6 also carry their Depends on line.
  • The capabilities’ requirement checklists now list their children.

What just happened. The two links are what later steps read mechanically. Part of lets BoB derive a capability’s status from its children. Depends on becomes an ordering edge in tomorrow’s flight plan, so #3 and #5 can run at the same time while #4 waits for #3.

Checkpoint. gh issue list --label req --label approved lists four issues, and gh issue view 6 shows both Part of #2 and Depends on #4 and #5.

Four requirements written in one sitting always disagree in small ways. One says links, another says urls. One returns JSON errors, another plain text. Groom them together:

/groom area:short-links
/groom area:manage-links

What you should see. A change report for each area: the requirement bodies it reconciled, the dependencies it confirmed or added, and a readiness verdict for each requirement. Groom edits issues and comments on them. It never touches code.

What just happened. Grooming is the last human-speed step before the loop runs at machine speed. Anything ambiguous now becomes a question the loop has to stop and ask on Wednesday, so read the report and fix what it flags.

Checkpoint. Every requirement is reported ready. A requirement the report marks not ready names what is missing, usually a vague acceptance criterion. Fix the issue body and run the same /groom line again.

Terminal window
bob plan build --from approved --branch week/hello-links --name "hello-links week one"

What you should see. The command prints the new plan’s issue number (#7). Open it on GitHub: a checklist of #3 to #6 in run order, with depends_on edges on #4 and #6, and week/hello-links declared as the integration branch.

What just happened. The plan is the week’s order, written down once. On Wednesday the loop consumes the plan instead of rediscovering the queue at every step. Because the plan is an issue, you can reorder it or drop an item by editing it, and the loop follows the edit.

Checkpoint. gh issue list --label flight-plan lists one open plan, and its body names all four requirements.

Terminal window
bob plan status 7

What you should see. #3 and #5 are runnable (nothing blocks them), while #4 and #6 are waiting on their dependencies. The critical path is three waves: #3 and #5 first, then #4, then #6.

What just happened. Nothing ran. bob plan status only reads the plan and the issues it names. It is the question to ask at any point this week: what can run now, and what is it waiting for? The same view drives the loop: an item the status calls waiting is never started.

Checkpoint. bob plan status 7 shows four open items, two of them runnable, and names week/hello-links as the integration branch. If an item is missing, it was not labelled approved: approve it and run the bob plan build line again. The build is idempotent and refreshes the same plan.


Wednesday — the dev environment and the first wave, in parallel

Section titled “Wednesday — the dev environment and the first wave, in parallel”
Terminal window
bob dev up --verbose
bob dev health

What you should see.

  • bob dev up --verbose reports that it generated a dev.json, because the project has none yet. It then starts wrangler dev on a port from the project’s band, runs a health check, and ends with the local URL.
  • bob dev health repeats the health check alone and reports healthy.

What just happened. dev.json is now the declared dev environment: the server command, the port and, as soon as the loop adds a D1 table, the migrations and seed data. Commit it. From now on every loop run starts by running bob dev up itself and checks health between chunks, so a requirement is tested against the running app, not only in unit tests.

Checkpoint. Opening the URL bob dev up printed shows the Worker’s Hello World response, and dev.json is committed on main.

Tuesday’s plan said #3 (create a link) and #5 (protect the API) depend on nothing. Run them at the same time:

Terminal window
bob fork fork --from-flightplan 7 --dry-run
bob fork fork --from-flightplan 7

The --dry-run line comes first so you can check the wave before anything is created: it lists the sessions it would spawn, one branch per requirement. The second line spawns them.

What you should see.

  • The dry run names exactly two items, #3 and #5. #4 and #6 are missing because they are still waiting on a dependency.
  • The real run creates two git worktrees next to your checkout, one tmux session with a window per worktree, and a warp-drive session in each window, scoped with --issue to its own requirement. It prints the tmux session name and the line to attach to it.

What just happened. Each session is an ordinary warp-drive run (plan, chunks, tests, commits, chunk reports), but in its own worktree, so the two never edit the same checkout. Neither can drift into the other’s requirement, because each is scoped to one issue. Attach to the tmux session to watch both at once, or leave them and come back after lunch.

Checkpoint. bob fork status lists two worktrees, each with a live warp-drive phase.

When both windows report their requirement complete:

Terminal window
bob fork status
bob plan status 7
bob fork drop --all

What you should see.

  • bob fork status shows both sessions finished.
  • bob plan status 7 now shows #3 and #5 done and #4 runnable. #6 still waits for #4.
  • bob fork drop --all removes both worktrees and their tmux windows. It refuses a worktree with uncommitted changes, and it never deletes a pushed commit.

What just happened. Two requirements landed in roughly the time of one. The plan did not need to be told: a closed issue counts as a finished dependency, so the next wave became runnable on its own.

Checkpoint. gh issue view 3 and gh issue view 5 are closed, each with chunk reports linked, and bob plan status 7 lists #4 as runnable.


Thursday — the integration branch and finalize

Section titled “Thursday — the integration branch and finalize”

#4 and #6 depend on each other’s work, so they run one after the other, on the integration branch the plan declared. Start Claude Code at Level 3 and hand it the plan:

Terminal window
claude -a3
/warp-drive --flightplan 7

In a second terminal, watch it:

Terminal window
bob warp status --watch

What you should see.

  • The run’s first lines say it opened the stream week/hello-links for flight plan #7, and bob warp status shows flight-plan #7 → stream week/hello-links.
  • The loop runs bob dev up before the first chunk, then works #4, then #6, filing a chunk report per commit and ticking each plan item as its requirement closes.
  • When no plan item is left, the run ends by itself and files a session summary. It never picks up work outside the plan.

What just happened. A flight-plan run consumes the plan in order and nothing else. Because the plan declares an integration branch, each finished requirement was merged into week/hello-links instead of main. main still has Wednesday’s work and none of Thursday’s.

Checkpoint. bob plan status 7 shows all four items done, and git log --oneline main..week/hello-links lists Thursday’s commits.

Terminal window
bob warp finalize --dry-run
bob warp finalize

What you should see.

  • --dry-run prints the exact git commands finalize would run: bring the branch up to date with main, merge it, push. Nothing is changed.
  • The real run performs them at Level 3 and clears the stream. At Level 2 it opens one pull request for the whole branch instead, for you to review and merge.

What just happened. Thursday’s two requirements reached main together, in one reviewable step, so main never had visits recorded without anywhere to show them.

Checkpoint. git log --oneline origin/main includes Thursday’s commits, and bob warp session status reports no active stream.

Stop 14. Check the capabilities are complete

Section titled “Stop 14. Check the capabilities are complete”
/groom
Terminal window
gh issue view 1
gh issue view 2

What you should see. /groom reports that both capabilities have every child requirement closed, and closes each one with the completed label. gh issue view 1 and gh issue view 2 then show them closed, labelled completed.

What just happened. You never closed a capability yourself. Its status is derived from its requirements: in progress while some are open, complete when all are closed. A capability closed without completed would mean it was abandoned. The reconciler never produces that state, so the label is a trustworthy record of what shipped.

Checkpoint. Both capabilities are closed with completed, and the flight plan #7 has every item checked.


Friday — release, retrospective and journal

Section titled “Friday — release, retrospective and journal”
Terminal window
git checkout main && git pull
npm install --save-dev commit-and-tag-version
npm pkg set scripts.release=commit-and-tag-version
git commit -am "chore: add the release script" && git push
bob release --dry-run
bob release --channel stable

The first four lines add the release tooling once: commit-and-tag-version computes the version and writes the changelog, and the release script is how bob release finds it. Then look before you leap: --dry-run runs every safety gate and shows what the release would do without doing it.

What you should see.

  • bob release --dry-run passes its gates (on main, a clean tree, HEAD equal to origin/main) and previews the new version. With feat: commits since the scaffold, that is a minor bump to 0.1.0.
  • bob release --channel stable commits chore(release): 0.1.0 [skip ci] with a new CHANGELOG.md, tags v0.1.0, pushes both, and publishes a GitHub Release whose notes are the new changelog section.

What just happened. The version came from the commit messages the loop wrote all week. Conventional Commits are not a style preference in BoB: they are what makes the release mechanical. If the gates had refused (a dirty tree, or main behind origin), the release would have named the reason and changed nothing.

Checkpoint. gh release view v0.1.0 shows the release, and CHANGELOG.md on main lists the week’s features.

/retrospective

/retrospective walks you through the week: what went well, what did not, and what to change. Answer honestly. The first flight plan usually teaches you something about how you wrote dependencies.

What you should see. A Retrospective — <date> issue labelled session-summary, plus one retro-action issue per action item you agreed.

What just happened. Action items are issues, not bullet points in a document. Next week’s /retrospective reads the open retro-action issues first and asks what happened to each, so nothing agreed on Friday is silently forgotten.

Checkpoint. gh issue list --label retro-action lists your action items.

Stop 17. Record one decision and one lesson

Section titled “Stop 17. Record one decision and one lesson”
/journal decision bearer-token-not-accounts
/journal lesson plan-dependencies-before-forking
Terminal window
gh issue list --label decision
gh issue list --label lesson
gh issue list --label retro-action

Pick a real decision from the week. “Bearer token instead of user accounts” is the one the vision’s non-goal forced. Pick a real lesson too. “Declare dependencies before forking” is a common first one.

What you should see.

  • A decision: … issue labelled decision, with context, the decision, the alternatives considered and the consequences.
  • A lesson: … issue labelled lesson, ending with a Tooling Potential rating.
  • The three gh issue list lines show where each record lives: decisions and lessons are knowledge, and retro actions are follow-up work.

What just happened. Reports are execution records, so they say what happened. Decisions and lessons are knowledge records, so they say what to do next time. BoB keeps the two apart: a chunk report is never labelled lesson, which keeps --label lesson a list worth reading months from now.

Checkpoint. gh issue list --label decision and gh issue list --label lesson each show your new issue, and the week’s tracker has no open req left.


In one week you went from an idea to a released product, and every step left a record: the vision in the repository; the capabilities, requirements, plan, reports, decision, lesson and retro actions in the tracker; and the version in a tag. Next week starts where this one ended. Run /what-next to see what is approved, or add a third capability and plan it the same way.

Next tutorial: Where BoB Talks to You — Try each place BoB reaches you once — terminal, tmux, the desktop app, Telegram, claude.ai remote control and iBoB — then choose one by situation.