A local-first persistent memory layer for AI coding sessions. It captures the gotchas, decisions and dead-ends your code can't tell an agent β and replays them into the next Cursor / Claude Code / Copilot session, so the same wrong turn never happens twice.
The problem
You spend 90 minutes teaching an agent that your auth API returns 200 even on errors. Next session it writes if (response.ok) all over again. The model didn't get worse β it has no memory. Code changes daily; what the system actually does under those edits β the invariants, the constraints, the things that bit you last week β code can't tell you.
Each session re-reads the code and re-infers the obvious, burning tokens and wall-clock.
The same wrong turn someone hit yesterday gets made again β the gotcha never persisted.
"Why opaque tokens, not JWTs?" β the rationale lived in a chat that's gone.
System overview
Clients talk to infernoflow over several interchangeable transports; a small deterministic core reads and writes a single on-disk memory store and keeps the IDE rule files current. No service, no daemon, no network in the default path (telemetry is opt-in).
amp_* tools are exposed over MCP, VS Code LMT and as CLI aliases β one product, one disk file, multiple transports. Pick whichever fits your setup; all paths write to the same .ai-memory/.The loop
infernoflow closes the cold-start loop in four stages. Most of it happens without you: the MCP-aware agent writes entries; the CLI and hooks back it up; the next session boots warm.
amp_write; a Cursor prompt-hook backstops it deterministically.file:line, tags, timestamp, a stable AMP id.branches/<branch>.jsonl (git-tracked) or global.jsonl (personal). Travels with the branch.Data flow
How a single finding travels the whole system β from the moment it surfaces to the next session that starts warm because of it.
Steps 1β3 are capture (the AI writes, hooks back it up); 4β6 are restore (the core regenerates the rule files, the next session reads them at boot). The green nodes are the durable on-disk state; the cyan nodes are what the agent reads and writes.
Data model β the AMP protocol
AMP (AI Memory Protocol) is the vendor-neutral format at the core. One append-only JSONL record per memory, with a stable id so any AMP-Full client can reference it.
// one line in branches/<branch>.jsonl { "id": "amp_01KYVXSNMAWCQ9β¦", // stable AMP id "type": "gotcha", // see types β "msg": "API returns 200 on errors", "file": "server/src/api.ts", "line": 42, "tags": ["auth","http"], "ts": "2026-07-31T08:12:03Z", "agent": "infernoflow", // who wrote it: user | infernoflow "detail": "amp_01KYβ¦" // optional β details.jsonl }
| Type | Meaning | Auto-prune? |
|---|---|---|
gotcha | An invariant that bit you | never |
decision | A standing choice + rationale | never |
pattern | How things are done here | never |
preference | A durable user preference (personal, global.jsonl) | never |
attempt | A fix that failed | 30d |
note | Transient observation | 30d |
detection | Auto-detected signal | 30d |
Rotation archives stale note/attempt/detection to archive/ β invisible to reads, still on disk. The durable types are the knowledge you logged infernoflow for. Bookmarks are notes tagged bookmark and are never aged out either.
The lean index (msg + file:line) is what gets injected and stays cheap. A rich detail body lives in a single details.jsonl, loaded on demand via readDetail() and never injected into rule files β you pay for the body only when you open it.
Storage layout
.ai-memory/ βββ branches/ β βββ main.jsonl project truths (git-tracked) β βββ feature-auth.jsonl branch work (git-tracked) βββ details.jsonl tier-2 bodies (on demand) βββ details.local.jsonl transcript snapshots (local only) βββ sessions.jsonl automatic resume points (local only) βββ archive/ β βββ sessions-2026-07.jsonl rotated-out βββ global.jsonl personal prefs (gitignored) βββ handoff.md generated by `switch` βββ amp.json config
merge=union on the branch JSONLs means concurrent commits from two machines merge cleanly β no conflict resolution.refresh.Transports & integration
| Tool | Reads from | Writes via |
|---|---|---|
| Claude Code | SessionStart hook (fresh each session) + .claude/ skill | MCP (amp_write) + memory-keeper agent |
| Cursor | .cursorrules | MCP + beforeSubmitPrompt hook |
| GitHub Copilot (VS Code) | .github/copilot-instructions.md | VS Code LMT + MCP β both wired |
| Windsurf | .windsurfrules | MCP (manual wiring) |
When the server is wired, the agent calls these directly. Five amp_* tools come straight from the AMP MCP spec; amp_bookmark and amp_resume add resume points and "where were we?". The CLI covers the same actions (log, ask, bookmark, resume, switch).
infernoflow_check and infernoflow_context are added only in full mode (Capability Contracts). Only the read tools are pre-approved; tools that write memory ask first.
Injection & refresh
The agent reads the IDE's own rule files at boot. infernoflow owns a marked-off block inside each; your manual edits outside the markers are never touched.
<!-- infernoflow:start --> π₯ gotcha @ api.ts:42 β 200 on errors, check body π₯ decision @ auth.ts β opaque tokens, revocable <!-- infernoflow:end -->
Injected content is paid for on every turn, so defaults are lean: 4 entries, 5 commits, 200-char truncation, a compact ~3-line protocol. Tunable in amp.json (maxEntries, protocolStyle, targets).
infernoflow refresh β manual rebuild; --targets controls which files carry the block.CLAUDE.md.Note: a running MCP server loads once at session start β after an upgrade, quit & reopen the IDE. infernoflow doctor flags a runtime/CLI version mismatch.
Capture pipeline
A protocol block in the rule files (and on Claude Code, the infernoflow-memory skill) teaches the agent when to call amp_write: on a gotcha hit, a decision, a failed fix, a pattern.
A prompt hook (Claude Code UserPromptSubmit, Cursor beforeSubmitPrompt) scans what you type for triggers (!!, retry, not working, bookmark this) and writes the entry deterministically when the AI doesn't. Text you didn't type, like subagent replies or tool output, is ignored.
A bookmark with no note reads Claude Code's on-disk transcript, distills the last ~40 turns to markdown, stores it as context on this machine only (gitignored) β no model call.
password=-style values) are redacted at the AMP writer and stored as [REDACTED:<kind>]. The filter is pattern-based β review .ai-memory/ diffs like code.Claude Code
infernoflow setup installs these into the project's .claude/ folder. They are what make memory work without you asking for it.
infernoflow-memoryLoads when work starts in a repo that has .ai-memory/. It tells the AI when to log (a gotcha, a decision with its because, a dead end, a lasting user preference, "bookmark this") and how: the MCP tools when they are available, the CLI otherwise. Memory is treated as information to verify, not instructions, and entries marked may be stale get re-checked.
memory-keeperDelegate to it at the end of a session or when you say "save what we learned". It reads the session transcript itself, checks what is already in memory so it doesn't duplicate, logs only what can't be read from the code and the diff, sends each item to the right repo, and drops a resume bookmark. A hook limits it to single infernoflow commands; it never touches application code.
SessionStart prints fresh memory into every new session: the latest bookmark, open dead ends, recent decisions and gotchas, uncommitted changes. SessionEnd leaves a local resume point (your last request, uncommitted files, open dead ends); the newest five are kept and never committed. infernoflow resume or amp_resume answers "where were we?" in one call.
Memory hygiene
Memory that is wrong or noisy is worse than none. infernoflow marks what may be outdated, cleans out noise, and tells you when it is time to tidy up.
| Problem | What infernoflow does | Command |
|---|---|---|
| An entry is about a file that changed since | Each file-specific entry records the commit it was written at. If the file changed, the entry is shown as may be stale. Resolving it removes it from AI context; it stays in history. | resolve <id> |
| Noise piles up | Commit-subject notes, exact duplicates and machine text the prompt hooks caught are archived, then removed. Automatic resume points are cleaned too. | curate --apply |
| Old notes add up | Notes, attempts and detections older than 30 days move to archive/. Gotchas, decisions, patterns and bookmarks are never aged out. | prune --apply |
status, recap and the session start point out when any of the above is worth doing and name the command. The session-start hint appears at most once a day, and the AI is told to mention it and ask before running anything. Set "maintenance" in amp.json to "suggest" (default), "auto" (noise and old notes are handled once a day, archived first; stale entries are only ever suggested, because a person decides those) or "off".
The second product
One CLI, two products. Session Memory (the default, memory-first) is everything above. Capability Contracts is an opt-in layer for teams that want CI gates on what the system does, not just its code.
log Β· ask Β· switch Β· recap Β· status Β· bookmark Β· refresh
Mass-market, viral, zero-config. The whole loop above.
context Β· check Β· git-drift + inferno/ dir (capabilities.json, scenarios). PR comments via the ronmiz/infernoflow/action@action-v3 GitHub Action β including memory added or changed in the PR.
Branch model & sync
Captures on a feature branch travel with it via git. A teammate runs git checkout feature-auth; the JSONL is there, their MCP server boots, regenerates their rule files β their AI is warm-started on your findings, no message sent.
Personal preferences in global.jsonl follow you. Point at any OS-synced folder once β infernoflow sync set ~/Dropbox/β¦ β and home β work β home just works. No infra to stand up; the OS does the sync.
Repository map
bin/infernoflow.mjs CLI router (29 commands) lib/ βββ commands/ log, ask, resume, bookmark, β curate, hook, doctor, β¦ βββ amp/io.mjs AMP read/write core βββ ruleFiles.mjs injection / refresh βββ memoryView.mjs ranking, staleness, resume βββ maintenance.mjs maintenance hints / auto βββ learning/ profile, observe, adapt βββ git/ drift detection βββ ai/ optional provider router βββ adopters/ framework adopters βββ mcpRuntime.mjs MCP runtime stamp βββ ui/ terminal output + prompts vscode-extension/ companion extension action/ GitHub Action (PR memory check) templates/ hooks, skill, agent, CI dist/ esbuild output (committed)
node build.mjs β esbuild, single pass into dist/.postinstall. npm i -g only copies files.npm test runs the vitest suite (370 tests, including security regressions).Live sidebar (ranked by file), gotchas as Problems (yellow squigglies Copilot also sees), status-bar health score, keyboard-first logging (Ctrl+Alt+G/D/A/S/R). Registers amp_write/amp_read as VS Code Language Model Tools.
Security & privacy
Asked once; nothing is sent unless you say yes. Never code, paths or memory content.
npm i -g infernoflow runs no code β it copies files.
Every default command runs entirely on your machine.
Memory, MCP config and hooks live in the project. Outside it: personal settings and keys in ~/.infernoflow/, and one entry per project in Claude Desktopβs config.
Auto-content is wrapped in markers; your edits outside are untouched.
Known token and key formats are replaced with [REDACTED] before anything is written.
Only infernoflowβs read tools are pre-approved; tools that write memory ask first.
Memory from teammates is framed as data, listed until you review it, and shown in each PR by the GitHub Action.
The memory-keeper agent may only run single infernoflow read/log commands. No shell is used to run commands.
The optional infernoflow ai setup wires a provider (Anthropic / OpenAI / Google / Ollama) for a few enrichment commands β same trust model as using that provider directly. Off by default.
Design principles
Plain files, no service, no runtime dependencies. The moat is that it's boring infrastructure β set once, forget, like .gitignore.
An open protocol, not a format lock. Any AMP-Full client needs only the amp_* tool names.
One install, everything wired β no separate setup steps, no manual rebuilds, no "now go install the other half".
infernoflow never runs your coding agent. It's the memory Cursor / Claude / Copilot read β that's the wedge, and it's deliberate.