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; the KB carries noAGENTS.md, 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,.config/crush/CRUSH.md,.copilot/copilot-instructions.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 talks to the server over HTTP (D37); the MCP entry it writes for a provider with a
workspace binding is the local stdio bridge cartographer mcp --provider <name>, which
proxies the session to the server
(D737).
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; - harness ledger — per client, the version last aligned with, where its changes are announced and which cells depend on it;
- tests under
internal/configuratorandinternal/provisioning— executable compatibility contract.
Known divergences from the documented path (D192)¶
One destination differs from the path the provider's own documentation
currently presents as canonical. It was proven working against the real
client, so it is not a fault today — but it 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) |
the version in the harness ledger |
The global cell is not moved: a destination change is a migration (the
lockfile-driven relocation of D360 does it), and what the cell needs is the alarm.
The workspace scope (D193) uses the repository path the vendor documents,
.agents/skills/<name>/, because that scope has no installed base to migrate. The
OpenCode global cells (~/.config/opencode/{skills,agents}/) are asserted against
opencode debug paths (D360).
Current limitations are documented once in the relevant table/section rather than repeated here. In particular, 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/hooks.json, .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 |
| Antigravity | .agents/skills, .agents/agents, .agents/hooks, .agents/hooks.json, .agents/mcp_config.json, AGENTS.md |
probed on the real client (D364) |
| Crush | .crush/skills, .crush/hooks, .crush.json (mcp, hooks) |
agents and instructions unsupported (D363) |
| Copilot CLI | AGENTS.md, .agents/skills |
the project mcp, agent and hook locations are gated on folder trust (D676) |
A subagent's tools allow-list is enforced by Claude Code only. The other
clients receive the agent without it, and therefore with every tool that client
has; each sync warns per agent, and strict_tools: true in the agent's
frontmatter skips it on those clients instead
(D283).
An agent can instead carry each client's own restriction in a providers: frontmatter
block (opencode, codex, kiro, antigravity, copilot), copied verbatim into that client's native
agent file; a client with an entry is not widened, so it is neither warned about nor skipped
(D291). Cartographer
does not infer the syntax, and which native keys each client honours has not been verified
against the real clients: the author writes them and owns their correctness.
Two consequences are worth stating plainly. Kiro receives subagents in both
scopes since D195,
and hooks only in the global scope, where they fire in one session mode
(D300, below). 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, and
workspace bind codex <path> --kb … --trust records the trust on request (D1074).
Kiro hooks: one session mode (D300)¶
Kiro has hooks on every engine, but a hook Cartographer can own fires in only one of its session modes. Probed on Kiro CLI 2.26.1 and 2.27.0 (macOS, the real binary, an unrelated temp dir, a sentinel file per hook):
| Session | Standalone ~/.kiro/hooks/*.json |
hooks inside an agent config |
|---|---|---|
kiro-cli chat interactive (the default; since 2.27.0 a new TUI over the v2 engine) |
does not fire | fires (agentSpawn) |
kiro-cli chat --no-interactive |
does not fire | fires |
kiro-cli chat --v3 --tui |
fires (SessionStart, UserPromptSubmit, Stop) |
fires |
--v3 / --agent-engine v3, non-interactive |
does not fire: the engine builds its hook cache only when the ACP client asks for hooks | — |
What this means for Cartographer:
- The registration is a standalone file Cartographer owns whole,
~/.kiro/hooks/cartographer.json({"version": "v1", "hooks": [...]}), with the hooks' files one level below it. The loader reads only the*.jsonfiles directly in~/.kiro/hooks/: it does not recurse, and a hook file in a subdirectory was not loaded. The scripts are therefore never read as hook files themselves. The workspace.kiro/hooks/fires in the same mode as the global one, so it adds nothing and staysunsupported. - No agent config is written for a hook. An agent's own hooks fire in every
mode, but only for that agent. The user's agent is theirs. Shadowing the
built-in
kiro_default(it can be shadowed in v2 since 2.26.1) would replace its prompt and tools, which is the intrusion D140 refused. A Cartographer-owned agent made the default withchat.defaultAgentwould not behave like the default either: an agent with notoolskey gets no tools (/tools: "No tools available", against 14 forkiro_default), and the default's prompt is compiled into the binary, so it would have to be copied from a moving target. - The scheduled timer stays Kiro's trigger for every session but
--v3 --tui.connect,statusanddoctorsay so, andstatusqualifies the hook count (hook 1/1 (fires in kiro-cli chat --v3 --tui only)).
Kiro IDE (workspace .kiro/hooks/<id>.json is documented, a global directory
is not) and Kiro Crew (~/.kiro/crew/hooks/ is documented) were not installed
on the probing machine, so no cell claims them.