Local-first memory for AI coding sessions.
Git remembers what changed. Whyline remembers why.
You've been there. You open a file, see a decision made months ago, and have no idea why. The diff shows what changed. The commit message says "fix retention logic." But why 90 days? Why a background job and not a cron? Why not S3?
That context lived in a conversation — and it's gone.
AI coding sessions with tools like Claude produce something valuable beyond the code: the reasoning behind it. The intent, the tradeoffs, the alternatives that were rejected, the risks that were acknowledged. None of that ends up in git. It lives in a chat window and disappears when the context resets.
Whyline captures it.
After each coding session, it stores a concise reasoning record in SQLite on your machine — no cloud, no auth, no new workflow. When you start a new session touching the same files, Claude searches those records automatically and surfaces the relevant context:
"Last time we touched this file, we rejected S3 archival because of cost. Still the case?"
The loop is tight:
- Start a task → Claude searches past memories and brings forward relevant decisions
- Finish and commit → Claude synthesizes the session and saves the reasoning automatically
- Come back later → The why is right there, not lost in a chat history
It works through Claude Code's MCP protocol. Two files to set it up in any repo: .mcp.json and CLAUDE.md.
npm view @malindar/whyline version
npm install -g @malindar/whyline
whyline --help
whyline doctorNode 18 or later. The native better-sqlite3 bindings must be compiled for your Node version:
npm rebuild better-sqlite3whyline init
whyline install-claude
whyline doctorCreates ~/.whyline/ with memory.db and config.json.
Run this once in each repo you want Whyline to work in:
cd your-project
whyline install-claudeCreates or updates three files:
.mcp.json— registers the Whyline MCP server (merges with existing entries)CLAUDE.md— adds the memory instructions for Claude (appends if the file already exists).claude/settings.local.json— auto-approves the five MCP tool calls so Claude doesn't prompt on every use
✓ .mcp.json (created)
✓ CLAUDE.md (created)
✓ .claude/settings.local.json (created)
Done. Open this repo in Claude Code and run `whyline doctor` to verify.
Running it again is safe — it only writes what's missing and never removes existing content.
whyline doctorChecks that the DB exists, migrations are current, the binary is on your PATH, you're inside a git repo, .mcp.json is configured, CLAUDE.md mentions Whyline, and the MCP server starts. Run this whenever something feels off.
✓ DB exists (~/.whyline/memory.db)
✓ Migrations current (v1)
✓ `whyline` on PATH (/usr/local/bin/whyline)
✓ Inside a git repo (/home/user/my-app)
✓ .mcp.json configured (/home/user/my-app/.mcp.json)
✓ CLAUDE.md mentions Whyline (/home/user/my-app/CLAUDE.md)
✓ MCP server starts (tools/list responded)
All checks passed. Whyline is ready.
Create memory.md in your project:
# Memory
Intent:
Add optimistic comment rendering.
Summary:
Implemented optimistic rendering for new comments so they appear immediately.
Decision:
Render comments immediately and reconcile after server ack.
Why:
Waiting for server confirmation made comment creation feel slow.
Alternatives rejected:
- Server-confirmed rendering only.
- Polling for new comments after submit.
Risks:
- Duplicate comments during reconnect.
- Failed server ack needs rollback UI.
Follow-ups:
- Add dedupe reconciliation tests.
- Add failed-send retry state.
Tags:
- comments
- sync
- optimistic-uiwhyline save --commit HEAD --summary-file memory.mdOutput:
Saved memory mem_abc12345
Repo: my-app
Commit: abc12345
Files: 3
whyline search "why optimistic comments?"
whyline search "refresh token" --file src/auth/session.ts
whyline search "checkout validation" --limit 5
# Filter by tag (repeat for AND semantics)
whyline search "" --tag auth --tag security
# Filter by date
whyline search "" --since 2025-01-01
whyline search "" --before 2025-06-30
whyline search "token" --tag auth --since 2025-01-01 --before 2025-12-31whyline list # all memories, newest first
whyline list --repo # scoped to the current git repo
whyline list --limit 5 # cap resultswhyline show mem_abc12345
whyline show --commit abc12345Open a memory in $EDITOR as markdown, save changes back to the DB:
whyline edit mem_abc12345whyline delete mem_abc12345 # prompts for confirmation
whyline delete mem_abc12345 --force # skips confirmation# Export all memories as JSON (default)
whyline export > backup.json
# Export as markdown
whyline export --format md --output memories.md
# Export only this repo's memories, filtered by tag and date
whyline export --repo --tag auth --since 2025-01-01 --output auth-memories.json
# Import from a previous export (skips duplicates, redacts any exposed secrets)
whyline import backup.jsonwhyline statsOutput:
Total memories: 42
Repos tracked: 3
Oldest memory: 1/15/2025
Newest memory: 5/13/2026
Most referenced files:
12x src/auth/session.ts
8x src/comments/sync.ts
5x src/db/migrations.ts
whyline mcpAdd .mcp.json to your repo root:
{
"mcpServers": {
"whyline": {
"command": "whyline",
"args": ["mcp"]
}
}
}Then add the skill to Claude Code by referencing src/skill/SKILL.md in your project's CLAUDE.md.
The parser is forgiving — missing fields fall back to safe defaults.
Supported headings:
| Heading | Type | Default |
|---|---|---|
Task: |
text | (omitted) |
Intent: |
text | "Unspecified intent" |
Summary: |
text | (full file content) |
Decision: |
text | "Unspecified decision" |
Why: |
text | "Unspecified rationale" |
Alternatives rejected: |
bullet list | [] |
Risks: |
bullet list | [] |
Follow-ups: |
bullet list | [] |
Tags: |
bullet list | [] |
Claude Code can call these tools via the MCP server:
| Tool | Description |
|---|---|
search_coding_memory |
Search memories by keyword |
save_coding_memory |
Save a new memory |
get_commit_memory |
Get memories for a specific commit |
get_file_memories |
Get memories touching a specific file |
All text is automatically scanned before saving. The following are redacted and replaced with [REDACTED_SECRET]:
- GitHub tokens (
ghp_,gho_,ghs_) - npm tokens (
npm_) - AWS access keys (
AKIA...) - Bearer tokens
.env-style secrets (API_KEY=,SECRET=, etc.)- PEM private key blocks
Copy src/hooks/post-commit.sample.sh to .git/hooks/post-commit and make it executable:
cp src/hooks/post-commit.sample.sh .git/hooks/post-commit
chmod +x .git/hooks/post-commitThis reminds you to save a memory after each commit.
npm run dev -- init # run via tsx without building
npm test # run tests
npm run build # compile to dist/
npm run lint # eslintAll data is stored locally at ~/.whyline/memory.db (SQLite). The repository is never modified unless you explicitly install the post-commit hook.
- v0.6 —
--manualinteractive save mode - v0.6 — GitHub PR integration
- v0.7 — team-shared memory server
