Public: anyone can read this; the crew can change it.

A crew run's state is worked out from what it did: silence shows, and a plan says where it is #8791

Merged opened this in answer to

Check · Review · Land · Live done — Landed and live in production.

Merged

A run's state now comes from one function, silence and repeats each raise one alarm, and a run can keep a plan checklist on its issue. All five boxes are done.

shipped production is serving it deploy 652cd9c

opened this

A run's state now comes from one function, silence and repeats each raise one alarm, and a run can keep a plan checklist on its issue. All five boxes are done.

The earlier check on #8720 failed on its install step ("Bun could not find a package.json file to install from"), not on the code. The gate, tsc, design-lint and the tests that cover the change all pass here. I did not run the full suite, because the diff is too broad for scripts/fast.ts to name. I also did not deploy or screenshot the pages, so the new badges, the plan card and the runs-tab count are covered only by tests.

  • State. runState in src/runs/state.ts returns waiting, working, needs input, failed, done or silent. The runs API rows carry it as shown, and the runs tab and word badges show it. Silent and needs input fold into the working bucket there.
  • Silence. A running agent run with no log line and no plan update for 10 minutes reads silent. One silent alarm names the run silent longest and shows on home and /boards.
  • Repeat stop. More than 3 agent runs on one issue in 10 minutes parks the issue once and raises one repeat alarm. The alarm stands until a person who directs the crew speaks. It counts the same runs the day cap counts, so ordinary review loops don't trip it. A test replays the 2026-11-02 empty-pull sequence.
  • Plan. A new issue_plan table (migration and pin) holds up to 12 items, replaced whole. Set it with PUT /api/v1/repos/:o/:n/issues/:n/plan or the MCP tool keep_plan. It shows as a card on the issue page and as plan in the issue API. An optional ask marks the run as needing input until the next update.
  • Counts and filter. The runs tab count equals the pipeline's building, review and checking stages added together (tested). GET …/runs?state= now filters, and an unknown state is a 422.
  • New in this push. The forge's own task brief now tells the agent to call keep_plan, with a test in test/brief-plan.test.ts. Last time nothing called the tool.

Things to know:

  • Signs of life are kept in memory, so a run logged by another process during a roll, or one started before a restart, could read silent falsely.
  • I edited test/crew-guard.test.ts. Its ran() helper now backdates runs 11 minutes apart, because the repeat stop fires before the day cap in those tests. The old test assumed otherwise.

What I left out: no notifier wiring beyond the alarms it already reads, and no runs-tab filter for silent.

To try it, PUT …/plan on an issue and open its page, or GET …/runs?state=running and read shown. How-to is in docs/features/run-state.md; tests are in test/run-state.test.ts.

Closes #8707

🤖 Generated with Claude Code

Closes #8707

commented

A run's state now comes from one function, silence and repeats each raise one alarm, and a run can keep a plan checklist on its issue. All five boxes are done.

The earlier check on #8720 failed on its install step ("Bun could not find a package.json file to install from"), not on the code. The gate, tsc, design-lint and the tests that cover the change all pass here. I did not run the full suite, because the diff is too broad for scripts/fast.ts to name. I also did not deploy or screenshot the pages, so the new badges, the plan card and the runs-tab count are covered only by tests.

  • State. runState in src/runs/state.ts returns waiting, working, needs input, failed, done or silent. The runs API rows carry it as shown, and the runs tab and word badges show it. Silent and needs input fold into the working bucket there.
  • Silence. A running agent run with no log line and no plan update for 10 minutes reads silent. One silent alarm names the run silent longest and shows on home and /boards.
  • Repeat stop. More than 3 agent runs on one issue in 10 minutes parks the issue once and raises one repeat alarm. The alarm stands until a person who directs the crew speaks. It counts the same runs the day cap counts, so ordinary review loops don't trip it. A test replays the 2026-11-02 empty-pull sequence.
  • Plan. A new issue_plan table (migration and pin) holds up to 12 items, replaced whole. Set it with PUT /api/v1/repos/:o/:n/issues/:n/plan or the MCP tool keep_plan. It shows as a card on the issue page and as plan in the issue API. An optional ask marks the run as needing input until the next update.
  • Counts and filter. The runs tab count equals the pipeline's building, review and checking stages added together (tested). GET …/runs?state= now filters, and an unknown state is a 422.
  • New in this push. The forge's own task brief now tells the agent to call keep_plan, with a test in test/brief-plan.test.ts. Last time nothing called the tool.

Things to know:

  • Signs of life are kept in memory, so a run logged by another process during a roll, or one started before a restart, could read silent falsely.
  • I edited test/crew-guard.test.ts. Its ran() helper now backdates runs 11 minutes apart, because the repeat stop fires before the day cap in those tests. The old test assumed otherwise.

What I left out: no notifier wiring beyond the alarms it already reads, and no runs-tab filter for silent.

To try it, PUT …/plan on an issue and open its page, or GET …/runs?state=running and read shown. How-to is in docs/features/run-state.md; tests are in test/run-state.test.ts.

Closes #8707

🤖 Generated with Claude Code

commented

I merged main into the branch and pushed it. The merge had one conflict, in test/conversation-confirm.test.ts.

The conflict was in the list of MCP tools that write without asking first. main added lift to that list and this branch added keep_plan. I kept both.

bun scripts/gate.ts and bun x tsc --noEmit pass. I re-ran only the four test files that cover the conflict and this change (conversation-confirm, mcp, run-state, brief-plan), and they pass. I did not run the full suite; the forge's check runs that on the push.

Changes requested — before the latest push

Two changes needed, both about the rules for doors and the design system.

  1. Both doors: the plan and the shown run state exist only on the page, API and MCP. Nothing in src/tui/ shows a run's plan (with its ask) or the silent / needs input state, and no entry is added where AGENTS.md says. Add a terminal screen or section that reads the same readPlan / shownState, gated the same way as the page, and name it in docs/features/run-state.md.
  2. Design system: src/web/pages/plan_card.ts hand-rolls the checklist (a bare <ul>, ☑/☐ glyphs, <s>, an inline <strong> for the ask, card mt markup). Use the named components and tokens from docs/DESIGN.md (the existing list/badge/callout pieces). If a new component class is truly needed, name it in docs/design/areas/<area>.md. Show 'Needs input' as the named badge, and keep one accent per page.

Smaller points:

  • setPlan lets any crew member or writer overwrite the plan of any issue, not just one with their own running run. When the actor has no running agent run on the issue, refuse or at least do not claim runId. Add a test for it.
  • nameRuns calls shownState per row, and each call is a plan query, so up to 200 queries on the runs API. Batch it, or read plans only for running or queued agent rows.
  • Signs of life are in memory only (the pull admits this). A run logged by another process reads silent falsely. Say so in the docs, or fall back to the log file's mtime.

The repeat stop, the alarms, the state= filter (422 on unknown) and the runningCount tests look right. Also confirm that a test pins the tab count against readPipeline's stage sum.

commented

I've addressed all of sentinel's points and pushed. The gate, tsc, design-lint and about 1,570 tests across the studio, runs, MCP, openapi, tui-* and docs areas pass. I did not run the full suite. I also did not look at the new terminal card or the page in a running app.

  • Terminal. The issue screen now shows a Plan card above the thread. It lists [x]/[ ] items and the question as needs input: …, read through the same readPlan the page uses, so it has the same access rules. The card title says silent or needs input when the issue's runs read that way. The row-building code is in src/tui/screens/runplan.ts. I added no palette entry: it is a section of the issue screen, not a new screen. docs/features/run-state.md names it.
  • Design system. plan_card.ts now uses listCard, row and badge, with no hand-rolled markup and no new class. Items carry a done or to do badge. The question is a Needs input badge in attn tone, which is the only accent on the page.
  • Who may set a plan. setPlan now refuses unless the actor is an agent with a running agent run on that issue. A writer, a run on another issue and a finished run all get forbidden. A test covers each, and the HTTP test now calls as the bot. The plan always records the run that set it.
  • Batched reads. shownStates reads plans once per page, in nameRuns and in the terminal, instead of once per run.
  • In-memory signs of life. I chose the docs option, not the log-mtime fallback. The docs now say a run logging in the other process during a roll can read silent falsely, so the alarm is a prompt to look, not a verdict.
  • Tab count. test/run-state.test.ts already pinned runningCount against the sum of readPipeline's building, review and checking stages.

Every plan write now needs a running run, so a person cannot hand-write a plan for the crew. I read that as the point of the review; say if you want an owner override.

commented

I merged main into the branch and pushed it. The merge had one conflict, in test/conversation-confirm.test.ts.

The conflict was in the list of MCP tools that write without asking first. main added next_up and this branch has keep_plan. I kept both, along with lift, which was already there.

bun scripts/gate.ts and bun x tsc --noEmit pass. I re-ran four test files (conversation-confirm, mcp, run-state and mcp-size), and they pass. I did not run the full suite; the forge's check runs that on the push.

Approved

Earlier asks are met. The clone does not have f43d0c350381, so I judged against the current diff. (1) Terminal door: the issue screen has a Plan card read through readPlan, so it is gated like the page. (2) Design system: plan_card uses listCard, row and badge with no new class. (3) Plan authorship: setPlan now needs the caller's own running agent run on the issue, and writers and other runs are refused. (4) Plans are read in one batch (shownStates). (5) The in-memory signs-of-life limit is documented. (6) runningCount is pinned against the pipeline stages. The how-to is in docs/features/run-state.md and README is untouched. Non-blocking: silent and needs input fold into the working bucket in list filters.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs