Shared memory and skills across Claude Code and Codex
Project description
unified-agent-context (uac)
Shared memory and skills across Claude Code and Codex, so what one agent learns the other can use — across sessions, and across projects.
No API keys. Every model call happens inside the official CLIs under your own subscription login. This tool never talks to a model API and never reads either CLI's credentials.
Install
Install the uac CLI with pipx — isolated, and on your PATH:
pipx install unified-agent-context # the `uac` command
pipx install uac-tui # optional: the `uac-chat` terminal app
Or the one-liner (installs uv/pipx first if you don't have it):
curl -fsSL https://uac-ai.com/install.sh | bash # just `uac`
curl -fsSL https://uac-ai.com/install.sh | bash -s -- --chat # + `uac-chat`
You also need both agent CLIs installed and logged in with your subscriptions:
npm install -g @anthropic-ai/claude-code
npm install -g @openai/codex
claude # log in with your Claude subscription
codex # log in with your ChatGPT subscription
Install from source (for development)
uv venv
uv pip install -e ".[dev]"
Set up a project
cd /path/to/your-project
uac init
Scaffolds AGENTS.md + .agents/, creates the memory DB, generates CLAUDE.md and the native
Claude skill mirror, and registers the MCP server + hooks + tool permissions in both agents.
⚠️ Then do the three steps uac init can't do for you
Until you do these, both agents silently ignore everything uac init wrote. They are
security decisions, so uac won't automate them.
- Run
claudehere once and accept the trust prompt. Otherwise Claude drops the permission rule — "Ignoring 1 permissions.allow entry from .claude/settings.json: this workspace has not been trusted" — and then silently refuses everymemory_write. It looks like it's working. It isn't. - Run
codexhere once and accept the directory trust prompt. Otherwise: "Not inside a trusted directory." - Inside codex, run
/hooksand trust the uac hooks. Codex ignores wrapper-installed hooks until you approve them there (#21615). This one is not optional: without it the session-start hook never runs, Codex never learns the shared memory exists, and when you ask it something it will grep your files and tell you it found nothing. That is the observed behaviour, not a hypothetical.
Claude's escape hatch, if you want it: projects["/abs/path"].hasTrustDialogAccepted: true in
~/.claude.json.
Then fill in AGENTS.md — it's the source of truth.
How it works
Claude Code ─┐ ┌─ .agents/memory.db this project
├─ MCP (stdio) ─ uac ────┼─ ~/.agents/global.db everywhere
Codex ───────┘ ├─ linked projects read-only
├─ .agents/skills/*.md
└─ AGENTS.md
Six MCP tools: memory_write, memory_search, memory_forget, skill_list, skill_load,
project_context.
Two hooks do the work you'd otherwise have to remember:
- SessionStart injects
AGENTS.md+ the skills index + recent memories, so a session starts informed. - Stop blocks the first stop of a session and asks the agent to save anything durable via
memory_write. The agent's own model writes it — that's how we summarize without an API key.
The SessionStart hook is the load-bearing piece. Tested on a real project: without it, Codex
was asked about a fact sitting in shared memory and grepped the filesystem instead, reporting it
found nothing — even though AGENTS.md told it to use memory_search. With the hook trusted,
the same question in a fresh session got the right answer with no mention of any tool. Injecting
context beats hoping the agent decides to go looking for it.
Memories are written deliberately, not captured silently: a small, clean store instead of a noisy one that burns tokens and goes stale.
Memory
uac memory list
uac memory search "deploy" # this project + global + linked
uac memory add "Staging needs VPN" --kind gotcha --tags deploy,staging
uac memory add "I prefer tabs" --kind preference --scope global
uac memory forget <id>
kind is one of decision, fact, gotcha, preference. Every memory records its source
(claude-code / codex / human) so you can see which agent wrote what.
Skills
A skill is one markdown file in .agents/skills/:
---
name: deploy-runbook
description: Use when the user mentions deploying, releasing, or shipping.
---
# Deploy runbook
...
The description must say when to use it — that's what makes it trigger.
uac skills list
uac skills show deploy-runbook
uac sync # regenerate CLAUDE.md + .claude/skills/
uac sync --check # exit 1 if stale — wire this as a pre-commit hook
One source of truth, two adapters: Claude Code gets native skills in .claude/skills/; Codex
gets the same content via skill_load. Bodies load on demand — the always-in-context index
is names and descriptions only.
Using your Claude skills in Codex
uac skills import # copies ~/.claude/skills/* into .agents/skills/
Claude keeps using them natively; Codex can now load them with skill_load. They become the
project's copy — commit them, edit them for both agents.
Only Claude's user skills can be imported (the ones in ~/.claude/skills/). The skills
that ship inside the claude binary — deep-research, dataviz, verify, code-review,
simplify … — aren't files, so there's nothing to copy. Several of them are about Claude Code's
own features and would mean nothing to Codex anyway.
Cross-project memory
Reuse one project's memory in another. Links are explicit, read-only, and one-way:
uac link add shared-infra # this project now READS shared-infra's memories
uac link ls
uac link rm shared-infra
Results from a linked project are labelled with their origin, so the agent knows a fact came from somewhere else and can discount it. Your writes never touch the linked project.
Chat (experimental)
uac chat --agent claude-code # or codex
uac run codex "explain this repo"
uac review "add retry logic to the client" # Claude writes, Codex reviews the diff
Your prompt is forwarded to the agent's CLI as a subprocess and its event stream is rendered back. No API key — it drives the CLI you already pay for.
There's also a VS Code extension in extension/ (chat panel + agent picker):
cd extension && npm install && npm run compile
Then open the folder in VS Code and press F5 → "Unified Agent Context: Open Chat".
Both are unverified against the real CLIs. The flags and event shapes (
claude -p --output-format stream-json,codex exec --json) move often. Check--helpbefore trusting them. See "Status" below.
What uac init writes
| File | Purpose |
|---|---|
.mcp.json |
Claude Code: MCP server, UAC_SOURCE=claude-code |
.claude/settings.json |
Claude Code: SessionStart + Stop hooks |
.claude/skills/ |
generated native skill mirror |
.codex/config.toml |
Codex: MCP server, UAC_SOURCE=codex |
.codex/hooks.json |
Codex: SessionStart + Stop hooks |
CLAUDE.md |
generated — @AGENTS.md + Claude extras |
.agents/config.toml |
your settings |
~/.agents/registry.toml |
makes this project linkable by name |
Re-running is idempotent and won't touch your own hooks or servers. uac refuses to overwrite
a hand-written CLAUDE.md.
Attribution works because each agent spawns its own stdio server process, so UAC_SOURCE is
set per agent. (This breaks under a single shared --http server — stdio only for now.)
Settings
.agents/config.toml:
[memory]
scope = "project" # "project" | "global"
max_results = 5
[links]
read = ["shared-infra"] # read-only, one-way
[claude]
extra = "- Use /self-review before PRs" # appended to generated CLAUDE.md
[hooks]
inject_context_on_start = true
flush_memory_on_end = true
claude_auto_memory = "ours" # "ours" | "native"
Claude ships its own Auto Memory. Running both can double-write. Set
claude_auto_memory = "native" to leave Claude's side alone (Codex is unaffected).
UAC_HOME overrides ~/.agents (used by the tests).
Status
Tested against Claude Code 2.1.210 and Codex 0.144.4, both live on a real project.
| Phase | State |
|---|---|
| 1 — memory + hooks | built. Real Claude calls mcp__uac__memory_write unprompted; real Codex calls memory_search unprompted and gets results; the Stop hook nudge fires for real |
| 2 — skills | built, verified from both agents over real MCP |
| 3 — cross-project links | built, verified |
| 4 — chat CLI + VS Code extension | built. All flags + event shapes confirmed against the real CLIs; VS Code UI itself unexercised |
5 — uac review |
built, unverified |
Known limitation: headless Codex can read, not write
codex exec auto-cancels MCP tool calls that aren't advertised read-only — a known upstream
bug (#16685,
#24135) whose only official workaround is
--dangerously-bypass-approvals-and-sandbox. We don't use that.
Instead our read tools are annotated readOnlyHint: true, which passes Codex's gate cleanly.
So:
memory_search/skill_list/skill_load/project_contextwork in headless Codex ✅memory_write/memory_forgetare cancelled in headless Codex ❌ — they work in an interactivecodexsession, where you approve them.
We annotate honestly (memory_write is not read-only; memory_forget is destructive) rather
than mislabel a write to slip past an approval gate.
Still to prove: the full round trip with interactive Codex.
Phase 0 was skipped. Nobody has yet confirmed, by living with it, that plain AGENTS.md +
an existing tool (agentmemory) isn't already enough. See project.md §8.
project.md §9a records everything that testing against the real CLIs changed — including two
real bugs (Codex hanging on stdin; MCP tools being permission-gated) and the trust gate.
The test that matters
Save a memory in Claude Code, then open Codex in the same project and ask what it knows. If that handoff doesn't work, nothing else here matters.
pytest # 103 tests
cd extension && npx tsc -p . --noEmit
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file unified_agent_context-0.1.1.tar.gz.
File metadata
- Download URL: unified_agent_context-0.1.1.tar.gz
- Upload date:
- Size: 103.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
adbe5a668f6b5f1ca45505ff9490c981982a586372d02fe5a23756ecb94ed3b7
|
|
| MD5 |
55ac916b89343d61ca542c6fdec6bc22
|
|
| BLAKE2b-256 |
d472f47bbfe7f8434ce959a7f97f481750160cb09d3039b9e611f7c0b15900b2
|
File details
Details for the file unified_agent_context-0.1.1-py3-none-any.whl.
File metadata
- Download URL: unified_agent_context-0.1.1-py3-none-any.whl
- Upload date:
- Size: 35.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
10f4fc52283654ca5082d7bf7c0cf069cfd42d1339f6db82bc8c35a1175d52a6
|
|
| MD5 |
2e389b5f53c22ce65afead136319e4fe
|
|
| BLAKE2b-256 |
c2bab9fd6b82efe6316d00613b2dc7eb88ed22eb63c71f4b2671081a67cfd432
|