One Rule, Many Doors
The rule for every harness is the same sentence: load identity through soul-vault bootstrap, and on failure stop and report the named cause. What differs is the door each harness offers for getting text in front of the model before the first turn. Soul Vault does not pretend those doors are the same. Each harness gets an adapter shaped to its own hook contract, and each adapter is a thin projection of the same client output: no adapter copies identity prose, and none keeps its own cache.
Claude Code: a SessionStart Hook
The simplest case. Claude Code runs a SessionStart hook and gives its output to the model as context. The hook runs soul-vault bootstrap --harness claude-code --hook; the card or the refusal arrives as the first thing the session sees. The family's global protocol adds the belt to those braces: a session that did not see a card must run the bootstrap itself before anything else.
Grok Build: a Rule File and a Gate
Grok Build is the instructive case, because its obvious door does not work. Grok ignores the standard output of a SessionStart hook, and it reads its home-level rule files before SessionStart runs. So the adapter has two parts:
- The session-start hook writes a rule file. It runs bootstrap and writes the card, or the refusal, into
~/.grok/rules/aa-soul-vault-identity.md. Grok injects that file into the next session. The hook always rewrites the file: a failure never leaves an older good card behind, which would let a broken setup keep looking healthy. - A prompt gate closes the one-session window. Because the card in the rule file can be one session old, a
UserPromptSubmithook runs bootstrap again on every prompt. If identity cannot load now, it prints the refusal and exits 2, which blocks the prompt. The hook is configured fail-closed, so a gate that crashes or times out also blocks.
Between the two, Grok's worst case is a session holding the previous session's card, and the content-addressed bundle name from the last lesson keeps even that on exact bytes.
Kimi Code: Context on Every Prompt
Kimi's SessionStart cannot deliver model context or block a model call. Its UserPromptSubmit event can: plain standard output becomes prompt context, and exit 2 blocks the turn. The Kimi adapter runs bootstrap on every prompt and supplies the card, fresh each time, so there is no copy or session cache to drift after a context compaction or a vault change. It supplies the card rather than the whole bundle on purpose: Kimi displays hook output in the terminal, and passing the entire bundle there displayed every note on every turn. The client's own deadline (20 seconds) sits inside Kimi's hook deadline (25 seconds), because Kimi treats a hook that times out as fail-open.
Cursor: Additional Context and a Submit Gate
Cursor's native user hooks project the card into its top-level additional context at session start. A session-start response alone cannot block a turn, so a separate beforeSubmitPrompt invocation returns continue: false with the named refusal when identity cannot load. This adapter is the answer to the kind of red the baseline found in track 1: Cursor's agent in a neutral directory never read the home rule folder, while a user hook runs whether or not the workspace has project rules.
The Pattern Underneath
Every adapter answers the same three questions for its harness: how does text reach the model before the first answer, how is a turn blocked when identity fails, and what happens when the hook itself crashes or times out. Where a harness fails open, an adapter adds a gate or keeps its deadline inside the harness's. And each adapter is proven by a real session, not by reading its config: the identity probe in track 8 runs a fresh session through every one of them.