πŸ”₯

infernoflow

v0.50.0

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.

runtime deps 0 storage JSONL on disk protocol AMP (open) transports MCP Β· LMT Β· CLI telemetry opt-in, off license MIT

The problem

Every AI session starts cold

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.

Re-derivation

Each session re-reads the code and re-infers the obvious, burning tokens and wall-clock.

Repeated mistakes

The same wrong turn someone hit yesterday gets made again β€” the gotcha never persisted.

Lost decisions

"Why opaque tokens, not JWTs?" β€” the rationale lived in a chat that's gone.

System overview

Four layers, one disk file

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).

Clients β€” AI agents
Claude Code
hooks Β· skill Β· agent
Cursor
reads .cursorrules
GitHub Copilot
copilot-instructions.md
Windsurf
.windsurfrules
β–²   read / write   β–Ό
Transports β€” same memory everywhere
MCP server
amp_* Β· infernoflow_*
VS Code LMT
#amp_write / #amp_read
CLI
log Β· ask Β· switch Β· bookmark
Rule files
injected, marker-managed
β–²     β–Ό
Core engine β€” deterministic, zero-dep
AMP writer / reader
lib/amp/io.mjs
Injection / refresh
ruleFiles.mjs
Learning profile
lib/learning/*
Git drift
lib/git/*
Clean-tree policy
cleanTree.mjs
Memory view
memoryView.mjs: ranking, staleness, resume
Maintenance
maintenance.mjs
β–²     β–Ό
Storage β€” plain files, git-tracked
.ai-memory/branches/*.jsonl
per-branch, travels via git
details.jsonl
tier-2 rich bodies
global.jsonl
personal, gitignored
amp.json
config
The same 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

Capture β†’ Link β†’ Persist β†’ Restore

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.

01
Capture
A gotcha, decision, failed attempt or pattern is worth saving. The AI calls amp_write; a Cursor prompt-hook backstops it deterministically.
β†’
02
Link
Each moment becomes a structured AMP entry β€” type, file:line, tags, timestamp, a stable AMP id.
β†’
03
Persist
Entries land in branches/<branch>.jsonl (git-tracked) or global.jsonl (personal). Travels with the branch.
β†’
04
Restore
Next session, the agent reads the rule files at boot β€” the most relevant entries are already there. Warm start.

Data flow

The closed memory loop

How a single finding travels the whole system β€” from the moment it surfaces to the next session that starts warm because of it.

THE MEMORY LOOP warm start, no cold derivation MCP boot / session start 1 You + AI work a gotcha / decision surfaces 2 Capture amp_write Β· MCP / hook 3 Persist .ai-memory/*.jsonl (git) 4 Refresh regenerate rule files 5 Rule files session hook Β· .cursorrules 6 Next session AI reads at boot

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

Everything is a typed AMP entry

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.

Entry schema

// 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
}

Entry types & retention

TypeMeaningAuto-prune?
gotchaAn invariant that bit younever
decisionA standing choice + rationalenever
patternHow things are done herenever
preferenceA durable user preference (personal, global.jsonl)never
attemptA fix that failed30d
noteTransient observation30d
detectionAuto-detected signal30d

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.

Two-tier bodies

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

One directory, git-native

.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

Why plain JSONL on disk

  • Git is the sync + merge engine. Branch memory travels with the branch; teammates inherit it on checkout.
  • merge=union on the branch JSONLs means concurrent commits from two machines merge cleanly β€” no conflict resolution.
  • No lock-in. It's readable text; grep it, diff it, delete it. No SaaS to leave.
  • Append-only writes keep the working tree calm; rule files refresh only at MCP boot / explicit refresh.

Transports & integration

Same memory, every tool

ToolReads fromWrites via
Claude CodeSessionStart hook (fresh each session) + .claude/ skillMCP (amp_write) + memory-keeper agent
Cursor.cursorrulesMCP + beforeSubmitPrompt hook
GitHub Copilot (VS Code).github/copilot-instructions.mdVS Code LMT + MCP β€” both wired
Windsurf.windsurfrulesMCP (manual wiring)

MCP tool surface

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).

amp_writeamp_readamp_search amp_bookmarkamp_handoffamp_healthamp_resume infernoflow_status infernoflow_git_drift

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

Rule files stay current, and lean

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.

Marker-scoped, budget-bounded

<!-- 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).

Refresh triggers

  • MCP server boot β€” the canonical moment rule files regenerate from memory.
  • infernoflow refresh β€” manual rebuild; --targets controls which files carry the block.
  • Claude Code session start β€” a hook prints fresh memory into each new session, so Claude Code doesn't depend on a copy in CLAUDE.md.
  • Content-hash guard β€” only rewrites when content actually changed, so the tree stays clean.

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

The AI writes it β€” with a deterministic backstop

1 Β· AI-driven

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.

2 Β· Hook backstop

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.

3 Β· Transcript distillation

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.

Known secret formats (API keys and tokens, JWTs, private keys, credentials in URLs, 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

A skill, an agent and two session hooks

infernoflow setup installs these into the project's .claude/ folder. They are what make memory work without you asking for it.

Skill Β· infernoflow-memory

Loads 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.

Agent Β· memory-keeper

Delegate 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.

Session hooks

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.

Cursor & Copilot get the same "when to capture" guidance through their rule-file protocol + MCP.

Memory hygiene

Memory that stays worth reading

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.

ProblemWhat infernoflow doesCommand
An entry is about a file that changed sinceEach 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 upCommit-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 upNotes, attempts and detections older than 30 days move to archive/. Gotchas, decisions, patterns and bookmarks are never aged out.prune --apply

Maintenance hints

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

Capability Contracts β€” opt-in

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.

Session Memory Β· default

log Β· ask Β· switch Β· recap Β· status Β· bookmark Β· refresh
Mass-market, viral, zero-config. The whole loop above.

Capability Contracts Β· init --mode full

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

Memory that travels β€” with the branch, and across machines

Branch-aware (team)

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.

Cross-machine (personal)

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

Components & build

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)

Build & test

  • Bundler: node build.mjs β€” esbuild, single pass into dist/.
  • Zero runtime deps: Node β‰₯ 18, no postinstall. npm i -g only copies files.
  • Tests: npm test runs the vitest suite (370 tests, including security regressions).
  • Extension: window-only in 0.7.9+ β€” the CLI is the single canonical writer of rule files, so there's no race.

VS Code extension surface

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

Local-first by construction

βœ…

Telemetry opt-in, off by default

Asked once; nothing is sent unless you say yes. Never code, paths or memory content.

🚫

No postinstall

npm i -g infernoflow runs no code β€” it copies files.

🚫

No network in default path

Every default command runs entirely on your machine.

βœ…

Per-project wiring

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.

βœ…

Marker-bounded edits

Auto-content is wrapped in markers; your edits outside are untouched.

βœ…

Secrets redacted

Known token and key formats are replaced with [REDACTED] before anything is written.

βœ…

Read-only pre-approval

Only infernoflow’s read tools are pre-approved; tools that write memory ask first.

βœ…

Review what arrives

Memory from teammates is framed as data, listed until you review it, and shown in each PR by the GitHub Action.

βœ…

Guarded agent

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

What holds it together

πŸ”’ Local-first, zero-dep

Plain files, no service, no runtime dependencies. The moat is that it's boring infrastructure β€” set once, forget, like .gitignore.

πŸ”Œ Vendor-neutral (AMP)

An open protocol, not a format lock. Any AMP-Full client needs only the amp_* tool names.

⚑ Transparent automation

One install, everything wired β€” no separate setup steps, no manual rebuilds, no "now go install the other half".

🎯 It feeds agents, it isn't one

infernoflow never runs your coding agent. It's the memory Cursor / Claude / Copilot read β€” that's the wedge, and it's deliberate.