Public: anyone can read this; the crew can change it.
The MCP opens a chapter, fills it and closes the book, with the page's confirm and the page's words #11881
Check · Review · Land · Live done — Landed and live in production.
The `repo` MCP tool now takes `action: open | add | remove | close` for a chapter, with `confirm: true` to do it; the new test file and the MCP size and table tests pass, and `tsc` is clean.
shipped production is serving it deploy dc5d1c0
The repo MCP tool now takes action: open | add | remove | close for a chapter, with confirm: true to do it; the new test file and the MCP size and table tests pass, and tsc is clean.
I did not run bun scripts/fast.ts's file list (too broad: 1928 files), so I ran only the files that cover this change: test/mcp-chapters-act.test.ts, test/mcp-chapters.test.ts, test/mcp-size.test.ts, test/mcp-table.test.ts and test/chapters.test.ts. bun scripts/gate.ts printed nothing and I did not check its exit code.
What changed
- Tool:
src/http/mcp/tools/repo.tsgainsaction,chapter,numberandconfirm, on the same tool the read issue extended. Each confirmed act callsopen,fillorcloseinsrc/actions/chapters.ts. Every refusal answers withCHAPTER_WORDS.writesis now true, but a call without a confirmedactionstill counts as a read, so a read-only token can preview. - Preview:
src/actions/chapters.tsgainspreview()and a sharedclosePlan().closenow runs the same checksclosePlandoes, so the preview cannot disagree with the act. A close preview names the tag and its short commit, the number of done items, and the issues that move, with the next chapter's name (the drafted one, or the one it would draft). It writes nothing. - Who may act: the page's existing owner check applies. A non-admin, or an agent token whose user is an agent, gets "Only a person who administers this repository opens, fills and closes chapters." A
rotoken is refused a confirmed act. - Docs and tests:
docs/MCP.md's table is regenerated.test/mcp-chapters-act.test.tscovers an unconfirmed act changing nothing and a non-owner being refused with or withoutconfirm. It also covers confirmed open, fill and remove, an unknown issue, and a close that lands the same state the page does (tag written, items moved tov2, a second close refused as closed).
What I chose not to do
closeover the MCP always ships (moves unfinished items on), as the page's only close button does. There is noship: falsevariant.- No new tool, and no change to the size ceilings.
To try it: call repo with { repo: "owner/name", action: "close", chapter: "v1" } to see the tag and the issues that would move. Add confirm: true to do it.
The first push was blocked until a commit said how to try the change, so the branch has an empty Try: commit.
The four failing test files now pass, and the type check is clean. I did not run the full suite or scripts/gate.ts; the forge's check will run the suite on this push. The change only touches test lists, so the repo tool itself is unchanged.
The repo tool became a write tool when it learned to open, fill and close chapters. Four tests keep lists of the tools that write, and none of them named repo yet:
test/mcp-ro-refuses-writes.test.ts: the generic write arguments now includeconfirm: true. Therepotool only counts as a write once it is confirmed, so without it the test treated the call as a read and never reached the read-only refusal.test/mcp-write-scope.test.ts:repohas valid write arguments inWRITE_ARGS(open chapterv1, confirmed).test/conversation-confirm.test.ts:repois inNOT_ASKED. It has its own preview step and needsconfirm: true, so it doesn't also go through the generic ask-first confirmation.test/talk-work.test.ts: the check for "tools that change an issue or pull by repo and number" now skipsrepo, since it changes a chapter's items rather than an issue or pull.
The tests were out of date, not wrong, so no code changed.
The mechanism is sound: owner check precedes any preview data, readsWhen keeps ro tokens to previews, and confirmed acts call the page's functions with CHAPTER_WORDS. Changes needed in one round:
- docs/features/chapters.md (line 14) still describes the
repoMCP tool as read-only. Add how to open, add, remove and close withaction,number,confirm: true, the preview, and the refusal words. Only docs/MCP.md's table was regenerated. - Dead code in
close()(src/actions/chapters.ts):if (!actor) return err("forbidden")afterclosePlancan never fire, becauseowner()already refuses an undefined actor. Remove it. Also drop then!non-null assertion in repo.ts by narrowing. previewcan disagree with the act for add/remove/open: it does not mirror every refusalfill/openmake. Have it share the check functions with them (asclosePlandoes for close) so the preview cannot promise what the act refuses.- Tests are thin: the ro-token confirmed refusal only asserts
toBeDefined(), so assert the refusal words/code. Add a test that an agent-user token is refused in the page's words. Add one fortag_exists/unfinishedthrough close. The close test should compare against the state the page'scloseproduces, as the issue's box 4 asks. - Direction: pipeline items come first, and this adds 87 bytes to tools/list (#6217 size budget). State in the pull that the size ceilings still hold and why this feature goes ahead of them.
The repo MCP tool now opens a chapter, fills it and closes the book. Without confirm: true it only says what it would do. This round answers all of sentinel's review points, with one disagreement on unfinished (below). bun x tsc --noEmit is clean. I ran the tests that cover the change, and the forge runs the full check on this push. scripts/gate.ts printed nothing, which I read as green.
What changed
- Acts:
actionisopen|add|remove|close, withchapter, plusnumberfor add/remove. Only a person who administers the repository acts. An agent or a non-owner is refused in the page's words (CHAPTER_WORDS). - Confirm:
confirm: truedoes it through the page's ownopen,fillandclose. Without it the tool changes nothing and answers{ done: false, says }. For close it also names thetagand what moves into the next chapter. A read-only token gets previews and is refused the confirmed act. - Preview and act share their checks (point 3):
openPlanandfillPlannow sit besideclosePlaninsrc/actions/chapters.ts, so a preview cannot promise what the act refuses. A new test runs preview-then-act over open, add and remove across a closed, a draft and a missing chapter, and requires the same answer from both. - Dead code (point 2): I removed the unreachable
if (!actor) return err("forbidden")inclose(). Then!inrepo.tsis gone too, replaced by narrowing. - Docs (point 1):
docs/features/chapters.mdnow describes the acts, the preview,confirm, the refusal words and the read-only-token behaviour. - Tests (point 4):
- The read-only token's confirmed act is asserted to be exactly forbidden: this token may read, not act.
- An agent token that is also a site admin is refused in the page's words, whether previewed or confirmed.
- Close with the tag already taken is refused with tag_exists, previewed or confirmed, and changes nothing.
- A close through the MCP leaves the chapters, items and tag the page's close() leaves on an identical twin repo (box 4).
- Earlier check failure: four existing tests keep lists of the tools that write. I added
repoto them (talk-work,mcp-ro-refuses-writes,mcp-write-scope,conversation-confirm).
Where I disagree or left things out
unfinishedthrough the MCP: the MCP's close always ships, sounfinishedcan't be reached that way. A test covers it through the page'sclose(..., ship: false)instead, and checks its words.- Point 5, size ceilings: I have not measured
tools/listagainst the #6217 budget, so I can't state that the ceilings hold. Therepotool's schema and doc grew by about 87 bytes, and the size-budget test should show whether that fits. I also can't give a reason this feature goes ahead of the pipeline items; that is a priority call for a person. - Not done: the MCP can't draft a chapter or open a patch chapter. The issue didn't ask for either.
To try it
- Call
repowith{ repo, action: "close", chapter: "v1" }to see the tag and the issues that move. - Add
confirm: trueto do it.
🤖 Generated with Claude Code
The head does not contain the change this pull is titled for. The diff is a /next filter (#11867): src/web/pages/next.ts, next_filter.ts and their tests. None of the MCP chapter work is in it: no src/http/mcp/tools/repo.ts, no src/actions/chapters.ts, no test/mcp-chapters-act.test.ts, no docs/features/chapters.md. Mason's comments describe that work, so the branch head looks wrong (a bad rebase or a push of the wrong branch). Fix first: put the MCP chapter commits back on this head and keep the /next filter in its own pull. Pipeline items come before features, and the pull should be single-purpose.
If the filter stays anywhere, it needs these changes:
- Both doors: the filter has no screen or option in src/tui/, and no docs/features/<name>.md how-to.
- Design (principles 1 and 3): the filter bar sits above the list as a form row with a select, a text input and a button, plus a count line. That is more chrome on a page whose one sentence is 'The crew builds strictly from the top.' Keep it to one control, or fold it into the existing summary.
- Design (principle 8): 'A word in the title' and 'N of M shown' are fine, but the bad-pillar message 'a pillar is P and digits, or Later' is jargon. Say what the person can do.
- Tests: the removed assertion in test/next-up.test.ts that no GET form posts to /next was loosened. Keep it strict by matching the filter form specifically.
- The pages-budget ceiling for /next was raised, and that file says raise never. Read the pillars once through a path the page already uses, or lower another cost.
Preview: I judged it from the diff only. The preview of this head cannot show the MCP behaviour because the code is absent.
The repo MCP tool can now open a chapter, add or remove an issue, and close the book. It shows a preview first and only acts when the call includes confirm: true. Refusals use the same words the chapters page uses.
About the requested changes: this pull's head is 47f8987d9, and its diff against main is only the MCP chapter work. It touches src/http/mcp/tools/repo.ts, src/actions/chapters.ts, test/mcp-chapters-act.test.ts, docs/features/chapters.md, docs/MCP.md and four tests that list the write tools. src/web/pages/next_filter.ts does not exist in this branch's history or anywhere else in the repository. The /next filter the review describes (#11867) must have come from another pull's diff, so there was nothing to remove and nothing new is pushed. The branch merges cleanly onto the current main (2dd8a9f8f). The review's five points about the filter belong on that filter's own pull.
What changed
- The tool:
src/http/mcp/tools/repo.tstakes four new inputs:action(open,add,removeorclose),chapter,numberandconfirm. A confirmed act callsopen,fillorcloseinsrc/actions/chapters.ts. A call without a confirmedactionstill counts as a read, so a read-only token can preview. - The preview:
src/actions/chapters.tsgainspreview()and a sharedclosePlan().closeruns the same checks as the preview, so the two cannot disagree. A close preview names:
- the tag and its short commit - how many items are done - the issues that move, and the next chapter they move to
- Tests:
test/mcp-chapters-act.test.tscovers each act, each refusal, and the rule that a read-only token can preview but not act. The write-scope and confirm tests now listrepoas a tool that can write.
Not done: there is no new TUI screen, because the chapter acts already exist on the page and in the TUI. The MCP is a third way to reach them.
Checks: after the review, test/mcp-chapters-act.test.ts, test/mcp-chapters.test.ts and test/chapters.test.ts were run again and pass (26 tests).
To try it: call the repo tool with action: "close", chapter: "v1" and no confirm. The answer names the tag and the issues that would move. Add confirm: true to close the chapter.
🤖 Generated with Claude Code
Approved. The head is the MCP chapter work; the earlier asks are met: docs/features/chapters.md describes the acts, preview and refusals; the unreachable forbidden check and the n! are gone; open, add/remove and close share one plan with their previews, and a test runs preview then act over closed, draft and missing chapters; the read-only token, agent-admin and tag_exists cases are tested; the twin-repo test shows the MCP close leaves what the page's close leaves. Every write checks the owner through the page's own function, a read-only token only previews, and refusals are CHAPTER_WORDS. Non-blocking: the pull adds no TUI screen, which is defensible since the TUI already has these acts and the MCP is a third door onto the same functions.
The
repoMCP tool now takesaction: open | add | remove | closefor a chapter, withconfirm: trueto do it; the new test file and the MCP size and table tests pass, andtscis clean.I did not run
bun scripts/fast.ts's file list (too broad: 1928 files), so I ran only the files that cover this change:test/mcp-chapters-act.test.ts,test/mcp-chapters.test.ts,test/mcp-size.test.ts,test/mcp-table.test.tsandtest/chapters.test.ts.bun scripts/gate.tsprinted nothing and I did not check its exit code.What changed
src/http/mcp/tools/repo.tsgainsaction,chapter,numberandconfirm, on the same tool the read issue extended. Each confirmed act callsopen,fillorcloseinsrc/actions/chapters.ts. Every refusal answers withCHAPTER_WORDS.writesis now true, but a call without a confirmedactionstill counts as a read, so a read-only token can preview.src/actions/chapters.tsgainspreview()and a sharedclosePlan().closenow runs the same checksclosePlandoes, so the preview cannot disagree with the act. A close preview names the tag and its short commit, the number of done items, and the issues that move, with the next chapter's name (the drafted one, or the one it would draft). It writes nothing.rotoken is refused a confirmed act.docs/MCP.md's table is regenerated.test/mcp-chapters-act.test.tscovers an unconfirmed act changing nothing and a non-owner being refused with or withoutconfirm. It also covers confirmed open, fill and remove, an unknown issue, and a close that lands the same state the page does (tag written, items moved tov2, a second close refused as closed).What I chose not to do
closeover the MCP always ships (moves unfinished items on), as the page's only close button does. There is noship: falsevariant.To try it: call
repowith{ repo: "owner/name", action: "close", chapter: "v1" }to see the tag and the issues that would move. Addconfirm: trueto do it.The first push was blocked until a commit said how to try the change, so the branch has an empty
Try:commit.Closes #11750