Skip to content

feat(claude-code): plannotator tool for agent-initiated opens under the mod - #1673

Merged
backnotprop merged 2 commits into
mainfrom
feat/claude-mod-plannotator-tool
Oct 3, 2026
Merged

backnotprop merged 2 commits into
mainfrom
feat/claude-mod-plannotator-tool

Conversation

@backnotprop

Copy link
Copy Markdown
Owner

Why

When the user tells Claude "open this in plannotator", Claude follows the plannotator skill and runs the CLI through Bash. That blocks Claude, and Ask AI then uses a separate AI. The mod (#1672) already makes the slash commands non-blocking. This PR gives agent-initiated opens the same behavior: Claude gets a real tool instead of the CLI.

What

  • One contract, packages/shared/plannotator-tool.ts: name plannotator, JSON schema, description, strict validation, argument mapping and result text. Input: { action: "annotate" | "review" | "last", target?, gate? (annotate), options?: { base? (review --base), markdown? (annotate --markdown) } }. Pi and OpenCode can adopt it later; they are not touched here.
  • Mod copy in apps/hook/hooks/mod/tool.ts, because a hooks module may import only its own folder. tool.test.ts fails if its CONTRACT section differs byte for byte from the shared file.
  • Registration: $.tool.register runs at session.start only when the mod is on, the session is interactive and /bin/sh exists. With the switch off, in -p runs and on Windows, nothing is registered.
  • Calls are answered in the mod's tool.call hook and use the same launch as the slash commands (PlannotatorMod.open): detached CLI, host result file, bridge token, session tag, cleanup. The tool returns at once and tells Claude to end its turn and wait. A bad call or a CLI startup error comes back as an error result.
  • Delivery: a gated tool session (gate: true) delivers a bare Approve as a turn, because Claude was told to wait for the sign-off. Done and Close send nothing. Slash-command behavior is unchanged.
  • Skill: one host-neutral line in the core plannotator skill: if your agent has a plannotator tool, use it instead of the CLI.
  • Docs: the AGENTS.md mod section.

Out of scope: Pi, OpenCode, plan review (stays on ExitPlanMode), intercepting Bash plannotator commands. Gated --json CLI runs are unchanged.

Verification

  • bun run typecheck, full bun test (5908 pass, 0 fail), claude plugin validate apps/hook (passes, lists $.tool.register), scripts/test-claude-code-mod.sh (9 pass, including 3 new tool cases).
  • Live on Claude Code 2.1.288 with --plugin-dir, a CLI built from this branch on PATH, PLANNOTATOR_CLAUDE_MOD=1 and a temp data dir:
    • "open notes.md in plannotator" made Claude call plannotator - plannotator (MCP), not Bash. The call returned in about 2 s and the page served.
    • Ask this session streamed an answer from the session ("No, notes.md says the cache is optional.").
    • Feedback posted through /api/feedback arrived as a plugin message, and Claude acted on it.
    • Close only logged a line. A gated open ("so I can approve it") launched with --gate, and Approve arrived as "Plannotator: notes.md — Approved."
    • With the switch off, Claude reported no plannotator tools, fell back to the CLI through the skill, and Ask AI offered no session bridge.

Known limitation

$.tool.register tools are deferred behind tool search; it cannot set alwaysLoad. Claude sees only the tool's name until it searches. With the updated skill line, Claude searched for the tool and called it. In a profile that still had the older installed skill text, Claude loaded that skill and ran the CLI. Users therefore need the refreshed skill, which the installer provides.

…he mod

When the user asks Claude to "open this in plannotator", Claude ran the CLI
through Bash, which blocks the session and gives Ask AI a separate AI. With
the mod on, Claude now gets a real `plannotator` tool ($.tool.register) that
goes through the same detached launch as the slash commands: it returns at
once, the decision arrives later as a plugin turn, and Ask this session works.

- packages/shared/plannotator-tool.ts: the one contract (name, schema,
  description, strict validation, argument mapping, result text) Pi and
  OpenCode can adopt later; the mod keeps a byte-for-byte copy with a parity
  test (hooks modules import only their own folder).
- Registered only when the mod is enabled, interactive and not Windows.
- A gated tool session delivers a bare Approve as a turn; Done/Close send
  nothing; slash-command behavior is unchanged.
- Core plannotator skill: one host-neutral line to prefer the tool.
@backnotprop
backnotprop merged commit fbdc1ea into main Oct 3, 2026
28 checks passed
@backnotprop
backnotprop deleted the feat/claude-mod-plannotator-tool branch October 3, 2026 21:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant