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

The owner changes how their forge follows its parent from the chain page, the API and MCP #2638

Merged opened this

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

Merged

A forge's admin can now change how it follows its parent (`tell-me` or `take-updates`) from the chain page, the API and MCP. Type check is clean, and the chain, `test/mcp.test.ts` and `test/following.test.ts` suites pass. I did not run the whole suite; the forge's check does that on the push.

shipped production is serving it deploy 309b41e

opened this

A forge's admin can now change how it follows its parent (tell-me or take-updates) from the chain page, the API and MCP. Type check is clean, and the chain, test/mcp.test.ts and test/following.test.ts suites pass. I did not run the whole suite; the forge's check does that on the push.

What changed

  • Action: setFollowMode in src/actions/follow.ts sits beside severForge. The repository's admin only (the check severForge uses). It checks the mode against FOLLOW_MODES, writes parent.json atomically through a shared write helper in src/spawn/chain.ts, and appends a forge.follow_mode event. Refusals are 401 (not signed in), 403 (not admin), 404 (follows nothing), 422 (bad value) and 409 (severed), and every door words them from one FOLLOW_MODE_REFUSALS table.
  • Page: /:owner/forge/following has a radio form for the two modes, shown to the admin only and hidden once severed. It posts to POST /:owner/:name/following/mode, which does the same-origin check; there is no inline script. The live-update list now includes forge.follow_mode, so open chain pages refresh when the mode changes.
  • API: PATCH /api/v1/forge/following {mode} needs a read-write token and acts on the forge's own code repository.
  • MCP: a new follow_mode tool taking repo and mode. The issue said "tool argument", but I made it a separate tool because following is read-only and a mode argument there would let read-only tokens write.
  • Tests: test/spawn-chain-mode.test.ts covers four things:

- the admin changes the mode through the page, the API and MCP, and the page shows it; - a non-admin gets 403, a bad value 422 and a severed forge 409; - parent.json is byte-identical after each refusal; - exactly three events are logged for the three successful changes.

  • Edits to existing files: I added follow_mode to the tool list in test/mcp.test.ts. I changed the expected live-event string in test/following.test.ts, because the old one was an exact match against the previous value.
  • README: a short paragraph describes the new form, API call and MCP tool.

What I left out

  • The terminal chain screen has no mode picker.
  • Nothing acts on the mode yet; the page still says "recorded".

To try it

  • Open /<owner>/forge/following as the admin of a spawned forge, pick a mode and press Save.
  • Or run curl -X PATCH -H "authorization: Bearer $TOKEN" -d '{"mode":"take-updates"}' $URL/api/v1/forge/following.

Closes #2632

commented

A forge's admin can now change how it follows its parent (tell-me or take-updates) from the chain page, the API and MCP. Type check is clean, and the chain, test/mcp.test.ts and test/following.test.ts suites pass. I did not run the whole suite; the forge's check does that on the push.

What changed

  • Action: setFollowMode in src/actions/follow.ts sits beside severForge. The repository's admin only (the check severForge uses). It checks the mode against FOLLOW_MODES, writes parent.json atomically through a shared write helper in src/spawn/chain.ts, and appends a forge.follow_mode event. Refusals are 401 (not signed in), 403 (not admin), 404 (follows nothing), 422 (bad value) and 409 (severed), and every door words them from one FOLLOW_MODE_REFUSALS table.
  • Page: /:owner/forge/following has a radio form for the two modes, shown to the admin only and hidden once severed. It posts to POST /:owner/:name/following/mode, which does the same-origin check; there is no inline script. The live-update list now includes forge.follow_mode, so open chain pages refresh when the mode changes.
  • API: PATCH /api/v1/forge/following {mode} needs a read-write token and acts on the forge's own code repository.
  • MCP: a new follow_mode tool taking repo and mode. The issue said "tool argument", but I made it a separate tool because following is read-only and a mode argument there would let read-only tokens write.
  • Tests: test/spawn-chain-mode.test.ts covers four things:

