sphica
v0.6.69
Published
Records Claude Code and Codex sessions on your machine and keeps past implementation and decisions, with their sources, for your agent to find.
Maintainers
Readme
Sphica
Local memory of past implementation and decisions for Claude Code and Codex.
English | 日本語
Sphica records your coding sessions, and keeps what was decided, rejected, deferred, and built, each record quoting the words it came from.
Your agent finds those records when it searches, and sees the relevant ones on its own when it reads or edits a file they apply to (in Codex, before a shell command that names the file and before apply_patch).
The database is a single SQLite file on your machine.
What the badges cover: how each release is built and published is in Security. A badge does not mean the code is free of bugs or vulnerabilities.
Features
- Automatic recording. Sphica keeps your prompts, the agent's final reply for each turn, and the paths of the files a turn changed (by the edit tools, or seen in
git statusat the turn's end). - Records with their sources.
/sphica:traceturns a session into records: decisions with the options rejected and why, constraints, implementations, findings, dead ends, and open questions. Every record quotes the exact words it came from. A decision counts as adopted in two ways: you said so (your decision), or the agent decided it itself in that session and its reply says so (an AI's decision). An AI's decision is shown as one, never replaces yours, and is never used for public interfaces, security and permissions, releases, or forgetting. - Shown when it matters. At session start, the current work; before the agent reads or edits a file, or runs a shell command that names it, the decisions tied to that file; when your prompt names a recorded option or code symbol, that record. An AI's decision is marked as one, with a note that the agent may depart from it for a stated reason.
- Find what you asked before. Ask the agent whether you asked something like this before:
searchwithasked: trueshows your earlier messages in other sessions, the records that quote them (with what replaced them), and says "no recorded decision" when none was recorded, including a matter you raised in several sessions. - Forget what should not have been kept.
/sphica:forgetremoves the messages, pull request items, or file excerpts you pick, with their search entries and the bytes left in the database file, after you confirm in a dialog. Records that cited them are judged again and leave active when nothing else supports them; a record's own text stays as it was.
Records are never rewritten: a correction is a new record that supersedes the old one, and the history stays. The agent is told to treat records as history, not instructions, and to trust the code when a record and the current code disagree.
More features
- Traced without asking. When you start a new session (an interactive one in Claude Code; one started from the terminal in Codex) and sessions from the last 14 days wait to be traced, the agent is asked to trace up to two of them, oldest first, after your request is done. Run
/sphica:traceyourself to keep something right away, and/sphica:trace pendingfor older sessions. To turn the automatic trace off, see Settings; recording and your own/sphica:tracekeep working. - Pull requests too.
/sphica:harvest <number>keeps a GitHub pull request (body, comments, reviews, review comments, commits, and up to five issues the body says it closes) and records what it decided. A reviewer's suggestion stays a proposal unless the owner or a maintainer adopted it; a merge alone adopts nothing. - Evidence found later.
/sphica:gleanadds evidence and corrections to existing records. It asks you for the source (an issue URL, the file and line, meeting notes) before saving; a claim without one is kept only as unsourced and never used as fact. - A command that failed before is stopped once. When a dead end is recorded with the command it is about (such as
pnpm test --watch), the first shell call in a conversation that runs that command is stopped, with the dead end as the reason. The agent checks the record and takes another way, or runs the call again, which then goes through. - Search in Japanese and English. Records are made with search words in both languages, so a question in either language is more likely to find them.
- See how a decision changed, and what held at a past time. Ask the agent how a decision came to be:
readwithtimeline: trueshows the decisions it replaced or was replaced by, when each change took effect and why, and the findings, dead ends, and questions saved by the same trace or harvest or tied to the same code, oldest first. Ask what was decided as of a time:searchwithas_of(a time with its offset, such as2026-10-01T09:00:00+09:00) searches the records as Sphica held them then, by the states and replacements of that time, and names apart the ones saved later that match now (oldest first, up to ten, then a count). The time is when Sphica saved a record, not when the words were said, so a session traced late or a pull request harvested late counts from the day it was saved. - See what is live, and what needs a look. Ask for the overview:
view: "live"lists every active decision and constraint by the directory it applies to;view: "look"lists records whose file is gone or whose symbol is not found, conditions you said would bring a rejected option back, and lines in your instruction files whose record was replaced. Nothing is expired or changed on its own. - See what Sphica showed your agent. Ask what Sphica has been showing:
view: "delivery"(withdays, 1 to 90, 7 by default) counts the deliveries the hooks logged by event (a shell call a dead end stopped, or was shown on without a stop, counted apart) and by main agent or subagent, lists the records shown most, and gives recent sessions with each record's key, so you can judge whether each helped. It says what the log leaves out, and marks a record "named later" only when a later reply wrote its key. - Track your own fields on records (trial). Say in a session which extra field to keep on records (the affected tenant, a p95 figure); trace then saves a value only when the conversation writes it, with the quote.
/sphica:fieldsshows each field and how many records carry a value. - Share decisions as a file.
/sphica:exportwrites the live decisions you pick, with the words quoted for them and the older decisions they replaced, to a Markdown file in your repository for people who do not run Sphica. You see the whole file before it is written, and it is never committed for you. One file holds about 29 KB, what a single reply to the agent carries whole; more decisions go into several files. - Rule text from records.
/sphica:rulesdrafts lines for CLAUDE.md, AGENTS.md, or.claude/rulesfrom the constraints and decisions you pick, each marked with its record key so the overview flags it once the record changes. It never edits the file. - Check your agents' memories against the records.
/sphica:memory-check($sphica:memory-checkin Codex) reads Claude Code's auto memory, Codex's memories, and your CLAUDE.md and AGENTS.md, and lists the lines that go against a live record or describe a replaced one as current, with the record and both quotes. Lines that mention an option a record rejected are listed apart, so a line that rightly forbids it is not counted as a problem. It never edits a file or a record; fixing a line is your call. Sphica does not take over the hosts' own memories. Codex'smemories.disable_on_external_contextkeeps chats that used MCP tools, Sphica's included, out of new memories; it does not stop the memories Codex already has. - Reviews check past decisions.
/sphica:reviewruns a reviewer per focus (correctness, security, written conventions, and past decisions by default; redundancy withfull), and checks the diff against the records it touches.
Requirements
- Node.js 24.15 or later
- Claude Code 2.1.139 or later, or Codex, or both. Older Claude Code skips Sphica's hooks without a word, so nothing is captured or delivered (
sphica doctorflags it) git, to identify the repositories you register- For
/sphica:harvestand fetching GitHub sources in/sphica:glean: the GitHub CLI (gh), signed in withgh auth login
Install
The plugin ships the MCP servers, hooks, and skills. The sphica CLI comes from npm and is installed separately. You need both.
1. Install the CLI
npm i -g sphica2. Add the plugin
Claude Code:
claude plugin marketplace add iroha924/sphica
claude plugin install sphica@sphicaCodex:
codex plugin marketplace add iroha924/sphica --ref main
codex plugin add sphica@sphicaIn Codex, open /hooks and mark Sphica's hooks as trusted. Automatic recording does not start until you do. If a plugin update changes the hooks, trust them again. The "Codex hooks" line of sphica doctor shows how many are trusted (for Codex 0.160.0).
Optional, Claude Code only: a pane that lists what Sphica handed the agent in this session.
claude plugin install sphica-pane@sphicaRun /sphica-pane to open it, and press ctrl+x then x to close it. Newest first, it shows the current work and constraints given at session start, the records given before a read, an edit, or a prompt, and the reason when Sphica stopped a shell call.
- It needs Claude Code 2.1.300 or later, the version its checks run on. Older Claude Code fails to load it, and Sphica itself keeps working.
- It is a Claude Code mod, so it runs with Claude Code's permissions. It only reads what the hooks returned and passes that on unchanged. It writes nothing, reads no files, and sends nothing anywhere.
- It recognizes Sphica's text by its wording, so text another plugin writes in the same words shows too. Treat it as a view, not a record.
- Where an organization manages Claude Code, the hooks it reads run only for plugins the organization lists, so the pane stays empty.
- Codex has no mods.
codex plugin listshows sphica-pane too, but do not install it there: Codex warns about its hooks file in every session.
3. Set up in your repository
cd path/to/your-repo
sphica initThis creates ~/.sphica/sphica.db and registers the repository. Running it again keeps the database and the registration as they are. If the repository has no origin remote, give it a name: sphica init --name <name>.
If gh is signed in, init also binds that GitHub account as yours, so your words adopt a decision even in someone else's repository where you are only a contributor (in pull requests harvested after binding). Only the first account is bound, and there is no command to change it: move the database aside and run init again. Without gh, init still sets up and says why nothing was bound; sphica doctor shows the bound account.
4. Check the setup
sphica doctordoctor checks Node.js, the CLI and plugin versions, the database, the recording queue, and the registered projects. Start here whenever something looks wrong.
Quick start
Only sessions in repositories you register (projects) go into Sphica's database; run sphica init in each one.
Work as usual. A new session asks the agent to trace earlier sessions on its own (in Codex, a session started from the terminal). To keep something right away, run /sphica:trace ($sphica:trace in Codex).
/sphica:trace pending lists earlier sessions not traced yet. To keep what a pull request decided, run /sphica:harvest 123.
When you find evidence later ("the ops notes say…", "Kimura said the team agreed"), run /sphica:glean with what you found.
To bring back earlier decisions, ask the agent:
- "Did we already decide how to handle retries here?"
- "Why did we choose this approach, and what did we reject?"
- "Did we try generating thumbnails in a worker before?"
What the agent sees on its own
Without being asked, Sphica adds a few past records to what the agent sees, each marked as a past record rather than an instruction:
- At session start: the current work and project-wide constraints, and, when earlier sessions wait to be traced, a request to trace them after your request is done.
- On a prompt that names a recorded code symbol, file path, or option.
- Before the agent reads or edits a file a decision applies to, and before a shell command that names such a file (naming it is not proof the command reads it). A read shows each record once per session.
- Before a shell command that runs the command a recorded dead end is about: the call is stopped, with the dead end as the reason. A dead end stops a conversation once (once more after a compaction or
/clear), and a conversation is stopped at most three times. Running the call again goes through. Past three stops, or for a dead end the conversation has already seen, the dead end is shown without stopping, within the read limit. - Before a review. When you run your own review command (any name containing
review, or a name listed in the review commands setting), it gets the decisions your local change touches./sphica:reviewchecks them itself.
Two kinds of agent get less, because what they were given at the start or on reads was seldom of use to them:
- A subagent, and a Codex child thread such as its built-in review's, starts with one line asking it to search Sphica's records first, not the current work and constraints. Its reads and edits get records as above.
- A run another agent started from its shell gets nothing at session start and nothing for what it reads:
claude -pstarted from Claude Code's Bash, andcodex execstarted from Claude Code's Bash or a Codex shell, when its session log sayscodex execor it keeps no log (--ephemeral). A shell command that names a file gets nothing either, even one that writes it (sed -i); edits through the edit tools orapply_patch, reviews, and dead-end stops are as above. A run you start yourself in a terminal gets everything. Sphica tells these runs apart by the marker the starting agent's session leaves in the environment, so a Codex terminal session that runs through a background server started from an agent's shell (see Settings) is taken for such a run too if Codex fails to name its session log to the hook.
In Codex the same happens at session start, on a prompt, before an apply_patch edit, before a shell command that names such a file (Codex reads files through shell commands, so this covers reads), and before a shell command that runs a dead end's command (stopped once, as in Claude Code).
Before a review, Codex gets the same decisions in three cases: its built-in review (/review, codex review), a review skill you name in the prompt ($my-review), and a review skill the agent picks itself, when it prints the skill's file with one plain command such as cat <path>/SKILL.md. A skill is a review when its name contains review or is listed in SPHICA_REVIEW_COMMANDS. $sphica:review checks them itself.
The agent searches with Sphica's search and opens full records with read. status tells it how much of the history has been traced, so an empty search is less likely to be mistaken for "never decided".
Settings
| Setting | Default | Claude Code option | Environment variable |
|---|---|---|---|
| Automatic trace | on | auto_trace | SPHICA_AUTO_TRACE (off) |
| Your own review commands whose names do not contain review, comma-separated | none | review_commands | SPHICA_REVIEW_COMMANDS |
- Claude Code. Set the plugin's options in
/config(Claude Code 2.1.269 or later), or set the variables in the environment Claude Code starts from; for the automatic trace,"SPHICA_AUTO_TRACE": "off"underenvinsettings.jsonworks too. The automatic trace stays off when either the option or the variable says off, so to turn it back on, turn the option on and unset the variable. Whenreview_commandsnames any command,SPHICA_REVIEW_COMMANDSis not read. - Codex. Codex plugins have no options page, so the settings are the environment variables. In a session that runs through Codex's background server (the terminal does by default), Sphica's hooks see the environment that server started with, not the terminal you open later: a value you set afterwards takes effect the next time the server starts (
codex app-server daemon restartstarts it again; work running in Codex may be interrupted).codex execdoes not use that server, so its hooks see the environment it was started from. A background server started from inside an agent's shell (for example! codexin Claude Code) keeps that agent's variables too: Sphica then takes every session that runs through it for that agent's child and records nothing until the server starts again.
What gets recorded and where it goes
Where. The database is
~/.sphica/sphica.db. Captured sessions wait in a local queue,~/.sphica/spool, until they are written to it. Each machine has its own database; nothing is shared between machines.What. Your prompts, the agent's final reply for each turn, and the paths of changed files. In Codex, a session is recorded only when Codex's own session log shows the messages come from the session's own thread: what Codex's built-in review is asked (its instructions, the subject of the commit it names) is not recorded, and neither is a
codex exec --ephemeralrun, which keeps no log. When Sphica cannot confirm a session, it records nothing of it; Codex's terminal shows Sphica's notice once, andcodex execshows none. Background-task notifications and messages from other agents are skipped when Sphica recognizes their format. Replies in the middle of a turn are not kept, nor are files created and deleted within one turn without the edit tools.What was shown. Each automatic delivery is logged by which records it showed, not their text.
Unregistered repositories. Sessions in a repository you have not registered stay in the queue and are written after you register it. Held sessions are dropped after 30 days, and when more than 1,000 are waiting the oldest go first.
Secrets. In your prompts, pull request text, and the file lines
/sphica:gleancites, only secrets with a recognizable shape are masked:- keys with known prefixes
KEY=…and"password": …assignments- credentials in URLs
- authorization headers
mysql -p
Anything else is stored as typed, so do not paste secrets into a session. If one got in, remove the source holding it with
/sphica:forget($sphica:forgetin Codex). It asks you to confirm in a dialog, so it works only in an interactive session: in a headless run (claude -p,codex exec) nothing is removed. A record that repeated it keeps its own text.Network. Sphica has no account, no hosted service, and no telemetry, and makes no network connections itself.
/sphica:harvestand/sphica:gleanrungh apiwith your credentials to read pull requests and issues,sphica initrunsgh api userto read which GitHub account is yours, andsphica doctorrunsnpm,claude, andcodexto check installed versions.gh apiis always sent to github.com.Text written by others. Pull request and issue text may come from anyone. It is kept as a source and passed to the agent as data, never as instructions. A decision is adopted by your words, those of the repository's owner or a maintainer, or what the agent decided itself; what the agent quotes or sums up from someone else's text is not adopted.
What Sphica can't do yet
- Only what you traced, harvested, or gleaned becomes a structured record. The rest of a conversation is searchable as captured text (
searchwithsources: true). - For shell commands, Sphica only sees whether a command names a file. It may show decisions for a file the command never reads, and a shell command that edits a file is not treated as an edit (in Codex, a patch passed to
apply_patchthrough the shell is treated as an edit). - A dead end's command is matched by its words, whole and in a row, within one command of one line. Sphica reads no other shell syntax: a mention outside quotes (
echo pnpm test --watch) matches, and a command joined to the one before it without a space (npm ci;pnpm test --watch) or written another way (npm.cmd) does not. - Before a review, Sphica compares your working tree with the default branch, whatever the review itself was given (a commit or a base branch in Codex's built-in review). In Codex, a review skill the agent reads in any other way than one plain command (after
cd, through a pipe, inside a longer script) gets nothing, and neither does the built-in review of acodex exec --ephemeralrun. - In Codex,
$sphica:trace,$sphica:harvest, and$sphica:gleancan write only when Codex tells Sphica which directory the session is in. Current Codex does. When it does not, they write nothing and tell you why. /sphica:memory-checkstays read-only in Claude Code because the Skill removes the write tools, Bash, subagents, and Sphica's record tools for its turn (they come back when you reply). Codex has no way for a Skill to remove tools, so$sphica:memory-checkkeeps to reading only by its instructions.- Showing a record does not make the agent follow it.
- Whether the agent decided something itself is judged from what its reply says, so it can be wrong.
- An AI's decision is adopted only when the trace runs in an interactive session: Claude Code's terminal, or a Codex turn a person started in the session's own thread (measured with Codex's terminal). In headless and SDK runs,
codex exec, and a Codex child thread it stays a candidate (recorded, but not adopted), and once a Codex child thread has called one of Sphica's record tools, no reply of that session is adopted. - The automatic trace is a request the agent may skip, and it uses your subscription's usage. In Codex it goes only to new sessions started from the terminal; in other Codex clients and in
codex exec, Codex tells you when sessions wait. - When Sphica cannot tell which turn ran one of its record tools, every reply Claude Code's agent writes in that project from then on stays a candidate, and records already saved as candidates are not adopted afterwards. If the hook only timed out, replies of other turns can be adopted again once the next recording sends what the hook saw (when the hook knew the turn). If the hook was turned off, the host sent no tool call id, or the call came before Sphica was installed, the stop stays for good.
sphica doctorlists the calls behind a stop and since when. Your decisions are not affected. - The agent never withdraws an AI's decision. When a later record contradicts it, the AI's decision is held back from being shown until you settle it, and so is the later record unless it is your decision.
- A code location in a record is checked against your working tree when it is read. Finding the code name (a function name, say) the record points to does not mean the decision still holds.
Updating
The CLI and the plugin are updated separately.
npm i -g sphica@latestClaude Code:
claude plugin marketplace update sphica
claude plugin update sphica@sphicaIf you installed the pane, update it too with claude plugin update sphica-pane@sphica. A fix to it comes with the next Sphica release.
Codex:
codex plugin marketplace upgrade sphica
codex plugin add sphica@sphicaRestart open sessions afterwards. When an update changes the database, update the CLI first, then run sphica init once: it migrates the database in place and keeps your records. Until then Sphica is unavailable and tells you so. An older CLI cannot read the migrated database: if one still says to move it aside, update that CLI instead.
Uninstalling
sphica uninstallThis deletes ~/.sphica (the database and the recording queue) after asking, and shows the commands that remove the rest:
claude plugin uninstall sphica@sphica && claude plugin marketplace remove sphica
codex plugin remove sphica@sphica && codex plugin marketplace remove sphica
npm uninstall -g sphicaIf you installed the pane, remove it first with claude plugin uninstall sphica-pane@sphica. Removing the pane alone leaves Sphica working.
Troubleshooting
Run sphica doctor first. It shows which part is out of date or not working. Common cases:
sphica: command not found. The plugin does not put the CLI on your PATH. Runnpm i -g sphica.- Nothing is recorded. Check that
sphica doctorlists the repository under Projects. In Codex, also check the "Codex hooks" line, or/hooks, for hooks that are not trusted; if Codex was started from inside another agent's shell, see Codex under Settings. - The MCP servers report an older version. Restart the session, or run
/reload-pluginsin Claude Code. - A search finds nothing. Search matches words. Try other words, the other language, an identifier, or fewer words. Ask the agent to check
status: sessions not traced yet are searchable only as captured text. doctorsays the full-text index is broken. Runsphica doctor --reindex.- A review says Sphica's git worker would not start, or
doctorshows it underGit worker. Sphica reads your working tree with git in a folder of its own,.sphica/gitunder your home directory, and refuses to when that folder overlaps the temp directory or the working tree itself (an agent in a sandbox can write there), or is a link.sphica doctor, run inside the repository, says which. Until it is fixed, the check before a review cannot read your local change.
Commands
| Command | What it does |
|---|---|
| sphica init | Create the database, bind the GitHub account gh is signed in to, and register the current repository |
| sphica doctor | Check versions, the database, recording, and each registered project |
| sphica doctor --reindex | Rebuild the full-text index when doctor says it is broken |
| sphica doctor --audit-quotes | List saved adoptions and reasons that rest on quoted words. It only reads: nothing is changed |
| sphica uninstall | Delete ~/.sphica and show how to remove the plugin and the CLI |
Everything else runs inside Claude Code and Codex, through the /sphica:* commands and Sphica's MCP tools.
Security
Report vulnerabilities privately as described in SECURITY.md.
Each release is built by GitHub Actions from a tag on the head of a pull request whose CI has passed. It is published only after the maintainer approves the release environment on GitHub, and it reaches npm through trusted publishing, with no stored token. The npm page links to the workflow and the commit each release was built from.
Releases are signed. To check one yourself, run npm init -y && npm install sphica && npm audit signatures in an empty directory: it verifies npm's registry signature and the provenance attestation, which is signed through Sigstore, so there is no key to fetch. The attestation of the SBOM (the list of dependencies bundled into the package) for a tarball from npm pack sphica@<version> can be checked with gh attestation verify sphica-<version>.tgz --repo iroha924/sphica --predicate-type https://cyclonedx.org/bom.
How the parts fit together is in ARCHITECTURE.md, and why the security claims hold is in ASSURANCE.md.
Dependabot opens weekly pull requests to update the GitHub Actions used in CI, and Renovate opens monthly ones for the npm dependencies bundled into the package.
Contributing
Come build something interesting together. Sphica is still small and there is plenty left to make. Ideas, bug reports, questions, and pull requests are all welcome, and small ones count: a typo fix or a "this part confused me" is a fine first contribution.
- Not sure where to start? Open an issue and say what you would like to try, or what got in your way. For a larger change, it is also the place to agree on the direction before you write any code.
- Have a change ready? Fork the repository and open a pull request. CONTRIBUTING.md walks through the setup, the checks, the commit rules, and how review works.
- What happens next? A pull request goes in once the maintainer has read and accepted it, so expect questions or requests for changes along the way. Only the maintainer merges.
Changes that add or change behavior include automated tests in the same pull request. CI runs them with bun run verify on every pull request.
Everyone taking part follows the code of conduct. Who decides what is in GOVERNANCE.md, and where the project is headed is in ROADMAP.md.
License
MIT. The published package bundles its dependencies. Their licenses are listed in THIRD_PARTY_NOTICES.md inside the package.
