Interoperability: OKF, providers and the configurator¶
OKF conformance¶
Every KB is a conformant OKF v0.1 bundle and a git repository in its own right. Any external OKF tool can consume it without modification. Everything is git + files: history, diff, backup, sharing, zero lock-in. The skills (SKILL.md agentskills.io) and secrets (SOPS) are likewise open, portable standards.
Obsidian is the human viewer (graph view, Dataview), conceptually read-only.
Hard rules vs soft guidance¶
- Hard rules → server: path/layout validation, strict-map type palettes, optimistic writes and git serialization. Agents use MCP tools instead of editing KB files directly.
- Soft guidance →
instructionsprovisioning (D56/D61, no longer anAGENTS.mdin the KB — removed by D62): a generated block injected into each provider's global instructions file (.claude/CLAUDE.md,.config/opencode/AGENTS.md,.codex/AGENTS.md, Kiro steering,.gemini/GEMINI.md), plus the optional curatedinstructions.mdin the KB root (D61) and the auto-generated agent section — seesync.md§Instructions.
The MCP + skill + hook triad¶
| Level | What it does | Token cost |
|---|---|---|
| MCP | Data and capabilities (bounded reads, structured frontmatter queries, search, validated writes) | Proportional to the content read |
| Skill | Competence/procedure (how to do ingest/query/lint), loaded on-demand | ~100 tokens catalog; body on-demand |
| Hook | Deterministic client-side automation distributed by the KB | No model cost unless the hook invokes an agent |
Multi-provider configurator¶
A dedicated tool (the cartographer client subcommands — agents/connect/status/sync,
see docs/configurator.md) configures skills, MCP, hooks (and references to services/secrets) on
each provider leveraging its capabilities to the fullest — no least-common-denominator. The
client always talks to the server over HTTP (no stdio transport on the client
side, D37).
Single source-of-truth → per-provider adapter: the source is the provisioning manifest generated by the server (compiled bundle + artifacts of the mounted KBs — skills, agents, hooks, instructions); a per-provider adapter (internal/configurator for the MCP config, internal/provisioning.Apply for materialization) translates each artifact into the native constructs, discarding what cannot be reliably mapped instead of guessing it. The full kind×provider matrix is in sync.md §Kind × provider matrix.
TUI: interactive dashboard (cartographer with no arguments): autodetects installed providers, per-provider status with per-kind counts, connect/resync/disconnect — see configurator.md §TUI mode.
Idempotent and non-destructive sync: deep-merge for JSON; marker-delimited blocks for TOML and instruction files; never overwrite the user's contracts or secrets; dry-run.
Automatic realignment when skills/agents/hooks change (bundle or KB): manifest+revision server-side, lockfile client-side, drift detection and layered triggers (SessionStart hook, MCP tool, push). See → sync.md.
Secrets and local commands: MCP descriptors may name environment variables in provider-native syntax, but Cartographer does not distribute or resolve their values. A trusted stdio descriptor configures a provider to run a locally preflighted executable; Cartographer never launches it during provisioning. Runtime secret injection remains an operator responsibility.
Provider behavior¶
Provider formats change independently of Cartographer, so this page does not duplicate a dated market-wide capability matrix. The maintained sources are:
- configurator — exact files Cartographer reads and writes;
- synchronization — the
kind × providermaterialization matrix, translation losses, trust and pruning; - tests under
internal/configuratorandinternal/provisioning— executable compatibility contract.
Known divergences from the documented path (D192)¶
Two destinations differ from the path the provider's own documentation
currently presents as canonical. Both were proven working against the real
client, so neither is a fault today — but both can break on a client release,
which is why internal/provisioning/clientcompat_test.go asserts the declared
destination against the client's own discovery output on a machine that has the
client installed (and skips where it does not).
| Kind × provider | Cartographer writes | Provider documents | Last verified |
|---|---|---|---|
skill × codex |
~/.codex/skills/<name>/ |
$HOME/.agents/skills (source) |
client 0.153.4 |
agent × opencode |
~/.opencode/agent/<name>.md |
.opencode/agents (source) |
client 1.18.20 |
Neither is moved here: a destination change is a migration (prune the old
files, re-key the lockfile), and what was missing was the alarm, not the move.
The Codex case is now half-resolved: the workspace scope (D193) does use the
repository path the vendor documents, .agents/skills/<name>/, because that
scope is new and has no installed base to migrate. The global cell stays at
~/.codex/skills/ for the reason above.
Current limitations are documented once in the relevant table/section rather than repeated here. In particular, Kiro's flat MCP tool namespace may require the server's per-KB tool prefix, and provider translations intentionally drop fields that cannot be represented safely.
Project-local scopes as an external contract (D193)¶
The workspace scope writes into each provider's project-local configuration,
which is a second set of external contracts, verified during the D193 audit and
changing outside this project's release cycle. Re-verify before changing a cell;
the citation lives next to it in internal/provisioning/workspacescope.go.
| Provider | Project-local scope | Source |
|---|---|---|
| Claude Code | .claude/skills/, .claude/agents/, .claude/hooks/, .mcp.json, ./CLAUDE.md |
skills, memory, sub-agents, hooks, mcp |
| Codex | .agents/skills, .codex/agents, .codex/hooks, .codex/config.toml, AGENTS.md |
skills, subagents, hooks, mcp |
| Kiro | .kiro/skills/, .kiro/agents/, .kiro/steering/, .kiro/settings/mcp.json |
skills, custom agents |
| OpenCode | .opencode/skills, .opencode/agent, .opencode/hooks, opencode.json, AGENTS.md |
skills, rules, agents, plugins |
| Hermes | none | its configuration is rendered by its own Ansible role and skills go to one inbox (D141) |
| Antigravity | none | only a global configuration root is documented (D194) |
Two consequences are worth stating plainly. Kiro receives subagents in both
scopes since D195 but keeps an
unsupported hook cell, because the shipped client has no hook mechanism at
all. And Codex ignores a
project's .codex/ layer unless the project is trusted, which is the one
case where writing the files correctly is not the same as the projection being
active: status and doctor report it as inactive rather than installed.
Kiro hooks: documented, not shipped (D195)¶
Kiro's documentation describes standalone hooks — .kiro/hooks/*.json with a
"version": "v1" schema, and ~/.kiro/hooks/ firing in every workspace. The
shipped client does not implement them. Verified on Kiro CLI 2.21.3,
2026-09-11:
- a hook in
~/.kiro/hooks/and in the workspace's.kiro/hooks/, with each ofAgentSpawn,SessionStart,PromptSubmit,UserPromptSubmitandPreToolUse, never fires — in a session that completes normally, with--v3; - the agent log never mentions hooks, the config
kiro-cli agent createwrites has nohookskey, and the shipped agent binary contains no.kiro/hookspath (it does contain.kiro/agents,.kiro/skills,.kiro/steering).
The reason is in the vendor's own text: the v1 hook format was "introduced in
IDE 1.0 and CLI 3.0", and the CLI changelog
puts 3.0 in early access with 2.21.x on the release channel. kiro-cli --v3
launches the next-generation agent, which is not the same thing as CLI 3.0.
The documentation also contradicts itself on the trigger names: the
migration page lists
SessionStart among the CLI triggers, while the
feature page marks SessionStart as IDE-only and
AgentSpawn as CLI-only. D140 recorded the same pattern against 2.20.0.
So Kiro's hook cell stays unsupported and its re-sync trigger stays the
scheduled timer. Re-check when CLI 3.0 reaches the release channel.
Instruction slots Cartographer deliberately does not write¶
Leveraging a provider to the fullest also means declining to write where the write would not survive, or would destroy what another owner maintains. Two Hermes slots are unsupported for that reason (D141), not for lack of a mapping:
SOUL.md, its always-on instruction slot — operator-owned and rendered from a template by an Ansible role, so a managed block written there is gone on the next playbook run. The imprinting that reaches every other provider as akind: instructionsblock simply does not reach Hermes;-
config.yaml, its MCP endpoint list — rendered by the same role, for the same reason.connect hermestherefore configures no MCP entry and says so. -
$HERMES_HOME/skills/is a third: not an instruction slot but the agent's own curated skill store, rewritten by its curator from its learning loop. Cartographer delivers proposals toskill-inbox/<name>/cartographer/and the agent adopts what it chooses — seesync.md§Hermes.