Skip to content

$.tool.register: one typed supertool tool, so Bash stops impersonating it — not one tool per op #2294

Description

@fdaviddpt

Follows #2293. A function-hooks module can register tools at run time:

$.tool.register takes { name, description, inputSchema? }; name is letters, digits, _ or - (up to 64)
$.tool.register: loopback MCP server listening on 127.0.0.1:<port>
$.tool.register: this host cannot add tools at run time (no in-process MCP server registrar installed)

(strings from @anthropic-ai/claude-code-darwin-arm64@2.1.260, verified 2026-09-04)

The wrong version of this idea is to register the roster. It inverts the premise. A tool call carries one call; supertool 'read:A' 'read:B' 'git-status' is three answers in one round-trip, and three registered tools is three round-trips each re-paying the cached prefix. ops:full says it costs 80100 bytes of descriptions alone, before an inputSchema per op, and as registered tools that is prompt weight on every session whether or not the session calls one. This repo's own listing already ships signature-only for exactly that reason (#1774).

The right version is one tool. { name: "supertool", description: <the ops table>, inputSchema: { ops: string[] } }. Same batching, same op strings, but the model fills a schema instead of composing a shell string that the raw-command guard then has to police. Today every supertool call is a Bash call, which means:

A registered tool moves all three from advice to mechanism.

Open questions:

  • Which ops, if any, deserve their own entry. A typed argument may be worth a second tool for a few (read, maybe grep), and I have not measured which. The default answer is none.
  • What the description carries. The signature table is 80100 bytes in full and far less signature-only. The tool.describe hook can rewrite it per session, so it need not be static.
  • How it degrades. The binary has an explicit "this host cannot add tools at run time" path, and there is a name collision check against existing MCP servers. If the registrar is absent the plugin must still work as it does today, through Bash.
  • Whether the loopback MCP server is acceptable here. It listens on 127.0.0.1. That is a new surface in a tool whose whole containment story is about untrusted input, and it deserves its own look before this ships.

Blocked on the same flag as #2293: CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1, flag tengu_plugin_hooks_modules, GrowthBook-gated.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

cohort-29Open at the v0.60.0 tag, 2026-09-11. Frozen: nothing joins a cohort.cohort-30Open at the v0.61.0 tag, 2026-09-12. Frozen: nothing joins a cohort.cohort-31Open at the v0.63.0 tag, 2026-09-19. Frozen: nothing joins a cohort.cohort-32Open at the v0.64.0 tag, 2026-09-23. Frozen: nothing joins a cohort.enhancementNew feature or requestlane-containmentpayload gate and trust model — reaches into other lanes, wants their reviewpriority-mediumRecurring cost; compounds if unfixed

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions