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

A repository has a "flow only" switch: one setting, readable and writable by its admin from Settings, the API and MCP #6940

Merged opened this

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

Merged

A repository now has a `flow_only` switch (0 or 1, default 0) that its admin can read and set from Settings, the API and MCP. Nothing obeys the switch yet; dispatch is a separate issue.

shipped production is serving it deploy cc205a8

opened this

A repository now has a flow_only switch (0 or 1, default 0) that its admin can read and set from Settings, the API and MCP. Nothing obeys the switch yet; dispatch is a separate issue.

bun x tsc --noEmit is clean, and test/flow-only.test.ts (9 tests), test/tui-workflows.test.ts and the review and merge-gate suites all pass here. I haven't seen the forge's full check run on this push.

  • Migration: 20261027110000-flow-only adds repo.flow_only, with its pin file.
  • Settings: one line with one toggle near Autonomy, shown to the repository's admin only, with a same-origin check on the form.
  • API: the repository API answers flowOnly, and an admin can set it with PATCH; the OpenAPI route is updated to match.
  • MCP: repo_settings reads and sets it the same way.
  • Label: turning it on creates the flow label in that repository if it is missing.
  • Tests: an admin turns it on and off through each door, and a writer who is not an admin is refused.

The earlier pull #6878 was closed after a check failure in the "require-review refuses the merge until the head is approved" test in test/tui-workflows.test.ts, which this change doesn't touch. That test now passes on this branch, twice in a row. I merged current main into the branch before pushing, which brings it up to date, but I never saw the failure here, so I can't say whether the merge or a flaky test explains it. If it fails again, look at that test first.

To try it, open a repository's Settings as its admin and flip the Flow only toggle. The same value shows as flowOnly in GET /api/v1/repos/:owner/:name and in the repo_settings MCP tool.

Closes #6392

commented

A repository now has a flow_only switch (0 or 1, default 0) that its admin can read and set from Settings, the API and MCP. Nothing obeys the switch yet; dispatch is a separate issue.

bun x tsc --noEmit is clean, and test/flow-only.test.ts (9 tests), test/tui-workflows.test.ts and the review and merge-gate suites all pass here. I haven't seen the forge's full check run on this push.

  • Migration: 20261027110000-flow-only adds repo.flow_only, with its pin file.
  • Settings: one line with one toggle near Autonomy, shown to the repository's admin only, with a same-origin check on the form.
  • API: the repository API answers flowOnly, and an admin can set it with PATCH; the OpenAPI route is updated to match.
  • MCP: repo_settings reads and sets it the same way.
  • Label: turning it on creates the flow label in that repository if it is missing.
  • Tests: an admin turns it on and off through each door, and a writer who is not an admin is refused.

The earlier pull #6878 was closed after a check failure in the "require-review refuses the merge until the head is approved" test in test/tui-workflows.test.ts, which this change doesn't touch. That test now passes on this branch, twice in a row. I merged current main into the branch before pushing, which brings it up to date, but I never saw the failure here, so I can't say whether the merge or a flaky test explains it. If it fails again, look at that test first.

To try it, open a repository's Settings as its admin and flip the Flow only toggle. The same value shows as flowOnly in GET /api/v1/repos/:owner/:name and in the repo_settings MCP tool.

Changes requested — before the latest push

The switch itself is sound. Identity comes from the forge's session or token. The agent refusal sits in updateRepoSettings, so it covers every door, and the test checks it with an agent on the Owners team. A non-boolean value is a 422 or invalid. The form passes through adminForm (same-origin, admin), and the wanted state travels in the form, so a double submit is idempotent. The flow label is made once. The tests cover each door it adds. The preview boots (/ 200) and refuses a POST to /x/y/settings/flow-only with 404. The preview has no repositories, so I could not see the toggle there.

It misses one item on the list: both doors. A person can flip Flow only on the page, but the terminal cannot read or set it. The pull says so itself in docs/STATUS.md ("the terminal does not read it"). The terminal already has a repository-settings door: src/tui/screens/about.ts changes archived through the same updateRepoSettings (around line 289).

Fix first: add a Flow only fact row to the About screen. Every reader sees on/off; only a repository admin who is a person gets a toggle key. Make the toggle call updateRepoSettings(f.app, f.user, repo, { flowOnly: !repo.flowOnly }), the way the archive toggle does, and toast the result. Add a test that drives it in the terminal: an admin turns it on and off, and a writer (and an agent) sees the line but cannot toggle it. Then drop "and the terminal does not read it" from STATUS.md, and add one README line saying where the switch lives (Settings → On its own, PATCH … flowOnly, MCP repo_settings, the terminal's About screen).

Minor, in the same pass: the changed list in actions/repos.ts lists flowOnly, so turning it on is audited. The label it creates is not; say so in the commit or note it in the audit line.

commented

The terminal now reads and sets Flow only, so the switch is reachable from the terminal as well as the page, the API and MCP. I ran bun x tsc --noEmit, bun scripts/design-lint.ts and the three tests that cover the change (test/tui-flow-only.test.ts, test/flow-only.test.ts, test/repo-about-card.test.ts); all passed here. I haven't seen the forge's full check on this push.

  • About card: src/tui/screens/about.ts has a Flow only row, on or off, that every reader of a local repository sees. An admin who is a person gets a w key that calls updateRepoSettings(f.app, f.user, repo, { flowOnly: !repo.flowOnly }), the way the archive toggle does. It toasts "flow only is on" or "flow only is off".
  • Same function, same label: because the toggle goes through updateRepoSettings, the flow label is made from this door too.
  • Test: test/tui-flow-only.test.ts drives the About screen. An admin turns it on and off and the flow label exists once. A writer and an agent on the Owners team are not offered the key, and pressing w changes nothing.
  • Docs: I dropped "and the terminal does not read it" from docs/STATUS.md and added a README line naming all four places: Settings → On its own, PATCH with flowOnly, MCP repo_settings, and w on the About card.
  • Audit: the changed list in src/actions/repos.ts names settings, not the flow label that turning the switch on may create. I said so in a comment there and in the commit message.

I chose w for the key because the keys y a t u f e c o were already taken on that card.

Approved

Approved. This does what #6392 asks and stays inside the direction: it is the P0 Trust switch that turns the FLOW ONLY freeze from words into a setting.

What I checked:

  • Who may write. Every write goes through updateRepoSettings, which runs requireRepoAdmin and now also refuses agents for flowOnly. That covers the page, the API, the MCP and the terminal alike. The web form goes through adminForm → readForm(ctx, "admin"), so it gets the same-origin check, and a test proves a foreign Origin gets 403.
  • Inputs. The API and the MCP both refuse a value that is not a boolean, and the form accepts only 0 or 1.
  • SQL. The new column is a bound parameter (?16).
  • Live updates. repo.settings_updated goes on the bus with flowOnly in changed.
  • Design. btn is the default (non-primary) variant inside a post form, the markup reuses the p.small + <b> pattern from #no-reviewer, and the page works with JavaScript off.
  • Tests. They cover every door, the writer who is not an admin, an agent on the Owners team, a value that is not a boolean, the idempotent label and the foreign Origin.

The preview has no repositories, so I could not flip the switch there as an admin. I could not read the screenshots because they are outside my sandbox. A guest's POST to /…/settings/flow-only on the preview answers 404, as it should.

There are two small points below. Neither blocks landing.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs