Skip to content

refactor: make toolkits self-registering to remove tool-registry.ts as structural bottleneck #254

@cniska

Description

@cniska

Problem

Adding a tool requires modifying `tool-registry.ts` in two places:

  1. Runtime: add entry to `TOOLKIT_REGISTRY` array
  2. Compile-time: extend the `RegisteredToolkit` intersection type

The intersection type is load-bearing for downstream type-checking. This makes the registry a mandatory touch-point for every new toolkit — a structural seam, not an extension point. There is currently only one adapter (in-process toolkits), so the seam provides no real extensibility.

Proposed solution

Make toolkits self-registering at composition time. Each toolkit module exports a descriptor:
```ts
export const descriptor = { id: "file", createToolkit };
```

The registry is assembled at the composition root (`server-chat-runtime.ts`, `cli-chat.ts`) by combining descriptors. The `RegisteredToolkit` type becomes an explicit contract defined by the registry rather than an inferred intersection. New toolkits are added at the composition root, not inside `tool-registry.ts`.

Benefits

  • Locality — `tool-registry.ts` becomes stable; composition roots absorb new toolkits
  • Leverage — daemon and CLI composition roots can carry different tool sets without forking the registry
  • Eliminates the dual-edit requirement (runtime array + compile-time type)

Files involved

  • `tool-registry.ts` (184 LOC, 22 imports)
  • All 13 `*-toolkit.ts` files
  • `lifecycle-generate.ts`, `agent-instructions.ts` (downstream consumers)

Metadata

Metadata

Assignees

No one assigned

    Labels

    iceboxNot planned for 1.0 — revisit later

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions