How slipstream works
Eleven modules. Seven lifecycle hooks. One append-only event log that doubles as replay. The whole helper compiles to a single dist tree the plugin manifest points at.
A map and a slice in,
a durable digest out,
live on the side.
The agent orients with sp_map, pulls one slice with sp_symbol or sp_lines, and writes durable facts with sp_remember. Every lifecycle event lands in an append-only JSONL log.
The dashboard tails the log over SSE and folds it into agents, activity, budget and a mind map. Replay is the same fold over a finished log. Nothing leaves the machine.
Just before the IDE compacts, a hook writes a structured digest of the session to memory. Next session, recall loads the digest plus a signal-ranked relevant subset, never the whole store.
The read loop
Each module, what it owns
src/mcp
Bundled MCP server (stdio).
tools.ts defines the nine sp_ tools and callTool, each a thin wrapper over the same library the helper CLI uses. server.ts is the pure handleRequest dispatcher plus a newline-delimited JSON-RPC stdio loop. index.ts is the entry point the IDE spawns. The protocol slice in play is small and stable: initialize, tools/list, tools/call. Tests drive handleRequest directly without spawning a process; a separate suite spawns the real binary over stdio.
src/map
The compact project map.
generateMap reads each source file once, extracts the exported surface and a one-line purpose with a cheap line scan, and never stores file contents. retrieveSymbol walks braces from a declaration line to return one slice. retrieveLines returns a bounded range. searchMap ranks files by a query. The whole module is a fast heuristic on purpose: the agent decides where to look from the map, then reads the real slice.
src/memory
File-based memory store, recall and digest.
store.ts is one Markdown file per fact under .claude/slipstream/memory/ with frontmatter, plus a regenerated MEMORY.md index (addMemory, pruneMemory, listMemories, recallMemories, regenerateIndex). recall.ts ranks the store against a task signal (rankBySignal, selectRelevant) and returns only the subset that fits a token budget. digest.ts builds the PreCompact session digest (buildDigest, digestToMemory).
src/context
Token budget and read guard.
estimateTokens converts bytes to a conservative token count (3.6 bytes per token). budget reports an ok / warn / compact level against the window. guardRead flags large whole-file reads, which the PreToolUse hook surfaces as a warning before the read happens.
src/dashboard (live server)
The local SSE dashboard.
events.ts defines and redacts the event schema. log.ts is the concurrency-safe append-only writer and reader (tested under 25 parallel writers). state.ts folds events into agent state, the same fold that drives live view and replay. server.ts is the node:http server with SSE. launch.ts is idempotent start and browser open. runner.ts is the detached process entry point.
src/dashboard (mind map)
Mind map and artifact.
buildMindMap turns the project map into a tree. mindMapToMermaid renders it as a themed Mermaid flowchart for the chat. renderArtifact writes a self-contained HTML file you can share.
src/engine
Skill contract and loader.
skillFrontmatterSchema enforces the plugin name and description plus a namespaced slipstream block (category, requires, verification gate, tags). loadSkills walks skills/**/SKILL.md, aggregates every issue, checks the directory name matches the skill name, and rejects shipping skills without a gate.
src/statusline
The status bar line.
formatStatusline renders the one-line status (budget level, durable memory count, active skill, model) as a pure function. The formatting is pinned by a snapshot test so changes are intentional.
src/doctor
End-to-end install check.
runDoctor checks the MCP server is built and declared, every hook (including PreCompact) is wired, the memory directory exists, the helper CLI is built, the statusline and output style are present, the subagents are loadable, and the plugin manifest is valid. renderDoctor prints PASS / FAIL per check. Backs /slipstream:doctor.
src/cli
The helper entry point.
A single dispatcher invoked by the hooks and the slash commands. Subcommands: map, slice, lines, guard, budget, memory, mindmap, status, dashboard, validate, plugin-validate, doctor, statusline, recall-signal, digest.
src/plugin-validate
Manifest validator.
Proves the plugin is well-formed: every declared hook script exists, every declared MCP server has an entry point, every subagent has a name, every command file is loadable. Fails loudly on the smallest drift.
Every hook, what it emits
SessionStart
The hook boots the dashboard server (idempotent, reuses a running one) and writes a SessionStart event. Recall builds a task signal from git branch + working-tree changes + last prompt, ranks memories against it, and emits the relevant subset plus the MEMORY.md index. The PreCompact digest from a prior session, if any, is reloaded first.
UserPromptSubmit
The hook writes a UserPromptSubmit event so the dashboard activity stream picks it up. The agent is nudged, via a system reminder, to orient with sp_map and to recall durable memory before opening files.
PreToolUse
For every tool call, the hook writes a PreToolUse event. guardRead inspects whole-file Read calls and, if the file is large, warns the agent and suggests sp_symbol or sp_lines instead. The dashboard groups events under the agent that issued them.
PostToolUse
The hook writes a PostToolUse event with the result, redacted by events.ts before it touches the log. The budget estimator updates the dashboard token-budget bar by adding the bytes that the tool returned into context.
SubagentStop
The dashboard flips the subagent's status to done (or failed) and folds its final state into the per-agent view. Because the only reliable subagent signal is SubagentStop, the dashboard infers a subagent from the first event that names it and flips status on stop.
PreCompact
Just before the IDE summarises and trims, the hook reconstructs the open task, decisions, files touched and next step from the dashboard event log (digest.ts), and writes a structured durable fact to the memory store. The next session loads it first.
Stop
On session end, the hook nudges the agent to write any remaining durable facts via sp_remember, then writes a Stop event. The session log remains on disk for replay; the dashboard session picker switches between recorded sessions.
What lives in your project
Everything slipstream writes goes under .claude/slipstream/. Git-ignored by default; commit only what you want shared.
| Path | Contents |
|---|---|
| .claude/slipstream/map.md | The compact project map, regenerable. Files, exported symbols, one-line purpose. |
| .claude/slipstream/map.json | The same map in structured form for sp_map and the mind map builder. |
| .claude/slipstream/memory/<id>.md | One Markdown fact per file, with frontmatter (id, tags, created, source). |
| .claude/slipstream/memory/MEMORY.md | A regenerated index of every fact. Drift-proof because it is rebuilt from the files. |
| .claude/slipstream/dashboard/<session>.jsonl | One append-only event log per session. State is a pure fold over the file. |
| .claude/slipstream/dashboard/server.json | The running server's port and PID, used by idempotent start. |
| .claude/slipstream/dashboard.json | Optional settings: enabled, autoOpen. |
Why this, not that
Hand-rolled MCP server, not the SDK
The slice of MCP in play is initialize + tools/list + tools/call. A plugin that bundles a server should add as little as possible to a user's install. The handler is a pure exported function, so tests drive it without a process.
I write the JSON-RPC framing myself. The benefit is zero runtime dependencies on the MCP path and a server I can audit in one file.
Append-only JSONL event log, not SQLite
Append-only by construction, tailable, human-readable when something goes wrong, and replay is free: state is a pure fold over the log.
Hand-rolled concurrency control via a small advisory lock in log.ts, tested under 25 parallel hook processes.
Server-sent events over node:http, not WebSocket on Express
The dashboard traffic is one-directional and SSE reconnects on its own. node:http is the standard library and serves one page, two JSON routes and one event stream in one file.
A tiny hand-written router. No Express tree to keep secure and in sync with the rest of the plugin build.
Files for memory, not a database
Reviewable, diffable, survives without a running service. The index is regenerated from the files, so it cannot silently drift.
No SQL queries over memory. Recall is signal-ranked at session start, which is what we actually need.
Signal-ranked recall, not load-everything
Loading the full store gets more expensive the more useful the store becomes. Ranking against a cheap task signal keeps recall cost flat in store size.
With no signal, recall loads nothing and defers to MEMORY.md. That is the design: loading arbitrary facts with no signal is the very thing the helper is built to avoid.
Byte-count budget estimate, not a real token meter
The helper cannot read the IDE's internal token counter, so it estimates from bytes-into-context at a cautious 3.6 bytes per token.
It is guidance, not a guarantee, and the wording everywhere says so. Conservative on purpose, so it warns early.
What you can measure
Failure modes you should expect
What is next
All on the roadmap in the wiki. No hosted version, no telemetry, no accounts: the design constraint is "if it phones home, it is not slipstream".
Compaction timeline on the dashboard
A horizontal track that shows where the session was compacted and what was offloaded, so resumed sessions are explicit about what changed.
Per-agent diff view
For each agent, a per-step diff of the files it touched, rendered from the existing PostToolUse events. No new persistence.
Shareable session artifact
Export a session log as a self-contained HTML file, the same shape as the existing mind map artifact. Send a colleague the whole walk-through.
A real SubagentStart signal
If the IDE adds an explicit SubagentStart event, the dashboard will wire it. Until then, status is inferred from the first event that names the subagent.
Ready to run it?
Add the marketplace, install the plugin, open the dashboard, run doctor. Five minutes from zero to your first slice.