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

The Claude Code and OpenCode plugins archive an app and decide many asks at once, with a confirm and an undo #11193

Merged opened this

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

Merged

Both plugins' `/forge` command now has `archive <app>`, `decide all <dismiss|ship|close> [kind]` and `undo <operation>`, with no new MCP tool. `test/plugins.test.ts` and `test/mcp-size.test.ts` pass (32 tests) and `bun x tsc --noEmit` is clean. I did not run `scripts/gate.ts`, `scripts/fast.ts` or the full suite; the forge's check runs the full suite on push.

shipped production is serving it deploy abf00b0

opened this

Both plugins' /forge command now has archive <app>, decide all <dismiss|ship|close> [kind] and undo <operation>, with no new MCP tool. test/plugins.test.ts and test/mcp-size.test.ts pass (32 tests) and bun x tsc --noEmit is clean. I did not run scripts/gate.ts, scripts/fast.ts or the full suite; the forge's check runs the full suite on push.

  • archive <app>: calls archive with repo. It is planned first, and dryRun: false is sent only after the person says yes. The receipt says the app is put away, not deleted, and how to wake it: say archive <app> again, which calls archive with archived: false.
  • decide all <dismiss|ship|close> [kind]: calls asks and takes every row, or only rows of that kind. It plans asks_act with those items and says how many and which. After a yes it applies with dryRun: false and prints the operation id with undo <operation>.
  • undo <operation>: calls asks_act with action: "undo" and that operation.
  • Where: the verbs are in plugins/claude-code/commands/forge.md and the COMMAND text in plugins/opencode/forge.ts. Both argument hints and both READMEs list them.

Tests:

  • Both texts must name archive and asks_act, which the server lists.
  • Both must carry the three verb phrases, the wake instruction and the confirm gate.
  • Both hints and READMEs must list the verbs.
  • Renaming archive to a tool the server doesn't have is caught, as it was before.
  • The expected verb list now includes archive, undo and a second decide, since decide all is its own line.

Not done:

  • I did not add a tool, change any ceiling or touch the MCP server.
  • decide all has no cap beyond asks_act's own 100 items.

To try it, run /forge archive <app> or /forge decide all dismiss in either harness.

Closes #11189

commented

Both plugins' /forge command now has archive <app>, decide all <dismiss|ship|close> [kind] and undo <operation>, with no new MCP tool. test/plugins.test.ts and test/mcp-size.test.ts pass (32 tests) and bun x tsc --noEmit is clean. I did not run scripts/gate.ts, scripts/fast.ts or the full suite; the forge's check runs the full suite on push.

  • archive <app>: calls archive with repo. It is planned first, and dryRun: false is sent only after the person says yes. The receipt says the app is put away, not deleted, and how to wake it: say archive <app> again, which calls archive with archived: false.
  • decide all <dismiss|ship|close> [kind]: calls asks and takes every row, or only rows of that kind. It plans asks_act with those items and says how many and which. After a yes it applies with dryRun: false and prints the operation id with undo <operation>.
  • undo <operation>: calls asks_act with action: "undo" and that operation.
  • Where: the verbs are in plugins/claude-code/commands/forge.md and the COMMAND text in plugins/opencode/forge.ts. Both argument hints and both READMEs list them.

Tests:

  • Both texts must name archive and asks_act, which the server lists.
  • Both must carry the three verb phrases, the wake instruction and the confirm gate.
  • Both hints and READMEs must list the verbs.
  • Renaming archive to a tool the server doesn't have is caught, as it was before.
  • The expected verb list now includes archive, undo and a second decide, since decide all is its own line.

Not done:

  • I did not add a tool, change any ceiling or touch the MCP server.
  • decide all has no cap beyond asks_act's own 100 items.

To try it, run /forge archive <app> or /forge decide all dismiss in either harness.

Changes requested — before the latest push

One real bug, found by reading src/http/mcp/tools/asks_act.ts. asks_act is dry by default: with action: "undo" and no dryRun: false it only answers { wouldUndo } and reverses nothing (asks_act.ts, the undo branch). Both undo <operation> lines say 'call asks_act with action undo and operation = the id; say what it reversed', so the agent plans and then reports a reversal that did not happen. That is the one safety net of this feature failing silently.

Fix first: in both plugins make undo plan and then apply. Say 'call asks_act with action: "undo" and operation = the id (planned first); after the person says yes, call again with dryRun: false; say what it reversed from the receipt'. Add a test assertion that the undo line mentions dryRun, so it fails without the fix.

Also in this round:

  1. decide all: asks_act takes at most 100 items. Say what the agent does with more rows (apply the first 100 and say how many remain, or stop and ask), instead of leaving it to a schema error after the person has confirmed.
  2. The test expect(t).toMatch(/action[^\n]*undo/) passes on any line that has 'action' before 'undo', including the verb hint. Anchor it to the undo line. Only after (they|the person) says? yes is also loose.
  3. verbsOf now expects decide twice. Make the helper dedupe, or compare unique verbs, so the equality test does not break when a verb gets a second form.

The archive text matches the tool (repo, archived, dryRun default true). READMEs and hints are updated, no README feature how-to was added, and there is no new dependency.

commented

I've pushed the fixes for all four points. test/plugins.test.ts, test/mcp-size.test.ts and tsc --noEmit pass. I did not run scripts/gate.ts or the full suite.

  • undo <operation> bug: both plugins now plan first, since asks_act defaults to dryRun: true and only answers wouldUndo. After the person says yes, the agent calls again with dryRun: false and reports what was reversed from the receipt. The line also says never to call it undone before that second call.
  • decide all past 100 rows: both plugins now say asks_act takes at most 100 items. With more rows, the agent plans and applies only the first 100, says how many remain, and offers to run it again for the rest.
  • Test anchoring: the undo assertions now run on the undo <operation> line itself, which must carry action: "undo", dryRun: false and "after the person says yes". The decide all line must carry the 100-item rule. The archive confirm check is anchored to the archive <app> line and now requires its dryRun: false re-call wording.
  • verbsOf: it now dedupes, so a second form of a verb no longer breaks the equality test. The expected verb list lists decide once.
Approved

All four earlier asks are met. (1) undo now plans first and applies only after a yes with dryRun false, and never says it is undone before the second call. (2) decide all states the 100-item cap, the first-100 rule and how many remain. (3) The tests anchor to the verb lines themselves. (4) verbsOf dedupes. Non-blocking: next, I would add a test that the item cap in the text matches asks_act own limit, so the two cannot drift. Non-blocking: the second README paragraph in the opencode plugin ends with a stray blank line before /forge plan; tidy it.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs