Over the past year, I built a memory and learning engine around my Claude Code repository.

A work session does not disappear when the chat closes. The current runtime preserves the raw transcript, normalizes its messages and tool calls, derives structural signals, and generates session-digest or content-seed candidates. Promotion into durable memory remains human-gated and capability-specific.

  • the transcript pipeline already feeds content seeds into the content engine;
  • the business judgment engine separately connects its own instrumented decisions to later outcomes;
  • the current Chief of Staff compares goals with kanban, PRD, and Git activity, while a memory-aware version remains future architecture;
  • retrieval already spans session history and durable patterns, but it does not yet consume the new canonical archive as one unified layer.

For most of the build, Claude Code was the primary work surface. I used Codex as a second set of eyes for plan review and implementation attacks, or to audit a claim. Sometimes Claude Code called the Codex CLI from inside its own workflow, but Claude remained the outer runtime whose hooks saw the lifecycle and closed the learning loop.

Recently, I started doing substantially more work directly in Codex. It became a separate primary harness where tasks begin, branch, use subagents, and end. A valuable decision made during a Codex-only session had to reach the same archive and learning system as one made in Claude Code.

It did not.

Both agents could read the repository, but Claude's lifecycle settings did not come with it. A good Codex session could end without entering the archive or content pipeline, leaving the future judgment, Chief-of-Staff, and unified-retrieval integrations with the same blind spot.

Claude hooks themselves do not execute inside Codex. Codex-native hooks have to call the same repository-owned behavior.

More execution surfaces can produce a worse memory

Claude sessions entered the transcript and content-learning path while standalone Codex sessions did not. That gave the system a distorted sample of my work. Retrieval quality would start depending on which logo happened to be above the chat.

The best harness will also keep changing. Claude Code may be the right environment for one workflow; Codex may be better for another. Gemini or a future harness may become useful for a third. I want to choose the execution surface based on the work without forcing the memory architecture to move with it.

A customer should not inherit a permanent Claude Code dependency because that happened to be the environment where I developed the first version. KnowledgeOS needs stable repository-owned contracts with adapters for whichever harness the customer uses.

A decision made in a Codex-only task had to enter the same archive, survive the same promotion gate, and remain available to either supported harness during later work.

Shared files were only the first layer

I had previously written: "All three consume the same instruction files, domain rules, and skills. The compounding is model-agnostic."

The shared-file claim was true. Claude Code and Codex could reach the same Markdown and structured data; Gemini could too. This implementation tested lifecycle parity between Claude Code and Codex, while Gemini remained outside the runtime audit.

Claude Code and Codex emit different transcript records and discover instructions differently. Their permissions use different configuration models. Even where both expose a "skill" or an "agent," the invocation signals are not equivalent.

Our skill architecture showed the ownership problem. The implementation lived under .claude/skills; .agents/skills pointed back into that directory. Codex could find the skill, but the repository still treated a Claude-shaped source tree as the authority.

Memory made the distinction consequential. Saving JSONL gives you evidence, not learning. A learning path has to preserve the raw source, derive a candidate without losing provenance, and prevent that candidate from changing durable memory until it passes a promotion gate.

We needed to make four layers portable:

  1. capture the native transcript and lifecycle event;
  2. normalize vendor-specific records into stable evidence;
  3. transform that evidence into attributable candidate learning;
  4. promote approved learning into memory that every harness can retrieve.

What we changed

While I work, the vendor transcript remains the L0 source of truth. When Codex or Claude Code emits Stop, a thin adapter passes the native payload into the shared capture runtime. The normalizer detects the transcript format and produces one message/tool record shape with the source, session ID, and raw-record position attached. Shared extractors derive file and skill signals from those records.

Stop writes a mutable checkpoint. Its idempotency key combines the harness and session identity with the lifecycle event and transcript fingerprint. If the same key arrives again in sequence, the checkpoint is reused and every completed turn still leaves a recoverable copy.

When the main task ends, SessionEnd finalizes an immutable content-addressed archive and appends provenance. The current Codex hook contract says this event runs when an open main task is archived or deleted, when Codex closes normally, or after 30 idle minutes with no connected client. It does not run for subagents. Codex caps the hook at three seconds, so the finalizer captures evidence and launches expensive model work outside the shutdown path.

In Victorious, the detached digest worker consumes canonical records rather than vendor JSONL. Provenance selects the provider: the existing Claude path can continue through claude -p, while a Codex-origin task can use an ephemeral read-only codex exec. Current digest output remains attributable to its source session, while the archive registry separately retains the transcript fingerprint. The learning-extension contract requires future capability ports to bind each derived candidate to the archive and prompt/schema version; no provider can overwrite promoted memory directly.

KnowledgeOS packages the same capture runtime and both lifecycle adapters. It also ships the memory-bundle and learning-extension contracts. A capability does not gain semantic learning merely because it can archive a transcript; it must supply a neutral prompt/schema and worker, then define its own promotion path.

There is one proof boundary I am keeping open. The Codex documentation now explicitly covers archiving an open task, but we have not yet captured the resulting SessionEnd artifact from an interactive desktop archive in this environment. The configuration and event contract are test-green.

What almost regressed

The neutral runtime could have broken Claude

The first refactor made existing Claude hook consumers import the neutral normalizer. It worked in the live tree because the new runtime files were present but untracked. A partial commit containing the modified hook without the runtime would have failed on Claude's next session.

Fable found that asymmetry, so we added guarded imports plus tested legacy-Claude parser and provider fallbacks. The neutral path is preferred, while an incomplete deployment still preserves the old Claude behavior.

Our first cross-harness skill detector treated slash-command prose and reads of SKILL.md as invocations. That fallback is useful when a harness lacks a native signal; in Claude it would have polluted the usage ledger. Claude now keeps its existing definition of a real invocation, while Codex uses the explicit evidence its transcript provides.

Neutralization removed behavior that was not vendor-specific

A shared record shape does not mean identical underlying events. Codex can mirror the same message through an event record and a response-item record with slightly different timestamps. Exact timestamp matching left duplicates. The fixture now varies timestamps and the normalizer collapses only the expected nearby cross-stream pair when role and text match.

The early deep-planning port removed Claude-specific language, but it also dropped durable plan locations and PRD sizing along with quality bars and phase checkpoints. Those details belonged to the repository method. They now live in the neutral capability source; each harness can add its own planning UI or delegation mechanics around them.

The worktree passed while the package was incomplete

The first neutrality audit undercounted legacy skill ownership because it inspected one frontmatter convention. Older adapters used another form and disappeared from the result. We changed the audit to use the same source resolver as the generator, and the inventory moved from 46 to 61 Claude-backed capabilities.

Then the live worktree passed while the deployable overlay omitted a learning-extension contract referenced by the package manifests. Fable caught the mismatch on its second review. We added the contract to an atomic staging manifest and tested a clean checkout containing only the files intended for the commit.

How we proved parity

The repaired runtime was implemented at internal commit 1004cc34. Internal PR #562 merged it into its exact-parent baseline branch as 154bcb1f; it is not yet canonical on main.

I did not treat parity as one pass/fail score. Each number closed a different way the port could appear healthy while still being incomplete.

Failure modeRelease evidenceWhat it established
Incomplete inventory46 → 61 legacy Claude sourcesThe original audit had hidden older adapter formats.
Broken adapter paths65 of 65 targets resolvedEvery live adapter target existed; this did not semantically execute all 65 capabilities.
Claude regression35 digest checks passedExisting Claude parsing and provider fallbacks remained intact.
Cross-harness behavior33 runtime and KnowledgeOS checks passedEquivalent Claude and Codex fixtures reached the shared contracts.
Incomplete release surface56 entries / 90 filesThe staging manifest resolved to exactly the intended commit boundary.

The order matters: correct what counts, resolve what ships, preserve the incumbent, then test the exact package—not the convenient worktree. Codex CLI 0.145.0 also passed strict configuration execution.

Claude Fable's first review returned a conditional result and found the partial-deploy risk. Its second review confirmed no Claude regression, then found the package contract missing from the staged surface. The final gate passed Claude preservation and cross-harness parity. Maintenance and commit readiness passed too.

Sequential repeated lifecycle delivery is deduplicated, and the content-addressed archive file is reused. The append-only provenance registry is not serialized against concurrent duplicate delivery; a crash between appending provenance and updating state can also duplicate a registry line.

Claude had become the operating constitution

Claude owned far more than the transcript hook. I had treated Claude Code as one execution surface sitting on top of my system. In practice, Claude's event model and configuration vocabulary had become the constitution of the system.

Shared policy lived in CLAUDE.md, while skills resolved from .claude/skills. The persistent content specialist kept its working memory under .claude/agents/memory. Permissions and end-of-session behavior were expressed as Claude settings. Even the Codex adapter for deep planning needed an explicit sentence saying it did not hand implementation authority back to Claude.

I had not planned the lock-in. Each useful behavior landed at the closest integration point until the integration point owned the method. Codex could read the data, but Claude still owned the operating method.

Fixing that meant separating policy from adapters instead of teaching every harness to impersonate Claude. AGENTS.md now owns shared rules; CLAUDE.md is the Claude-specific overlay. Codex retains a transitional CLAUDE.md fallback because some nested directories still carry unmigrated safety and context.

The capability registry now declares the real source behind each adapter. Deep planning is the first skill we moved: its method belongs to the repository, while each harness decides how it delegates. Sixty-one other skills still resolve through Claude-era sources.

The same boundary now governs specialists, memory, and permissions. The specialist definition and six-file memory schema are neutral, but the live content-writer bundle still sits on a legacy Claude path. The registry owns that binding until it can be moved cleanly. Permission adapters preserve the same approval and execution intent without pretending Claude tool rules and Codex approval or sandbox settings are the same mechanism.

KnowledgeOS now packages these contracts and both adapters, but that is not proof of a universal runtime.

Each learning-enabled capability still needs its own prompt/schema, worker, provenance binding, and promotion path. Each harness still has to map native lifecycle events and permission controls into the shared contract. Remove a vendor directory or swap an adapter, and the break tells you exactly where the vendor still owns the system.

A portability test you can actually fail

If I were auditing another agent system, I would run five tests:

  1. In a clean copy, make the vendor-named source directory unavailable and resolve every registered capability. Any failure reveals vendor ownership hiding behind an adapter.
  2. Replay equivalent native transcripts and compare canonical messages, tool calls, and derived signals. Preserve differences where the harnesses expose different evidence.
  3. Deliver the same lifecycle event twice. Check the mutable checkpoint, immutable archive, and provenance ledger separately.
  4. Trace one session through raw evidence, candidate learning, and promoted memory. Require provenance at every boundary and prove that a model adapter cannot promote its own output.
  5. Run incumbent regression tests and the exact staged package in a clean checkout. A dirty worktree is useful for development, not release proof.

One uppercase Claude permission template remains for installer compatibility, and 16 generated adapters have known drift. The provenance ledger also needs concurrent-delivery serialization.

This pass addressed portability and lifecycle integrity, not transcript governance. Retention windows, secret or PII redaction, encryption at rest, and repository access remain deployment decisions.

The current Codex contract says an interactive archive should run SessionEnd. I still want the receipt from this desktop: one archived task, its immutable archive hash, the matching provenance entry, and the detached digest. Until I have that artifact, the Stop checkpoint is the recovery path and a missed finalization still requires manual reconciliation.