How it works . slipstream

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.

TL;DR

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.

rendering
Inside a session: hooks emit events, tools serve precise slices, the dashboard tails the log, PreCompact writes a durable digest before the trim.
Core data flow

The read loop

rendering
Inside a turn: orient via sp_map, slice via sp_symbol, hooks update budget and dashboard.
Module map

Each module, what it owns

src/mcp

Role

Bundled MCP server (stdio).

How it actually works

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

Role

The compact project map.

How it actually works

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

Role

File-based memory store, recall and digest.

How it actually works

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

Role

Token budget and read guard.

How it actually works

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)

Role

The local SSE dashboard.

How it actually works

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)

Role

Mind map and artifact.

How it actually works

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

Role

Skill contract and loader.

How it actually works

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

Role

The status bar line.

How it actually works

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

Role

End-to-end install check.

How it actually works

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

Role

The helper entry point.

How it actually works

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

Role

Manifest validator.

How it actually works

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.

Session lifecycle

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.

On-disk layout

What lives in your project

Everything slipstream writes goes under .claude/slipstream/. Git-ignored by default; commit only what you want shared.

PathContents
.claude/slipstream/map.mdThe compact project map, regenerable. Files, exported symbols, one-line purpose.
.claude/slipstream/map.jsonThe same map in structured form for sp_map and the mind map builder.
.claude/slipstream/memory/<id>.mdOne Markdown fact per file, with frontmatter (id, tags, created, source).
.claude/slipstream/memory/MEMORY.mdA regenerated index of every fact. Drift-proof because it is rebuilt from the files.
.claude/slipstream/dashboard/<session>.jsonlOne append-only event log per session. State is a pure fold over the file.
.claude/slipstream/dashboard/server.jsonThe running server's port and PID, used by idempotent start.
.claude/slipstream/dashboard.jsonOptional settings: enabled, autoOpen.
Design trade-offs

Why this, not that

Hand-rolled MCP server, not the SDK

Why I made this call

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.

What it costs

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

Why I made this call

Append-only by construction, tailable, human-readable when something goes wrong, and replay is free: state is a pure fold over the log.

What it costs

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

Why I made this call

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.

What it costs

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

Why I made this call

Reviewable, diffable, survives without a running service. The index is regenerated from the files, so it cannot silently drift.

What it costs

No SQL queries over memory. Recall is signal-ranked at session start, which is what we actually need.

Signal-ranked recall, not load-everything

Why I made this call

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.

What it costs

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

Why I made this call

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.

What it costs

It is guidance, not a guarantee, and the wording everywhere says so. Conservative on purpose, so it warns early.

Performance and the test suite

What you can measure

71%
fewer tokens, sp_symbol vs whole-file Read
retrieve.ts, 1,381 vs 4,841 bytes
5.4%
cost of orienting via sp_map
vs reading every file in src/
88
tests across 11 files
~2.1s on Apple Silicon, Node 25

Failure modes you should expect

Two hook processes race on the event log
Cause: Two lifecycle hooks fire close together (e.g. PostToolUse then PreToolUse)
Fix: log.ts holds a small advisory lock around the write, so sequence numbers do not collide. Tested under 25 parallel writers.
Dashboard URL does not appear
Cause: Dashboard disabled by setting or env var
Fix: Check .claude/slipstream/dashboard.json or SLIPSTREAM_DASHBOARD. Run /slipstream:doctor to confirm the start path is reachable.
Session resumes from a lossy summary
Cause: PreCompact hook is not wired
Fix: Doctor checks the PreCompact hook on every run. If it is missing, the plugin manifest is out of date; reinstall or re-add the marketplace entry.
sp_symbol returns nothing
Cause: Symbol name does not match a top-level declaration in the file
Fix: Fall back to sp_lines with the location from sp_search, which returns ranked locations without contents.
Memory recall feels random at session start
Cause: No task signal yet: empty branch, clean working tree, no last prompt
Fix: That is by design. Recall returns nothing and defers to MEMORY.md so the agent can navigate the index itself.
Statusline shows wrong skill
Cause: Skill changed after the statusline cache was written
Fix: formatStatusline is pure; the cache is the input. The CLI rewrites it on every PostToolUse, so the next tool call corrects it.
Future direction

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.