Retrieved article excerpt
Open article ยท Retrieved 2026-09-22T21:23:06.614459+00:00
# Strata
Strata gives a fleet of AI coding agents shared memory. Agents working the
same project write what they learn to a scope and read what other agents
already wrote โ and every write is checked by an LLM judge before it lands,
so one agent's mistake never corrupts what the rest of the fleet reads.
## Core concepts
- **Fleet** โ the whole set of scopes and agents sharing one Strata memory.
- **Scope** โ one node agents bind to and read/write; scopes are grouped
into ordered strata (e.g. architecture โ backend โ tests).
- **Contribution** โ one write to a scope: a proposed directive (binding) or
context (non-binding).
- **Judge** โ the LLM that reviews every contribution and decides whether,
and how, it's admitted.
- **Record** โ the append-only audit trail of everything ever contributed
and judged, per scope.
Scoping โ which memory an agent binds to and reads/writes โ is a
discipline boundary for well-behaved agents, not a security boundary; a
harness sandbox's own file-access rules are the enforcement layer against
an adversarial agent.
For the full theory and vocabulary, see
[`docs/philosophy.md`](https://github.com/oren198/Strata/blob/main/docs/philosophy.md) (why Strata exists, why naive
sharing fails) and [`CONTEXT.md`](https://github.com/oren198/Strata/blob/main/CONTEXT.md) (the canonical glossary
every part of the codebase uses โ 23 terms, no synonyms).
---
## Install and run
```
pipx install strata-mem # strata + strata-mcp on PATH, in an isolated env
cd your-project
strata register # wires memory into this project
```
`strata` is a local-first Python service: SQLite + markdown storage, an
embedded MCP mode that needs no backend running, file-canonical
`fleet.yaml`, and an optional read-only browser Console. The
[Quick start](https://github.com/oren198/Strata#quick-start-two-agents-one-memory) below is the one supported
first run; everything deeper โ architecture decisions, the Console UI, upgrade
notes โ lives under `docs/` and is linked from the relevant section.
---
## Quick start: two agents, one memory
The first run this release is built around: **two terminals on one machine, a
Claude Code session and a Codex session bound to the same scope.** One session
learns something and writes it back; the judge admits or declines it, with a
reason you can read; the other session acts on it next time. You can see what
the fleet believes, where each belief came from, and what was kept out.
The engine is embedded โ the MCP server applies migrations and opens storage
itself on first use, so nothing needs to run in the background. `strata start`
exists for one reason, the **Console** (step 7); agents never depend on it.
### 1. Prerequisites
- **Python 3.11 or newer** (`strata-mem` declares `requires-python >=3.11`).
Check: `python3 --version`. On an older interpreter the install refuses rather
than half-installing โ checked on Python 3.10.12: `pip install` stops with
`ERROR: Package 'strata-mem' requires a different Python: 3.10.12 not in '>=3.11'`, and `pipx install --python <3.10 interpreter>` stops with "The Python
you named does not satisfy '>=3.11'". pipx builds the isolated env from the
interpreter pipx itself runs on, so that is the one that must be 3.11+. No
Python 3.11+? See
[No Python 3.11+ globally?](https://github.com/oren198/Strata#no-python-311-globally-use---bootstrap-venv).
- **Claude Code and Codex CLI**, both installed and logged in (`claude` and
`codex` on your `PATH`). The register step below wires whichever it finds; this
quickstart wires both.
- **A judge API key.** The judge is an LLM you point at any endpoint that speaks
the Anthropic Messages API โ get an Anthropic key at
<https://console.anthropic.com/>, or use a router/proxy/self-hosted gateway
that speaks that API (see [Environment variables](https://github.com/oren198/Strata#environment-variables)).
### 2. Install
```
pipx install strata-mem # strata + strata-mcp on PATH, in an isolated env
```
`pipx` is the supported install. `pip install strata-mem` inside a Python 3.11+
virtualenv also gives you working `strata` and `strata-mcp` commands (checked with
`python3.11 -m venv` + `pip install`); then run `strata` from that environment, or
put its `bin/` on `PATH`, because the registered hooks call bare `strata`. `uv` was
not checked, so nothing is claimed for it. If another `strata` is already on your
`PATH` (an older pipx install, say), see [Troubleshooting](https://github.com/oren198/Strata#troubleshooting).
### 3. Register โ wiring both harnesses
```
mkdir strata-demo && cd strata-demo
git init # a project root needs a marker (.git, pyproject.toml, ...)
strata register --harness claude-code --harness codex
```
`strata register` is idempotent and strictly additive. With those flags it wires
both harnesses whether or not it can detect them (without flags it wires every
harness it finds). It creates `.strata/` (config, a one-scope `fleet.yaml`, the
database directory), appends a `# Strata` block to `.gitignore`, and then:
- **Claude Code:** copies the Strata skills into `.claude/skills/`, adds the
`strata` server to `.mcp.json`, and installs the freshness `Stop` hook under
`.claude/`.
- **Codex:** merges the `strata` MCP server and the same `Stop` hook into Codex's
own config, `$CODEX_HOME/config.toml` (default `~/.codex/config.toml` โ a
machine-level file, not a per-project one), and seeds this project's
`AGENTS.md` with a short memory-moves block.
Strict mode is on by default โ a session that read fleet memory and wrote nothing back is reminded at its end to contribute or close out (at most twice) โ and `strata register --no-strict` turns it off.
In an interactive terminal `strata register` also asks what the first scope's memory is for (one line; Enter skips it). Scripts pass `--description "..."`; a non-interactive run never asks. It is written to `fleet.yaml` as the scope's `description:`.
See [What `strata register` does](https://github.com/oren198/Strata#what-strata-register-does) for the full list.
### 4. Set your judge API key
The default judge is `qwen/qwen3-235b-a22b-2507` on OpenRouter, so the key is an
**OpenRouter key** ([openrouter.ai/keys](https://openrouter.ai/keys)). To judge with
Anthropic instead, use an Anthropic key โ see [Choosing a judge](https://github.com/oren198/Strata#choosing-a-judge).
Put it in a `.env` file at the project root. `strata register` already adds `.env`
to `.gitignore`, and every entry point (the MCP server, the CLI and the Console
backend) loads it:
```
JUDGE_API_KEY=sk-or-...
```
`strata register` offers to capture the key for you and writes `JUDGE_MODEL` and
`JUDGE_BASE_URL` beside it, so the `.env` states which judge the key is for.
**With Codex, use the `.env` file, not an export.** Codex starts its MCP server with
only the `[mcp_servers.strata.env]` table from its own config, not your shell's
environment, so an exported key never reaches it and Codex's contributions go
unjudged. The project `.env` is how the key reaches Codex's server. For Claude Code
alone, `export JUDGE_API_KEY=sk-...` in the shell you launch it from also works.
(The older `ANTHROPIC_API_KEY` / `STRATA_ANTHROPIC_API_KEY` names still work as a
deprecated fallback โ see [Environment variables](https://github.com/oren198/Strata#environment-variables).)
Without a key, reads work, but a contribution is recorded with **no verdict**: the
tool returns an error saying the scope-manager cannot judge without a key, and the
contribution shows in `strata record` as "judge errored". Once a key is set (restart
the harness so the server sees it), `strata_rejudge` gives it its verdict.
### 5. The fleet: keep the one scope
`.strata/fleet.yaml` is seeded with one scope, `g_root`. Keep it: one scope is a
complete, working setup, and it is what both terminals bind to. With exactly one
scope, an unset `STRATA_AGENT_SCOPE` auto-binds to it, so **you export nothing**
for either harness. Grow the fleet later, when real roles emerge (edit
`.strata/fleet.yaml` and validate with `strata bootstrap`, or edit it in the
Console); binding becomes an explicit choice once there are two or more scopes โ
see [Binding past one scope](https://github.com/oren198/Strata#binding-past-one-scope).
Give each scope a one-line `description:` in `fleet.yaml` โ what its memory is for.
The judge measures relevance against it: material "outside this scope's stated
purpose" is declined, and the decline reason quotes the purpose. Without a
description the judge may use what the scope already holds as an implied purpose,
but only once there is enough of it to tell what the scope is about (about 50 words
of summary and directives; `STRATA_IMPLIED_PURPOSE_MIN_WORDS`); a scope with an
empty summary is judged exactly as before, with no relevance rule at all. `strata doctor` warns once per scope that has no description, and the Console shows it in
the scope header ("no description" when unset).
### 6. Two terminals, same project
**Terminal 1 โ Claude Code**
```
cd strata-demo
claude
```
What to expect the first time in Claude Code (verified on Claude Code 2.1.278):
- It asks whether you **trust this folder** โ choose *Yes, I trust this folder*
(the highlighted default is *No, exit*).
- It then reports **"New MCP server found in this project: strata"**. **The
highlighted default is *Continue without using this MCP server*. Pick *Use this
MCP server* (or *Use this and all future MCP servers in this project*) instead:
accepting the default gives you a memory-blind session with no Strata tools.**
**Terminal 2 โ Codex**
```
cd strata-demo
codex
```
What to expect the first time in Codex (all verified on codex-cli 0.153.4):
- Codex asks whether to **trust the directory** โ continue.
- It then shows **"Hooks need review"** for the Strata `Stop` hook. Choose
**Trust all and continue**. Codex does not run a hook until it is trusted; until
then (and always under `codex exec`) the turn-end reminder never fires. The
trust is remembered.
- **Leave `STRATA_AGENT_SESSION_ID` blank** in Codex's config (register ships it
blank). Each Codex session gets its own id automatically, and the hook lands on
the same id as the MCP server; exporting a value would reach the hook but not the
server and split one session in two.
- **Set `default_tools_approval_mode = "approve"` under `[mcp_servers.strata]` in
`~/.codex/config.toml` (or answer every per-tool prompt with *Allow*). Under
`codex exec` an MCP call that is not approved is refused, so without this
`codex exec` gets no Strata tools; in the interactive `codex`, cancelling the
prompts does the same. Either way that is a memory-blind session.** The
interactive prompts are *Allow*, *Allow for this session*, *Always allow* or
*Cancel*; "Always allow" is remembered per tool, so each Strata tool asks once,
and the config key covers all of them at once.
Codex's `workspace-write` sandbox mounts `.git/refs` read-only, so a Codex session
cannot create git tags or refs itself (observed on codex-cli 0.153.4 under `codex exec -s workspace-write`: `git tag` failed inside the sandbox). Have another session, or
you, do the tagging.
In Claude Code the session-start hook tells the agent to read its perspective
first; in Codex the seeded `AGENTS.md` does. In both, the agent has these tools:
`strata_read_perspective`, `strata_contribute`, `strata_session_closeout`, and
their read-only siblings.
A way to run the demo: in terminal 1, ask Claude Code to read the perspective,
then state one decision or lesson worth keeping and contribute it. Watch the
judge's verdict come back. Then, in terminal 2, start a Codex session and ask it
about that topic โ it reads the same scope.
### 7. See what the fleet believes
From the project directory:
```
strata stats writeback # write-back rate by harness: who contributed, who closed out, who stayed silent
strata summ