Repository-scoped learning system for Claude Code
npm install learning-agentA repository-scoped learning system that helps Claude Code avoid repeating mistakes across sessions. Captures lessons from corrections and retrieves them when relevant.
Claude Code forgets lessons between sessions. This leads to:
- Repeated mistakes across sessions
- Users re-explaining preferences
- No memory of what worked or failed
Learning Agent solves this by capturing lessons when corrections happen and retrieving relevant ones at session start and plan time.
``bashUsing pnpm (recommended)
pnpm add -D learning-agent
> Warning: Do NOT install from GitHub URL (e.g.,
pnpm add github:user/learning-agent).
> GitHub installs don't include the compiled dist/ folder, which will cause all CLI
> commands and hooks to fail. Always install from npm registry as shown above.$3
After installation, run the setup command to configure everything:
`bash
npx lna setup
`This single command:
- Creates
.claude/lessons/ directory
- Adds AGENTS.md with workflow instructions (prioritizes MCP over CLI)
- Installs Claude Code hooks (SessionStart, PreCompact) in .claude/settings.json
- Registers MCP server in .mcp.json for lesson_search and lesson_capture tools
- Installs git pre-commit hook for lesson reminders
- Downloads the embedding model (~278MB)To skip the model download (if you'll do it later):
`bash
npx lna setup --skip-model
`$3
- Node.js >= 20
- ~278MB disk space for embedding model
- ~150MB RAM for embedding operations
Quick Start
`bash
Install dependencies
pnpm installBuild
pnpm buildRun tests
pnpm testDownload embedding model (first use)
pnpm download-model
`Development
$3
| Script | Duration | Tests | Use Case |
|--------|----------|-------|----------|
|
pnpm test:fast | ~6s | 385 | Rapid feedback during development |
| pnpm test | ~60s | 653 | Full suite before committing |
| pnpm test:changed | varies | varies | Only tests affected by recent changes |
| pnpm test:watch | - | - | Watch mode for TDD workflow |
| pnpm test:all | ~60s | 653 | Full suite with model download |Recommended workflow:
1. Use
pnpm test:fast while coding for rapid feedback
2. Run pnpm test before committing
3. CI runs the full suite$3
The CLI integration tests spawn Node.js processes (~400ms overhead each) and account for 95% of test time.
test:fast skips these, running only unit tests that verify all business logic.Architecture
`
project_root/
|-- .mcp.json <- MCP server config (project scope)
|-- AGENTS.md <- Workflow instructions for Claude
+-- .claude/
|-- settings.json <- Claude Code hooks (SessionStart, PreCompact)
|-- CLAUDE.md <- Always loaded (permanent rules)
|-- lessons/
| |-- index.jsonl <- Source of truth (git-tracked)
| +-- archive/ <- Old lessons (compacted)
+-- .cache/
+-- lessons.sqlite <- Rebuildable index (.gitignore)
`$3
`
+----------+ +----------+ +----------+ +----------+
| Mistake |--->| Claude |--->| Quick |--->| Stored |
| happens | | notices | | confirm | | lesson |
+----------+ +----------+ +----------+ +----------+
| |
(or user (MCP or
corrects) --yes)+----------+ +----------+ +----------+
| Next |<---| Retrieve |<---| Session |
| task | | relevant | | start |
+----------+ +----------+ +----------+
`Features
- MCP Integration: Native Claude tools (
lesson_search, lesson_capture) via MCP server
- Lesson Capture: Capture lessons after user corrections, self-corrections, or discoveries
- Quality Filter: Prevents vague or obvious lessons (must be novel, specific, actionable)
- Vector Search: Local semantic search using EmbeddingGemma-300M via node-llama-cpp
- Hybrid Storage: JSONL source of truth (git-tracked) with SQLite FTS5 index (rebuildable)
- Offline First: No external API dependencies; works completely offline
- Hook System: SessionStart/PreCompact load context, git pre-commit reminds to captureCLI Usage
`bash
Capture a lesson manually
pnpm learn "Use Polars for large files, not pandas"Capture with citation (file:line provenance)
learning-agent learn "API requires auth header" --citation src/api.ts:42Search lessons
learning-agent search "data processing"List all lessons
learning-agent listList only invalidated lessons
learning-agent list --invalidatedMark a lesson as wrong/invalid
learning-agent wrong L12345678 --reason "This advice was incorrect"Re-enable an invalidated lesson
learning-agent validate L12345678Show database stats (includes age distribution)
learning-agent statsRebuild index from JSONL
learning-agent rebuildCompact and archive old lessons
learning-agent compact
`Claude Code Integration
$3
The
lna setup command configures everything automatically:`bash
npx lna setup
`This installs:
- MCP Server: Exposes
lesson_search and lesson_capture as native Claude tools
- SessionStart hook: Loads workflow context when Claude starts
- PreCompact hook: Reloads context before compaction
- Git pre-commit hook: Reminds to capture lessons before commits$3
If you prefer to configure hooks manually, add to
.claude/settings.json:`json
{
"hooks": {
"SessionStart": [
{
"matcher": "",
"hooks": [
{ "type": "command", "command": "npx lna prime 2>/dev/null || true" }
]
}
],
"PreCompact": [
{
"matcher": "",
"hooks": [
{ "type": "command", "command": "npx lna prime 2>/dev/null || true" }
]
}
]
},
"mcpServers": {
"learning-agent": {
"command": "npx",
"args": ["learning-agent-mcp"]
}
}
}
`The git pre-commit hook is installed separately via
npx lna init and runs lna remind-capture before commits.
`$3
| Tool | Purpose |
|------|---------|
|
lesson_search | Search lessons before architectural decisions |
| lesson_capture | Capture lessons after corrections or discoveries |$3
| Command | Purpose |
|---------|---------|
|
prime | Load workflow context and high-severity lessons |
| remind-capture | Prompt to capture lessons before commit |$3
`bash
Check integration status
npx lna setup claude --statusRemove hooks
npx lna setup claude --uninstallPreview changes
npx lna setup claude --dry-run
`API Reference
`typescript
import {
// Storage
appendLesson, readLessons, searchKeyword, rebuildIndex, closeDb, // Search
searchVector, cosineSimilarity, rankLessons,
// Capture
shouldPropose, isNovel, isSpecific, isActionable,
detectUserCorrection, detectSelfCorrection, detectTestFailure,
// Retrieval
loadSessionLessons, retrieveForPlan, formatLessonsCheck,
// Types
type Lesson, LessonSchema, generateId,
} from 'learning-agent';
`See examples/ for usage examples.
Lesson Schema
Lessons are stored as JSONL records with the following schema:
$3
All lessons must have these fields:
| Field | Type | Description |
|-------|------|-------------|
|
id | string | Unique identifier (e.g., "L12345678") |
| type | "quick" \| "full" | Lesson complexity level |
| trigger | string | What caused the lesson (context/situation) |
| insight | string | What was learned (the takeaway) |
| tags | string[] | Categorization tags |
| source | string | How it was captured (user_correction, self_correction, test_failure, manual) |
| context | object | Tool/intent context |
| created | ISO string | Creation timestamp |
| confirmed | boolean | Whether user confirmed the lesson |$3
| Field | Type | Description |
|-------|------|-------------|
|
evidence | string | Supporting evidence (full lessons only) |
| severity | "high" \| "medium" \| "low" | Importance level (separate from type) |
| citation | object | File/line reference (file, line, commit) |Note: The
severity field is separate from type. A quick lesson can have high severity, and a full lesson can have low severity.$3
At session start, lessons are loaded based on:
- High severity lessons are always loaded
- Confirmed lessons are prioritized
- Only non-invalidated lessons are included
$3
`json
{
"id": "L12345678",
"type": "full",
"trigger": "API returned 401 despite valid JWT token",
"insight": "Auth API requires X-Request-ID header in all requests",
"evidence": "Traced in network tab, discovered missing header requirement",
"severity": "high",
"tags": ["api", "auth", "headers"],
"source": "test_failure",
"context": { "tool": "fetch", "intent": "API authentication" },
"created": "2024-01-15T10:30:00.000Z",
"confirmed": true,
"citation": { "file": "src/api/client.ts", "line": 42 }
}
`Lesson Types
$3
`json
{
"id": "L001",
"type": "quick",
"trigger": "Used pandas for 500MB file",
"insight": "Polars 10x faster",
"tags": ["performance", "polars"],
"source": "user_correction"
}
`$3
`json
{
"id": "L002",
"type": "full",
"trigger": "Auth API returned 401 despite valid token",
"insight": "API requires X-Request-ID header",
"evidence": "Traced in network tab, header missing",
"severity": "high",
"source": "test_failure"
}
`$3
`json
{
"id": "L001",
"type": "quick",
"trigger": "Used pandas for 500MB file",
"insight": "Polars 10x faster",
"tags": ["performance", "polars"],
"source": "user_correction",
"deleted": true,
"deletedAt": "2026-01-30T12:00:00Z"
}
`Deletion is append-only: a lesson is soft-deleted by appending a full lesson record with
deleted: true and deletedAt.
For backward compatibility, legacy minimal tombstones ({ id, deleted: true, deletedAt }) are still accepted on read.Schema types:
-
LessonSchema: Full lesson structure
- LessonRecordSchema: Union of LessonSchema and legacy minimal tombstone format (used when reading JSONL)Technology Stack
| Component | Technology |
|-----------|------------|
| Language | TypeScript (ESM) |
| Package Manager | pnpm |
| Build | tsup |
| Testing | Vitest |
| Storage | better-sqlite3 + FTS5 |
| Embeddings | node-llama-cpp + nomic-embed-text-v1.5 |
| CLI | Commander.js |
| Schema | Zod |
Development
`bash
Watch mode (rebuild on changes)
pnpm devRun tests in watch mode
pnpm test:watchType checking
pnpm lint
`Project Status
Version 0.2.8 - Hook UX improvements and smarter failure detection. Key features:
- MCP Server:
lesson_search and lesson_capture as native Claude tools (primary interface)
- Smart hooks: UserPromptSubmit (correction/planning detection), PostToolUseFailure (smart failure tracking)
- Pre-commit checkpoint: Checklist-format reflection prompt before commits
- MCP-first workflow: AGENTS.md and prime output prioritize MCP tools over CLISee CHANGELOG.md for details.
Documentation
| Document | Purpose |
|----------|---------|
| doc/SPEC.md | Complete specification |
| doc/CONTEXT.md | Research and design decisions |
| doc/PLAN.md | Implementation plan |
| AGENTS.md | Agent instructions overview |
| .claude/CLAUDE.md | Claude Code project instructions |
| doc/test-optimization-baseline.md | Test performance metrics |
Testing
$3
Tests are organized for parallelization:
`
src/
├── *.test.ts # Unit tests (fast)
├── cli/ # CLI integration tests (split by command)
│ ├── cli-test-utils.ts # Shared utilities
│ ├── learn.test.ts
│ ├── search.test.ts
│ └── ...
├── storage/ # Storage layer tests
├── embeddings/ # Embedding model tests (skipped if model unavailable)
└── ...
`$3
Embedding concurrency: The
node-llama-cpp` native addon may crash under heavy parallel load. This is a known limitation of the underlying C++ library. Tests pass reliably under normal conditions.Timing-based tests: Some tests verify performance thresholds. These use generous limits (5000ms) to avoid flakiness on slow CI machines.
MIT