1 Building with Issues
mitosis edited this page 2026-09-02 08:56:51 +00:00

Issues are the roadmap. The crew is the build team. Write what you want in an issue. Add one label. A builder builds it, previews it, and ships it through a reviewed PR. This page covers the full loop: writing issues, steering, dependencies, rework, and episodes.

The one label that does everything

Apply the agent-work label to any open issue. The label is the entire trigger. The label IS the queue.

What happens next, in order:

  1. The label flips to agent-working. An agent has claimed the issue.
  2. A PR opens on a branch named agent/issue-<N>. The title is 🏗️ <your issue title>. The body carries Closes #N and a plan.
  3. Commits stream in. Every push refreshes a live preview at https://pr-<N>-<app>-<org>.open-platform.sh, where <N> is the PR number. See Preview Environments.
  4. When the builder finishes, the 🏗️ prefix drops from the PR title. The reviewer signs into the preview with a real browser. The reviewer posts exactly one verdict.
  5. On ✅ Ship it or ⚠️ Ship with nits, the PR auto-merges. The merge closes your issue, unblocks dependents, and auto-releases a patch version.

The other two verdicts do not merge. ❌ Blockers found starts a bounded rework round (see below). ❌ Untestable reports an infrastructure failure, not a fault in your code.

During a long run, one heartbeat comment (🔄 worker working...) updates itself in place. There is no comment spam. Every finished run ends with a ship summary and three prefilled links for follow-up issues. The roadmap grows itself.

The fastest way to file is a prefilled new-issue link:

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

The title and body params prefill everywhere. Forgejo does not accept a label in the URL. Apply agent-work after you press Create.

To file the same brief on a schedule — a nightly QA sweep, a Monday review — see Routines.

Writing an issue that builds well

The issue body becomes the agent's prompt, verbatim. A deliverable-shaped issue builds better than a vague one.

  • One deliverable per issue. Write "Add CSV export to the reports page", not "improve reporting".
  • Say what done looks like. The reviewer drives your core flow in a browser. Describe the flow so the reviewer can drive it.
  • Never paste credentials. Secrets go in repo Settings → Actions → Secrets. See Secrets and Config. Never put a secret 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.

The timeline of that issue:

  1. You add the agent-work label. The label flips to agent-working.
  2. The PR 🏗️ Add CSV export to reports opens.
  3. Four commits land. The preview link is posted.
  4. You comment on the PR: "use semicolons for EU locale". The builder adjusts.
  5. The 🏗️ prefix drops. The reviewer posts ✅ Ship it.
  6. The PR auto-merges. The issue closes. The platform releases v0.3.4.
  7. The platform stamps Time Spent: 18m 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. Use comments for scope corrections, taste calls, and "actually, do it this way" moments. When the prefix drops, the build phase is over. The reviewer 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. In the UI, open issue B's "Blocked by" field and add issue A. Or call the MCP tool add_issue_dependency. Cross-repo edges use dep_owner / dep_name (for example, leasing#2 blocked by homebase#2). The blocked issue cannot start until the blocker closes.

The dispatcher honors edges automatically. An agent-work issue with open blockers waits without burning budget. The label stays on. The moment the blocker closes, ready dependents start and the wave cascades.

Dependencies are not body text. The only in-body markers are provides: <slug> / consumes: <slug> lines. These lines name shared surfaces, with one provider per slug. See Orgs and Planning.

Two rules keep graphs alive:

  • Label every blocker with agent-work. An unlabeled blocker stops everything downstream.
  • If an issue stalls on a cycle or a dead blocker, the platform diagnoses it. The platform posts one 🚧 comment with the exact fix: remove an edge, or label the blocker. The platform never nags a benign "still building" wait.

Prefer a flag over an edge. Use a dependency edge only when the later issue cannot work without the earlier one. For mere feature ordering, build now behind a release feature flag that defaults OFF.

You never need an edge to v1. Every app has a root issue (🏗️ v1: <app>) and every issue you file is rooted at it automatically — open root, the issue waits for v1; closed root, the edge is lineage. See Dependency Trees.

Rework, bounded

A ❌ Blockers found verdict starts a loop, not an ending. The dispatcher re-adds agent-work. A fresh agent fixes the blockers. The reviewer checks again. Rework is bounded at 2 rounds. After that, the platform stops auto-iterating and posts a 🛑 handoff comment. From there the work is yours: push a fix and re-add the agent-work label to resume.

❌ Untestable means an infrastructure failure, not a fault in your code. No rework round is charged.

The timeclock

Every completed run stamps its agent-compute time onto the issue or PR it served. It uses Forgejo's native Time Spent tracker. The figure is active compute, not calendar time. Open any issue to see its exact cost in agent effort. The figures roll up into episode digests.

Milestones are episodes

Group post-v1 issues into milestones with titles like v1.1 — sharing. A milestone is an episode. The fleet view tracks its progress bar. When every issue in the open milestone closes, the platform closes the milestone. The platform then 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. When a change makes the app repo's wiki/ pages (the Wiki tab) stale, the same PR updates them: flows on Home, endpoints on API, schema on Data-Model. The reviewer spot-checks that the docs still describe the app it just drove. You never file an "update the docs" issue. The docs are part of done.

Keep going