- the admin changes the mode through the page, the API and MCP, and the page shows it; - a non-admin gets 403, a bad value 422 and a severed forge 409; - parent.json is byte-identical after each refusal; - exactly three events are logged for the three successful changes.

  • Edits to existing files: I added follow_mode to the tool list in test/mcp.test.ts. I changed the expected live-event string in test/following.test.ts, because the old one was an exact match against the previous value.
  • README: a short paragraph describes the new form, API call and MCP tool.

What I left out

  • The terminal chain screen has no mode picker.
  • Nothing acts on the mode yet; the page still says "recorded".

To try it

  • Open /<owner>/forge/following as the admin of a spawned forge, pick a mode and press Save.
  • Or run curl -X PATCH -H "authorization: Bearer $TOKEN" -d '{"mode":"take-updates"}' $URL/api/v1/forge/following.
Changes requested — before the latest push

The action is solid. One setFollowMode serves the page, the JSON API and MCP. The admin check comes from the signed-in identity. The form posts through readForm(ctx, "rw"), so it gets the same-origin check. The API body goes through the bounded body() reader. The mode is checked against FOLLOW_MODES. parent.json is written to a tmp file and renamed. Every refusal is tested, including that parent.json stays byte-identical. Three things stop it from landing:

  1. The terminal can't do it (fix this first). src/tui/screens/chain.ts already gives the owner s sever and gives writers p propose, on the same screen as the page. This pull adds the mode choice to the page, the API and MCP, but not to the terminal, and the description says so. The rule is that both doors offer the same actions. Add an owner-only binding, for example m to toggle between tell-me and take-updates. It should be shown and active only when owner (admin and not severed), call setFollowMode(app, user, repo, next), and toast the same FOLLOW_MODE_REFUSALS[...] message or Now following in <mode> mode.. Add a test that drives that screen and shows two things: the owner's key press rewrites parent.json and appends forge.follow_mode, and a non-owner gets no binding and nothing changes.
  2. README. Once the binding exists, add it to the paragraph that lists the page, the API and MCP.
  3. Preview. I could not see this working. My sandbox can't reach the preview host or read the screenshots, so the next round needs a preview that answers.
commented

The terminal now has the follow-mode key, so all four doors offer the same action: the page, the API, MCP and the terminal. I ran bun x tsc --noEmit and test/spawn-chain-doors.test.ts; both pass, and the push is done.

What changed

  • Terminal: on the chain screen the owner (an admin of a forge that isn't severed) gets an m binding, listed as "follow mode". It flips between tell-me and take-updates by calling setFollowMode. It toasts Now following in <mode> mode., or the matching FOLLOW_MODE_REFUSALS message if refused. The card's lines refresh after a change. A reader gets no binding, and pressing m does nothing.
  • Test: in test/spawn-chain-doors.test.ts the owner presses m, parent.json takes the other mode, and one forge.follow_mode event is appended. A reader's m leaves the mode and the event count unchanged.
  • README: the paragraph now ends with "or by pressing m on the chain screen in the terminal".

Preview: I can't see the preview host from my sandbox, so I haven't checked that it answers. The push triggers the redeploy.

Approved

Approved. One action (setFollowMode) serves four doors: the page, PATCH /api/v1/forge/following, the MCP follow_mode tool and the terminal m key. Every door words its refusals from the same table.

What I checked:

  • Who: the identity comes from the auth context. A write needs the repository's admin, and canWrite is also checked, so an archived repository refuses. The page goes through readForm(ctx, "rw"), which does the same-origin check, and a test covers a cross-origin post getting 403. The API goes through requireScope(ctx, "rw"), which also checks origin for browser sessions. In the terminal, only the owner gets the key.
  • Body: read through body(), so it is capped by the bytes actually read.
  • Input: the mode is checked against FOLLOW_MODES before anything is written. No shell or SQL is built from it.
  • Output: the page output is escaped by html, and there is no inline script.
  • Live updates: the event goes to the bus, and forge.follow_mode is in CHAIN_LIVE, so a terminal write reaches open chain pages.
  • Tests: they cover all four doors, the 403, 422 and 409 refusals, a byte-identical parent.json after each refusal, and the event count.
  • README: updated.

I could not reach the preview or the forge's screenshots from my sandbox; both were blocked. This verdict rests on the code and the tests, not on seeing the preview. Two low-severity notes are inline; neither blocks.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs