1 Building with Issues
mitosis edited this page 2026-07-29 08:11:35 -05:00

Issues are your roadmap and the crew is your build team: describe what you want, add one label, and an agent builds it, previews it, and ships it through a validated PR. This page covers the full loop — writing, steering, dependencies, rework, and episodes.

The one label that does everything

Apply the agent-work label to any open issue. That's the entire trigger — the label IS the queue.

What happens next, in order:

  1. The label flips to agent-working — an agent has claimed it.
  2. A PR opens titled 🏗️ <your issue title>, with Closes #N in the body and a plan, on a branch named agent/issue-<N>.
  3. Commits stream in; every push refreshes a live preview at https://pr-<PR#>-<app>-<org>.espoautos.com (see Preview Environments).
  4. When the agent is done, the 🏗️ prefix drops from the PR title. A validator signs into the preview with a real browser and posts exactly one verdict.
  5. On ✅ Ship it or ⚠️ Ship with nits, the PR auto-merges — closing your issue, unblocking anything that depended on it, and auto-releasing a patch version.

While a long run is in flight you'll see one self-updating heartbeat comment (🔄 worker working...) instead of comment spam, and every finished run ends with a ship summary plus three prefilled links for follow-up issues — the roadmap grows itself.

Fastest way to file: a prefilled new-issue link like

https://git.espoautos.com/<org>/<app>/issues/new?title=Add+CSV+export&body=Users+need+to+export+reports+as+CSV.

title and body prefill works everywhere; Forgejo doesn't accept a label in the URL, so apply agent-work after you hit Create.

Writing an issue that builds well

The issue body becomes the agent's prompt, verbatim. Deliverable-shaped beats vague:

  • One deliverable per issue. "Add CSV export to the reports page" — not "improve reporting".
  • Say what done looks like. The validator will exercise your core flow in a browser; describe it so it can.
  • Never paste credentials. Secrets go in repo Settings → Actions → Secrets (see Secrets and Config), never in issue text.

Anatomy of a well-run issue

Title: Add CSV export to reports Body: On the reports page, add an "Export CSV" button that downloads the current filtered view as a CSV with a header row. Empty results should download a header-only file, not error.

Timeline: label agent-work added → agent-working, PR 🏗️ Add CSV export to reports opens → 4 commits, preview link posted → comment on the PR: "use semicolons for EU locale" → agent adjusts → 🏗️ drops → validator verdict ✅ Ship it → auto-merge, issue closed, v0.3.4 released → Time Spent: 18m logged on the issue.

Steering while it builds

Comment directly on the PR while the 🏗️ prefix is on the title — the building agent reads your comments and adjusts course mid-flight. This is the steering wheel; use it for scope corrections, taste calls, and "actually, do it this way" moments. Once the prefix drops, the build phase is over and the validator takes it from there.

To re-engage an agent on an existing open PR, apply agent-work to the PR itself.

Dependencies: build in the right order

When issue B needs issue A finished first, declare a real Forgejo dependency — open issue B's "Blocked by" field in the UI and add issue A, or via the MCP tool add_issue_dependency (cross-repo with dep_owner/dep_name, e.g. leasing#2 blocked by homebase#2). Semantics: the blocked issue cannot start until the blocker closes.

The dispatcher honors edges automatically: an agent-work issue with open blockers is deferred without burning budget — the label stays on, and the moment the blocker closes, ready dependents are armed and the wave cascades. Dependencies are not body text; the only in-body markers are provides: <slug> / consumes: <slug> lines that name shared surfaces (one provider per slug — see Orgs and Planning).

Two rules that keep graphs alive:

  • A blocker must itself be labeled agent-work — an unlabeled blocker dead-stops everything downstream.
  • If an issue stalls on a cycle or a dead blocker, the platform diagnoses it and posts one 🚧 comment telling you the exact fix (remove an edge, or label the blocker). Benign "still building" waits are never nagged.

Prefer a flag over an edge: use dependency edges only when the later issue truly can't work without the earlier one. Mere feature ordering is better built now behind a release feature flag defaulting OFF.

Rework, bounded

A ❌ Blockers found verdict isn't the end — it's a loop. The dispatcher re-adds agent-work, a fresh agent fixes the blockers, and the validator re-checks. This is bounded: after the validator returns blockers more than twice, the platform stops auto-iterating and posts a 🛑 handoff comment. From there it's yours: push a fix and re-add the agent-work label to resume. ❌ Untestable means infrastructure failure, not your code — no rework round is charged.

The timeclock

Every completed run stamps its real agent-compute time onto the issue or PR it served, using Forgejo's native Time Spent tracker. That's active compute, not calendar time — open any issue and see exactly what it cost in agent effort. These figures roll up into episode digests.

Milestones are episodes

Group post-v1 issues into milestones titled like v1.1 — sharing. A milestone is an episode: the fleet view tracks its progress bar, and when every issue in the open milestone closes, the platform closes the milestone and posts one digest to the episode log — ✅ <org>/<repo> / <milestone> — episode complete, with issues shipped and total agent-compute logged. Add &milestone=<id> to a new-issue deeplink to file straight into an episode.

The docs keep up

Every change the crew ships carries its documentation with it: the app repo's wiki/ pages (the Wiki tab) get updated in the same PR when a change makes them stale — flows on Home, endpoints on API, schema on Data-Model — and the validator spot-checks that the docs still describe the app it just drove. You never file a "update the docs" issue; the docs are part of done.

Keep going