Playbook — Authoring or Modifying an Adapter
P: Procedure for adding a new agent adapter under
src/adapters/<id>/or modifying an existing one (Claude / Codex). R: Adding a new agent runtime, bumping an adapter's SDK floor, expanding capability declarations, or porting a hook to a new adapter. S: Day-to-day Claude work — see claude-sdk.md instead. N: claude-sdk.md, adapter-parity.md, hooks-reference.md
Nav: Section Index | Docs Index
The mental model
An adapter is the mRNA layer that translates the agent-agnostic kernel (src/core/) into a specific agent's filesystem layout. Each adapter must self-contain enough configuration that a consumer project can install and run it independently of any other adapter.
Three contracts every adapter must satisfy:
adapter.yamldeclares the agent's identity, the directory layout it expects (hooks_dir,rules_dir,skills_dir,commands_dir), and thehook_capabilitieslist — the(event, matcher)pairs the runtime can actually fire.- A settings template (e.g.
src/adapters/claude/settings.template.json) is GENERATED fromsrc/core/hooks/registry.yamlbysrc/cli/hook_renderer.py. The renderer filters registry entries againsthook_capabilitiesso an adapter never claims coverage it cannot deliver. install.shis the consumer-side entry point. It must be idempotent and source-of-truth-compatible — running it twice on the same project produces no diff.
Steps to add a new adapter
- Create the adapter directory.
src/adapters/<id>/withadapter.yaml,install.sh, and the settings template stub. - Fill
adapter.yaml. Identity, paths, capabilities. The capability list is the most important field — every absent pair becomes silent coverage gap, not a hidden bug. Be honest about what the runtime supports. - Implement
install.sh. Symlink hooks fromsrc/core/hooks/into the consumer's<adapter-dir>/hooks/, render the settings file, write any agent-specific helpers (e.g. Claude's hooks expect Skill registration; Codex doesn't). - Add adapter SDK glue if needed. A formula-dispatcher implementation (
src/adapters/<id>/sdk_dispatcher.pymatching the protocol insrc/adapters/claude/sdk_dispatcher.py). Register it via the dispatcher factory insrc/core/thinking_os/cognition.py. P8 Adapter-SDK autonomy: the kernel must NOT import an adapter SDK directly. - Run the renderer.
make regen-adapter-templates. The first run produces a completesrc/adapters/<id>/settings.template.jsonwith only the events the adapter can deliver. - Write the parity test.
tests/test_adapter_parity.py— at minimum, assert the rendered template matches a golden snapshot attests/golden/<id>_base/. - Document the gaps. Update adapter-parity.md with the new adapter's coverage matrix and the architectural reasons for any missing pairs.
Steps to modify an existing adapter
- Locate the SSOT. SDK pin →
adapter.yamlorpyproject.toml. Hook coverage →hook_capabilitiesinadapter.yamlplussrc/core/hooks/registry.yaml. Settings shape →src/cli/hook_renderer.py. - Edit the SSOT. Never edit the generated artifact (
settings.template.json) directly. - Regenerate.
make regen-adapter-templates. - Update golden tests. Recapture with
make golden-capture(all sections, ormake golden-capture SECTION=<id>). Review the diff line by line — silent coverage shifts are real bugs. - Document migration. If consumers must take action, write a short note under
docs/adapters/<id>-migration-<date>.mdand link it from the adapter's main reference.
Acceptance
make regen-adapter-templatesis a no-op on a clean checkout.tests/test_adapter_parity.pyandtests/test_adapters.pypass.cos doctorreports the adapter as healthy in a freshly scaffolded project.- The adapter's
hook_capabilitieslist matches the agent's actual runtime (verified by reading the agent's hook spec, not by guessing). - No core code imports the adapter's SDK (P8 Adapter-SDK autonomy).
Rollback
Adapter changes are propagated through cos sync-all to existing projects. To roll back: revert the commit, regenerate templates, and ask consumers to re-run cos sync-all. If a consumer has already pulled the change and edited their local settings, the local edits survive — only the template is rewritten.
Anti-patterns
- Putting agent-specific imports inside
src/core/. P8 violation; refuse. - Hand-editing
settings.template.jsonto add a hook the registry doesn't know about. The next regen wipes it. - Declaring
hook_capabilitiesaspirationally — claiming a matcher the runtime doesn't fire. The renderer happily emits the entry, but it's dead weight in the consumer's settings. - Writing an
install.shthat mutates files outside<adapter-dir>/. Side effects must be confined to the adapter's directory and.coding-os/.