Your agent forgot the ADR you wrote 30 prompts ago.
A bash CLI that re-injects your curated project brief into Claude Code on a cadence — fights context rot before AutoCompact summarizes your decisions away.
30 prompts in. AutoCompact fires. Background jobs feel slow, so you ask the agent: "can we add Redis + Sidekiq for the queue?" It says yes — forgetting you spent an entire ADR deciding Postgres-backed jobs only, no new infrastructure.
With revive, the PostCompact hook just refreshed your project's
.revive/static.md into the recent attention window:
PURPOSE: Internal billing service for a 12-person team. Goal: ship
features without growing the on-call surface — the team has no DevOps.
Constraint: Postgres is the only datastore; no Redis, no Kafka, no
new infra without exec sign-off.
INVARIANTS:
- Background jobs run on solid_queue (Postgres-backed). No Sidekiq,
no Redis queues. Decided in ADR-014.
So the agent pushes back: "Sidekiq + Redis violates ADR-014 and the no-new-infra constraint. Want to revisit the ADR, or solve queue latency another way — raise solid_queue concurrency, partition the jobs table?"
The decision you made 30 prompts ago is still load-bearing.
curl -fsSL https://raw.githubusercontent.com/justi/context-revive/main/install.sh | bashRequires bash + git. Optional: jq (for install-hook), gh (for
best-quality PURPOSE auto-detection).
Use this if you keep hitting the same failure in Claude Code: 30 prompts in,
the agent forgets an ADR, re-suggests an approach you already rejected, or
asks questions CLAUDE.md already answered. You probably don't need it if
your sessions are short (<15 prompts), CLAUDE.md stays under 1k tokens, or
you already restart sessions frequently.
Not a replacement for CLAUDE.md, Cursor Rules, or AGENTS.md — those load
once at session start and get summarized away by AutoCompact. This keeps
your curated facts fresh in the recent attention window, complementary to
them.
One bash script, zero runtime on the hot path. Works with any agent via paste
(revive show | pbcopy); Claude Code gets first-class hook integration.
cd your-project
revive init # scaffold .revive/static.md; PURPOSE auto-detected, 3 sections left as placeholders
revive suggest | pbcopy # paste into active agent — agent rewrites PURPOSE/DIFFERENTIATORS/INVARIANTS/GOTCHAS
revive audit | pbcopy # paste into a FRESH session — agent proposes bullets the first pass missed
revive install-hook # wire UserPromptSubmit + PostCompact + SessionStart(clear) into .claude/settings.json
revive doctor # sanity-check the install (git, static.md, hook, log)
revive show # preview the assembled brief (forced emit, ignores cadence)The two-pass flow (suggest then audit in a fresh session) is deliberate:
a single session that both generates and audits its own output suffers from
context saturation and self-critique sycophancy. Fresh context finds gaps
the generation pass can't. suggest rewrites placeholder sections;
audit only APPENDS bullets to existing sections after your approval.
Everything below is optional — the quick start gives you a working hook.
- What the source file looks like — four sections, flat text, 2–5 KB typical.
- How often the brief is injected —
cadence rules, env vars for tuning (
REVIVE_REFRESH_EVERY,REVIVE_REFRESH_TIME_GAP). - Token cost — measured ~2–3k tokens per emit, ~1.5% of Opus 4.7 1M context across a 30-prompt session.
- Reset / regenerate from scratch —
rm -rf .revive && revive init && revive suggest | pbcopywhen.revive/static.mdhas drifted. - Upgrade to a new release — re-run
install.sh. Per-project state preserved.
Four flat sections. Immediately after revive init, the file has
PURPOSE filled (auto-detected — see the chain in Design notes) and
three placeholder sections waiting for your edits:
PURPOSE: <auto-detected from gh / manifest / CLAUDE.md / README>
DIFFERENTIATORS:
- (what sets this project apart; edit this file)
INVARIANTS:
- (top-5 architectural rules; edit this file)
GOTCHAS:
- (landmines you keep stepping on; edit this file)
PURPOSE is one physical line in the file — no \n in the middle,
even when it holds 2–3 sentences and wraps visually in your editor
(up to 400 characters). The three other sections are bullet lists
under a section header.
After revive suggest + revive audit (or a hand edit), the file
looks like:
PURPOSE: Background-job scheduler for small Go services. Success metric is zero surprise job failures after a deploy — goal: replace ops-managed cron with code-defined schedules that survive rollouts. Constraint: job state lives in the app's own Postgres; no new infrastructure.
DIFFERENTIATORS:
- Traditional cron → schedules defined in code, survive deploys
- Managed SaaS schedulers → zero new infrastructure; reuses app Postgres
- Temporal / DAG workflow engines → single-step jobs only; keep it small
INVARIANTS:
- Every schedule change ships with a migration; never edit rows in prod.
- Jobs must be idempotent — retries on deploy-overlap are expected.
- Worker binary must not grow past 30 MB (embedded-device deploy target).
GOTCHAS:
- `make test` runs integration against a real Postgres — set TEST_DATABASE_URL.
- `bin/deploy` always runs `schedule:apply` last; reordering breaks overlap detection.
The file is checked in. revive show assembles the brief around it on each
refresh. Placeholder-only sections (still saying "(edit this file)") are
suppressed from the emitted brief — no noise injected to the agent.
Emits when ANY of these is true:
- First prompt of the session (counter = 1).
- Every 5th prompt after that, via
REVIVE_REFRESH_EVERY(default5). - Gap of >10 minutes since the last emit, via
REVIVE_REFRESH_TIME_GAP(default600seconds). - Right after
/compact(or AutoCompact). ThePostCompacthook drops.claude/revive-compact.signaland the next refresh consumes it, bypassing cadence — that's the moment the agent has lost the most context, so re-injecting the brief gives the highest ROI. - Right after
/clear.SessionStartwithmatcher: "clear"drops the same signal —/clearwipes more than/compact, same recovery path applies.
Prompts between emits see nothing from revive — silent skip, zero cost. Tune in your shell:
export REVIVE_REFRESH_EVERY=3 # every 3rd prompt
export REVIVE_REFRESH_TIME_GAP=300 # 5-minute gap thresholdMeasured on a rich-architecture project (Python + Streamlit + 19 ADRs,
.revive/static.md ≈ 4 KB with 12 INVARIANTS, 8 GOTCHAS):
| Scope | Tokens | % of Opus 4.7 1M |
|---|---|---|
| Brief per emit | ~2–3k | ~0.25% |
| 30-prompt session (6 emits) | ~15k | ~1.5% |
| Claude Code hook hard cap | 10k chars per emit | — |
English-only repos land closer to ~1.5k per emit; Polish/mixed with unicode
glyphs runs higher. Measure your own by running /context before and after
a prompt that triggers the hook — the delta in Messages is the emit cost.
If .revive/static.md drifted (old extractor, stale rules, marketing-tagline
PURPOSE slipped in):
cd your-project
rm -rf .revive
revive init
revive suggest | pbcopy # paste → agent rewrites the file end-to-end
revive audit | pbcopy # paste into FRESH session → agent fills gaps
revive show # verifyLighter alternative: revive init --force regenerates only PURPOSE and
preserves user-edited DIFFERENTIATORS / INVARIANTS / GOTCHAS.
curl -fsSL https://raw.githubusercontent.com/justi/context-revive/main/install.sh | bash
revive version
revive doctor # sanity-check the installRe-writes ~/.local/bin/revive. Per-project .revive/static.md files and
Claude Code hook settings are not touched. Release notes flag when a
version adds a new section and you may want revive init --force to
regenerate scaffolding.
- PURPOSE — one physical line, ≤400 chars, typically 2–3 sentences
covering what the project is, its business goal, and the one hard
constraint that shapes design decisions. Auto-detected via a chain:
gh repo view --json description→ manifestdescription(pyproject, package.json, Cargo, gemspec, composer) →CLAUDE.mdfirst paragraph → filtered README prose. First hit wins. - DIFFERENTIATORS, INVARIANTS, GOTCHAS — human-curated (via
suggest+audit, user-reviewed). Research: "Human curation yields ~4% performance gains; auto-generation reduces success rates by 0.5–2%" (Augment Code, 2026). - STATE —
gitbranch + last 3 commits (subject only for subject-only commits; subject plus the first paragraph of the body, truncated to ~100 chars, for commits that carry a body). Squash-merge bodies typically hold the PR description, so this surfaces PR context for free without aghAPI call. - HOT_FILES — top 5 files by commit-frequency over the last 20 commits, each annotated with the last commit subject.
- COMMANDS — exact test / lint / build / dev / setup
invocations. Source priority:
.revive/commands.mdoverride → Railsbin/*(ifGemfileor*.gemspecpresent) →package.jsonscripts→Makefiletargets → Railsbin/*fallback. Whole section is suppressed if no source matches.
Auto-generated architecture overview, directory tree, dependency graph,
full file contents, LLM-summarized anything on the hot path. Evidence:
"Directory trees cause stale structural references that mislead agents",
and auto-generated summaries reduce agent success rate by 0.5–2% while
increasing cost 20%+ (Augment Code, 2026). If you want an
architecture summary in the brief, write it by hand into INVARIANTS.
Anthropic's AutoCompact fires at the context-window ceiling — it summarises the conversation to make room. revive addresses a different failure: context rot, where the agent forgets as tokens drift out of attention long before AutoCompact triggers. Cadence-based re-injection keeps key facts in the recent window (Zylos, 2026 splits context into stable prefix + fresh suffix — our STATIC/DYNAMIC split maps cleanly).
Zero runtime. <100ms cold start. Transparent — cat $(which revive).
One file to audit, no dependency tree. The point of this repo is that it
works on any dev machine without installing a language toolchain.
Pre-alpha. Weekend MVP in active dogfooding. v0.2.0 — context-loss
recovery: refresh fires after /compact and /clear; revive init
auto-fixes .gitignore; sharper tagline; see
Releases for history.
MIT