Watchfire eats its own dogfood: how this website is built by the thing it documents
On this page
You can see the live counts at /built-with-watchfire.
Open a terminal in the root of this website's repository and run a single command:
ls .watchfire/tasks/
0001.yaml 0017.yaml 0033.yaml 0049.yaml […] 0128.yaml
0002.yaml 0018.yaml 0034.yaml 0050.yaml […] 0129.yaml
0003.yaml 0019.yaml 0035.yaml 0051.yaml […] 0130.yaml
There are one hundred and thirty YAML files in that directory, and every page you have ever read on watchfire.io was produced by one of them. The hero on the landing page, the comparison matrix in the docs, the Mermaid diagram halfway down the Wildfire post, the "Edit on GitHub" link in the footer of every blog page, the /about page, the favicons, the very index you came in through — each of those lives in this repo because a Watchfire task spawned an agent in an isolated worktree, the agent shipped a diff, and the daemon merged it. The website is the output of the loop the website documents.
This post is the proof. It is also a hub: every other architecture-focused post in this series — Wildfire, worktrees, the sandbox, Beacon, secrets, Insights, Bring Your Own Agent, and Anatomy of a great task — argues that Watchfire's design works. A reader could fairly ask whether we actually use the thing ourselves. The answer is yes, and the receipts are sitting on disk in this very repository. One hundred and thirty task files. One hundred and twenty-nine of them are status: done, success: true at the time of writing. The one that is not is the one producing this paragraph.
The first task and the last task
The earliest file in the directory is 0001.yaml. Its title reads "Scaffold Next.js project with Tailwind CSS and base layout." Open it and the first surprise is what it asks for: an app/layout.tsx with a purple accent color (#a855f7), an Inter body font, a bg-zinc-950 baseline. The website you are reading does not have any of those things. The brand colour is fire-orange. The body font is Outfit. The first eight tasks shipped a purple developer-tools website that no longer exists, and task 0009 — titled "Rebrand website from purple to fire orange color palette" — is the merge commit where that website became this one. Task 0010 did the same job for the docs.
The most recent task before this one is 0129.yaml. It produced Anatomy of a great task. The task before that, 0128, produced the /about page. The one before that produced the per-backend landing pages. The one before that produced the comparison matrix. Tracing the directory in order is tracing the history of the site the way a designer traces a layered Figma file: each task is one layer, and the merge order is the layer order.
The interesting thing about the arc from 0001 to 0129 is not that it covers a year of work. It is that the cost of taking a small improvement from idea to merged change is, in practice, one task file. Most of the entries in that directory took less than ninety minutes of wall-clock agent time. The unit of progress on this website is a fifty-line YAML document, written by a human, executed by an agent, reviewed against acceptance criteria the human wrote in advance. The whole project is a directory listing.
One task, end to end
Take task 0118 as an example, because it is small enough to walk through in full and large enough to have shipped real value.
task_number: 118
title: Add an "Edit on GitHub" link to blog post pages
prompt: |
Docs pages already have an "Edit on GitHub" link
via `components/EditOnGithub.tsx`, rendered at
the bottom of every page under
`app/docs/[[...slug]]/page.tsx`. […]
Blog posts at `/blog/[slug]` have no equivalent
link. The MDX files live under `content/blog/`
and are just as fixable, but a casual reader has
no obvious path from "I found a typo" to a GitHub
edit URL. This task closes that gap.
# […]
acceptance_criteria: |
- Every published blog post page at
`/blog/[slug]` shows an "Edit on GitHub" link
in its footer, visually identical to the docs
version (same component, same icon, same
styling).
- The link is rendered by reusing
`components/EditOnGithub.tsx` — no duplicate
component is created.
- Blog index page `/blog` and tag archive pages
`/blog/tags/[tag]` do **not** show the link.
- `npm run build` and `npm run lint` both succeed.
status: done
success: true
agent_sessions: 1
That YAML file is the entire brief. A human spent maybe ten minutes writing it. The agent then spawned in its own worktree at .watchfire/worktrees/0118/, on the dedicated branch watchfire/0118. It read components/EditOnGithub.tsx, decided the existing component was already general enough, imported it into app/blog/[slug]/page.tsx, wired up the source-file path, ran npm run build and npm run lint, and set status: done. The daemon noticed, merged the branch back into main, and tore the worktree down.
You can audit every step of that without leaving the repo. git log app/blog/[slug]/page.tsx shows commit b00d9ad — "Add Edit on GitHub link to blog post pages", followed by 319b4a0 — "Merge watchfire/0118". The pencil icon you see at the bottom of this very page exists because that one task file did. The link you would click to fix a typo in this paragraph points back at the MDX file the task produced the wiring for. The fingerprints are everywhere.
What dogfooding revealed
Three things, each of them obvious only in hindsight.
The task file is the spec
We did not set out to write specs. We set out to queue up work. But once the prompt and the acceptance criteria are detailed enough for the agent to do the job without supervision, they are detailed enough that they are the specification. The .watchfire/tasks/ directory turned out to be a design-history archive nobody had to maintain — every change to the site, ordered, motivated, scoped, and verifiable against the diff it produced.
This collapse — task as spec — is what Anatomy of a great task is really arguing for. A task that the agent can finish in one session is, by construction, a task that explains its own intent. Once you write enough of them you stop opening a separate spec document, because the task already has the file paths, the acceptance commands, the negative constraints, and the cross-links. The natural artifact of running an agent is the spec. The natural shape of running this loop turned the design history into a directory listing you can grep.
The worktree is the review surface
When task 0118 finished, what it produced was not a thousand-line refactor. It was four lines of import, six lines of JSX, one new prop on an existing component. The merge commit at 319b4a0 is reviewable in under a minute. Multiply that by a hundred and thirty and the cumulative review surface is still tractable: one hundred and thirty small diffs against main, each on its own branch, each annotated by the YAML that produced it.
That is the central argument of Why we run every task in its own git worktree, and dogfooding made it concrete. The alternative — one long-lived branch with one hundred and thirty commits — would have been unreviewable by week three. Worktree-per-task is what kept the diff economy honest. If a task tried to do too much, the bloated diff was visible immediately, and the right move was to throw the branch out and rewrite the YAML. We did that more than once.
The metrics file is the retrospective
Every task from 0061 onwards has a sibling <n>.metrics.yaml file alongside its task file. Sixty-nine of them, as of this writing. Each one records duration_ms, tokens_in, tokens_out, cost_usd, exit_reason, agent_sessions — the full record described in What we measure when we measure an agent. All sixty-nine carry exit_reason: completed. Across the full directory, thirteen tasks needed more than one agent session to finish.
There is no retrospective ritual here. We do not run a weekly meeting where somebody pulls up an analytics dashboard and asks where the time went. We grep for agent_sessions: [2-9] and the answer is on disk. The metrics are siblings of the work itself; the diff and the cost of the diff live next to each other in the same directory. Insight is a filesystem operation. That is what made the dashboard category go away.
What dogfooding broke
Three honest things, all visible in the directory listing.
The most awkward is task 0009 and 0010. The first eight tasks shipped a purple website nobody wanted, and tasks 0009 and 0010 had to rip out every purple token and replace it with a fire-orange one. We did not anticipate the rebrand. The task file directory carries the scar, and you can read the entire wrong-then-right arc in the commit history. The lesson was real: pin the brand before the scaffolding lands. We did not, and the loop dutifully shipped the wrong one until we told it otherwise.
The next is task 0020 — "Update changelog with v0.1.1 through v0.3.0 releases." It carries agent_sessions: 6. A six-session task is a task that fought back. The story on disk is that bulk-updating a structured MDX file from a written changelog turned out to be much more error-prone than the prompt assumed; each session left the file almost right and the next one had to refine. The insight file flagged it immediately, the way the Insights post describes — grep -l "agent_sessions: [2-9]" .watchfire/tasks/*.yaml returns thirteen tasks, and 0020 is the worst of them. The fix, in retrospect, was a smaller per-version task, not a bigger model.
The third is the v4.0.0 cleanup. Task 0070 — "Site-wide consistency pass after v4.0.0 Beacon updates" — exists because the seven-task v4.0.0 push (0061 through 0070) shipped enough drift across the site that a follow-up pass was necessary to bring everything back into alignment. That follow-up was itself one of the multi-session tasks. The pattern is honest: when a feature lands in multiple places, the per-task brief sometimes leaves the seams visible, and the only fix is another task to walk them out. Not a flaw in the loop. A flaw in the brief.
Closing
The most persuasive documentation a developer tool can ship is not a tutorial, a screencast, or a comparison page. It is a repository where you can read the project's own task history and verify that the workflow the marketing site describes is the workflow the marketing site was built with. That is what .watchfire/tasks/ is. One hundred and thirty YAML files, one hundred and twenty-nine merged, one in progress. The fact that you are reading this on a site shipped by the system it documents is the argument. The receipts are on disk. The directory listing is the case study.
For a browseable hub of projects built this way — starting with this site and the daemon itself — see the Showcase.
More posts
Watchfire for teams: shared task lists, review surfaces, and multi-agent fleets
11 min
Watchfire was designed for one developer running many agents — but the same primitives (tasks as files, worktrees as review surfaces, audit trails on disk) turn out to be exactly what a team needs. Here's how it works when there's more than one of you.
Firestorm 9.0: Watchfire becomes a factory agents can drive
7 min
For nine majors Watchfire drove coding agents. Firestorm inverts that: watchfire mcp serve exposes the whole orchestrator to any MCP-capable client as an 18-tool factory, so an outer agent plans and reviews while Watchfire manufactures the code in sandboxed, worktree-isolated runs. It is the fourth thin client, it holds no orchestration logic of its own, and it is local-only by construction.
Inferno 8.0: one window per project
6 min
Inferno is the first feature-forward major since Beacon, and it's built around a single idea — supervising many projects at once. The Electron GUI goes multi-window, the Project View flips to chat-primary, wildfire becomes a GUI control, the dashboard becomes mission control, and a new analytics layer measures what the agents actually shipped, not just how many tasks closed.