Offload context. A plugin for Claude Code and Codex CLI that stashes findings, decisions and long outputs into a project-local .attic/ folder and keeps only a one-line index in the conversation. The live context stays lean, and what matters survives /compact, /clear and new sessions.

Most token-saving tools shorten what Claude writes. Attic targets a different sink: the knowledge Claude keeps re-reading and re-explaining because it lives nowhere but the chat.
you: why does the login test time out?
claude: `attic:login-test-timeout` · 5s fixture timeout in tests/conftest.py:41, SMTP call is real. Fixing now.
The full trace, the files it read and the reasoning are in
.attic/items/login-test-timeout.md. Three hours and one /compact later,
Claude still knows.
Install
Claude Code
claude plugin marketplace add NishikantaRay/Attic
claude plugin install attic@attic
Codex CLI
codex plugin marketplace add NishikantaRay/Attic
codex plugin add attic@attic
Then run /hooks once in an interactive session to trust the attic hooks;
Codex does not run hooks it has not reviewed. Same skills, same script, same
hooks as the Claude Code build. Details, alternatives and exactly what was
verified: docs/CODEX.md.
Check it is on, then see the difference
/attic-help # prints a card if the plugin is loaded
/attic # reports and sets the level
sh scripts/try-attic.sh # side by side, on a throwaway project
sh scripts/try-attic.sh --host codex
It asks one question twice, with and without the answer stashed, and prints both answers and both token counts. Measured on 2026-09-04:
| Without attic | With attic | |
|---|---|---|
| Claude Code | 92,976 tokens, 3 turns | 30,201 tokens, 1 turn |
| Codex CLI | 85,434 tokens, 3 shell commands | 15,717 tokens, 0 commands |
Both arms answered correctly. Full walkthrough, including how to watch a
finding survive /compact: docs/QUICKSTART.md.
Requires Node.js on PATH for the hooks. Without Node the skills and commands still work; only the automatic session-start injection is lost.
Try it without installing:
git clone https://github.com/NishikantaRay/Attic
claude --plugin-dir ./Attic
Commands
| Command | What it does |
|---|---|
/attic [lite|full|ultra|off] |
Set the level. No argument means full. |
/attic default <level> |
Make a level the default for new sessions. |
/attic-stash [title] |
Stash the latest finding, result or decision and get its handle. |
/attic-recall <slug or words> |
Pull an item back and summarise it. |
/attic-index |
List everything stashed in this project. |
/attic-sweep |
Save plan, open questions and in-progress state. Run before /compact. |
/attic-pin <slug> |
Always inject this item, never trim it. |
/attic-prune |
Archive stale items. Dry run by default, never deletes. |
/attic-stats |
What the attic costs and holds, measured locally. |
/attic-doctor |
Check .attic/ for drift, orphans and leaked credentials. |
/attic-git |
Fix .attic/ merge conflicts and set up a shared team attic. |
If the index ever gets out of step with the items, it is derived data and can
be regenerated: node skills/attic/scripts/attic.js rebuild. The item files
are the source of truth, so nothing is lost.
| /attic-help | One-screen reference. |
Every command, every script flag and every exit code: docs/COMMANDS.md.
Installed plugins are namespaced, so the fully qualified form is /attic:attic-help; the short form works when no other plugin claims the name.
Claude also stashes on its own at full and ultra, and reacts to phrases like "stash this", "remember this for later", "before compact" and "what did we find about X".
Levels
| Level | What changes |
|---|---|
lite |
Stash only on /attic-stash, at the end of a task, or when asked to sweep. Normal replies otherwise. |
full |
After every investigation, write the conclusion to the attic and reply with the handle plus three lines. Never re-explain what is in the attic. Decisions logged. Long output summarised and stashed, never pasted. Default. |
ultra |
Everything non-trivial is stashed. Replies are handle plus three lines. Claude must check the index before re-reading anything it has already seen. |
off |
Dormant. |
ATTIC_DEFAULT_MODE=lite|full|ultra|off sets the starting level. /attic default <level> does the same and persists it to ~/.claude/attic/config.json (or the plugin data dir).
What ends up in .attic/
.attic/
INDEX.md one line per item: - [slug](https://github.com/NishikantaRay/Attic/blob/main/items/slug.md) · kind · one-line hook
DECISIONS.md append-only: - 2026-09-04 · use lru_cache · because one line beats a cache class
items/<slug>.md frontmatter (title, kind, date, tags) + the content
archive/<slug>.md pruned items: still recallable, no longer injected
How the index scales
The index is injected at every session start, so it cannot grow without bound. Three tiers share a fixed budget:
| Tier | Rule |
|---|---|
| Pinned | /attic-pin marks these. Always injected, never trimmed. |
| Recent | Newest items fill the remaining budget. |
| Rest | Collapsed to one line naming the counts, so older knowledge stays discoverable via /attic-recall. |
Trimming drops the oldest unpinned entries. Your newest finding is never the one that disappears.
Kinds: finding, decision, plan, output, note. Handles look like attic:<slug>.
Always stashed verbatim: code, commands, file paths, line numbers, error text. Never stashed: secrets, tokens, credentials, one-line answers, typo fixes.
Git
.attic/ is plain Markdown. Two sensible choices:
- Commit it for shared team memory. New contributors (and new Claude sessions) start with the index.
- Ignore it (
echo .attic/ >> .gitignore) if you want it personal.
If you commit it, run /attic-git. INDEX.md and DECISIONS.md are
append-only, so two branches that each stash something conflict on every
merge. The command installs a union merge driver that keeps both sides.
See docs/TEAM.md.
How it works
Three hooks, all zero-dependency Node scripts in hooks/:
| Event | Script | Effect |
|---|---|---|
SessionStart (startup, resume, clear, compact) |
attic-activate.js |
Injects the rules for the active level plus .attic/INDEX.md (capped at 60 lines / 4 KB). This is what makes the attic survive /compact. |
UserPromptSubmit |
attic-mode.js |
Tracks /attic <level> and /attic default <level>, confirms the change. Silent on every other prompt. |
SubagentStart |
attic-subagent.js |
Briefs subagents so they stash instead of dumping into their report. |
The ruleset itself lives in skills/attic/SKILL.md. The other skills are the slash commands.
Architecture
Attic is built as a versioned, testable, enforceable component rather than a Markdown prompt. See docs/ARCHITECTURE.md for the full layer map.
skills/attic/
├── SKILL.md the hub: scope, rules, routing
├── references/ domain knowledge, loaded on demand
├── scripts/attic.js deterministic file operations
├── templates/ output shapes
└── evals/ activation + behaviour suites
The split that matters: the model decides what is worth stashing and writes
the prose; the script owns everything mechanical. Slug hygiene, frontmatter,
index bookkeeping, atomic writes and credential detection are software
concerns, so scripts/attic.js handles them and exits non-zero when something
is wrong. "Never stash secrets" is still in the instructions, but it is no
longer the only thing enforcing it.
node skills/attic/scripts/attic.js stash --slug x --kind finding --hook "..." --body "..."
node skills/attic/scripts/attic.js recall "login timeout"
node skills/attic/scripts/attic.js validate # exit 3 on drift or a leaked credential
Does it actually help?
Sometimes. Here is the measurement, including where it does not.
The benchmark asks one question about code whose answer is already stashed, against a 26-file fixture, and counts real input tokens from the CLI's own usage output. Both arms are graded for correctness, because a cheaper wrong answer is not a win. It runs on both supported hosts.
Codex CLI, three runs per arm:
| Case | Without attic | With attic | Delta |
|---|---|---|---|
| Answer is stashed | 43,357 | 14,569 | -66.4% |
| Nothing relevant stashed | 28,654 | 29,363 | +2.5% |
Claude Code, two independent runs of three:
| Case | Without attic | With attic | Delta |
|---|---|---|---|
| Answer is stashed, run 1 | 90,263 | 30,163 | -66.6% |
| Answer is stashed, run 2 | 90,272 | 60,687 | -32.8% |
| Nothing relevant stashed | 57,698 | 60,428 | +4.7% |
Correctness held at 18 of 18 across both hosts, both arms and both cases.
Read that honestly. On Claude Code, two runs of the same benchmark differ by more than 30 points, so no single percentage from that host is trustworthy. Codex is far steadier: its attic arm varied by 14 tokens across three runs. What both hosts agree on is the direction. When the answer is already stashed the attic arm costs fewer input tokens and fewer turns, because its cost does not depend on how much the model decides to read. On Codex the attic arm ran zero shell commands against two for the arm that had to search. When nothing relevant is stashed, the attic is pure overhead, and the last row of each table is what that looks like.
node benchmarks/run.js --runs 3 # Claude Code
node benchmarks/run.js --host codex --runs 3 # Codex CLI
Full method, raw samples and the reasons not to quote a headline number: benchmarks/README.md and docs/HONEST-NUMBERS.md.
Evaluation
Activation and behaviour are measured separately.
node scripts/run-evals.js --suite activation # real headless sessions, scores the classifier
node scripts/run-behavior.js # real sessions, graded on files + reply
node scripts/run-evals.js --suite behavior # the remaining judgement-call checklist
node scripts/run-evals.js --case act-22 # a single case
Activation proves the right skill fires. Behaviour proves it then does its
job: run-behavior.js seeds an attic, runs a real headless session, and
asserts on what landed on disk and what the reply said. It is what catches a
skill that activates correctly and then does nothing.
The activation suite reports accuracy, coverage, false positive rate, false negative rate and wrong-skill rate over positive cases, negative cases, and collision cases. Current baseline: 100% across 22 cases, recorded in skills/attic/evals/results/.
Attic publishes no headline savings percentage, because a reproducible
baseline for agent sessions does not exist. /attic-stats reports what is
measurable on your machine and says where the attic costs more than it
returns. See docs/HONEST-NUMBERS.md.
Enforcement
| Layer | Mechanism |
|---|---|
| Session start | hooks/attic-activate.js injects the index, so the attic survives /compact. |
| Write time | scripts/attic.js refuses credentials with exit code 2. |
| Commit time | scripts/attic-precommit.sh blocks a commit with a malformed or leaking .attic/. |
| CI | .github/workflows/ci.yml runs tests and manifest validation; attic-guard.yml validates .attic/ on pull requests. |
| Merge time | scripts/attic-merge.js resolves index conflicts instead of losing one side. |
Project files
docs/QUICKSTART.md · poster · docs/COMMANDS.md · CHANGELOG.md · docs/CODEX.md · CONTRIBUTING.md · SECURITY.md · docs/ARCHITECTURE.md · docs/HONEST-NUMBERS.md · docs/TEAM.md
Repository layout
skills/ the skills, shared by both hosts
hooks/ session hooks, shared by both hosts
scripts/ tooling; scripts/codex/ holds the Codex launcher and installer
codex/ GENERATED Codex plugin — do not edit, run npm run build:codex
.agents/plugins/ Codex marketplace manifest; makes this repo installable with codex plugin add
benchmarks/ the two-arm benchmark and its recorded results
docs/ architecture, honest numbers, team workflow, Codex notes
Claude Code loads skills/ and hooks/ directly through its plugin
manifest. Codex gets the same content via the generated codex/ build, which
carries a .codex-plugin/plugin.json of its own; .agents/plugins/ makes
the repository a Codex marketplace.
Development
npm test # unit tests: hooks, script, eval suite integrity
claude plugin validate . --strict # manifest and component checks
claude --plugin-dir . # load this checkout into a session
npm run build:codex # regenerate codex/ after changing a skill
npm run bump -- 1.2.0 # move every version string together, then rebuild
sh scripts/publish-release.sh # tag + publish a GitHub release (needs gh auth login)
npm run bench # the two-arm token benchmark
npm run make:assets # regenerate the README diagrams
npm run make:logo # regenerate the logo variants
npm run make:poster # regenerate the poster and social card
Uninstall
claude plugin uninstall attic@attic
.attic/ folders in your projects stay where they are; delete them if you want.
License
MIT
No comments yet
Be the first to share your take.