Claude Project History MCP Server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Claude Project History MCP Server Start a new task for adding user tests"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Claude Project History MCP Server
Invisible project intelligence for Claude Code. Tracks workflows, tasks, blockers, and decisions locally. Zero Docker. Zero cloud. Just works.
Data lives in PGlite (Postgres WASM) at ~/.cph/db.
Install
git clone https://github.com/the-occom/occom-claude-project-history.git
cd occom-claude-project-history
npm install
npm run build
npm run install-hooks # wires hooks + daemon + .mcp.json + CLAUDE.mdRelated MCP server: sqlite-memory-mcp
Register with Claude Code
Daemon mode (recommended)
The install script starts a background daemon and writes .mcp.json automatically:
{
"mcpServers": {
"cph": {
"url": "http://localhost:3741/sse"
}
}
}All Claude Code instances share one daemon process with atomic writes.
Stdio mode (single-session fallback)
{
"mcpServers": {
"cph": {
"command": "node",
"args": ["/absolute/path/to/occom-claude-project-history/dist/index.js"]
}
}
}Or via npx:
{
"mcpServers": {
"cph": {
"command": "npx",
"args": ["github:the-occom/occom-claude-project-history"]
}
}
}Daemon
A long-lived background process that owns the PGlite database. All MCP clients connect via HTTP/SSE.
npm run daemon:start # spawn detached, write PID+port
npm run daemon:stop # kill by PID, clean up state files
npm run daemon:status # print running/stopped + port
npm run daemon:restart # stop + start
node scripts/daemon.js ensure # start only if not running (used by hooks)State files live at ~/.cph/:
daemon.pid— PID of running daemondaemon.port— port (default3741, scans to3751if busy)daemon.log— stdout/stderr
The first Claude Code hook invocation of the day auto-starts the daemon.
How it works
You do nothing. Claude Code does everything.
At session start, Claude Code calls cph_session_init automatically (via CLAUDE.md).
It gets back a minimal context — active tasks, open blockers, relevant decisions — under 600 tokens.
Then it works. Tasks, blockers, and decisions are recorded silently as side effects.
The hook system enforces this:
PreToolUseon Write/Edit/MultiEdit — blocks file writes if no active taskStop— surfaces incomplete tasks and open blockers at session endpost-commitgit hook — silently links commits to recent decisions
Atomic writes
State-changing tools (task_start, task_complete, task_cancel, blocker_resolve, blocker_escalate) use SELECT ... FOR UPDATE row locks inside transactions. Safe for concurrent access from multiple Claude Code sessions.
Tools
Session (call these)
Tool | When |
| Start of every session — auto via CLAUDE.md |
| When on a new branch with no workflow yet |
| Once, to set your preferred context depth |
| To verify the plugin is working |
Workflows
Tool | Description |
| Create workflow — do this once per project/branch |
| List all workflows |
| Task counts, blocker count, estimation accuracy |
| Update name, status, branch pattern |
Tasks
Tool | When |
| Before starting any discrete piece of work |
| Immediately after create — sets status + start time |
| When done — provide actual_minutes |
| Full details including subtasks + blockers |
| List tasks (paginated, summaries only) |
| Update title/description/priority |
Blockers
Tool | When |
| Immediately when blocked — before asking for help |
| When unblocked — always provide resolution text |
| When blocker needs urgent human attention |
| List open/resolved blockers |
Decisions
Tool | When |
| When choosing between approaches |
| Before any architectural choice |
| Full details on a specific decision |
| List decisions (summaries only) |
| Called by git hook automatically |
Context depth
Set once per engineer, remembered forever:
minimal = active tasks + open blockers (~300 tokens)
standard = + relevant decisions (~600 tokens) ← default
deep = + teammate activity (~1200 tokens)# In Claude Code:
cph_set_depth with depth="minimal"Retrieval design
Lists return IDs + titles only. Full content requires a specific ID lookup. This is intentional — prevents context flood on large projects.
Pattern for using decisions:
cph_decision_searchwith keyword — get IDscph_decision_getwith specific ID — get full record
Never load all decisions. Pull what you need.
Data
~/.cph/db/ ← PGlite database
~/.cph/daemon.pid ← daemon process ID
~/.cph/daemon.port ← daemon port
~/.cph/daemon.log ← daemon logs
.cph-workflow ← current project's workflow ID (gitignored)Compression runs automatically at session end:
Decisions > 30 days: rationale/alternatives discarded, title+decision kept
Completed tasks > 7 days: description discarded, timing data kept
Resolved blockers > 7 days: description discarded, title+resolution kept
Contributing
After editing TypeScript files in src/, always rebuild before testing:
npm run buildThe daemon runs from dist/, not src/. If you skip the build step, your changes won't take effect and you may get confusing version-mismatch restarts.
What's deliberately NOT here
No GraphQL — direct PGlite queries until multi-user sync is needed
No cloud sync — single-user local only; team sync is the paid tier
No ML inference — estimation intelligence is server-side (paid tier)
No semantic search — structural matching only; local LLM is enterprise tier
No auth — local tool, no auth needed
Available Tools
30 toolscph_activity_streamActivity StreamARead-onlyIdempotent
Get recent activity events for team awareness.
Shows what's been happening: tasks started/completed, decisions recorded, blockers created/resolved, sessions started.
Filter by workflow, time range, and event types.
Inputs: workflow_id, since_minutes, event_types, limit.
cph_blocker_createCreate BlockerA
Log a blocker that is preventing progress.
CALL THIS IMMEDIATELY when blocked — before asking the user, before trying workarounds. The timestamp of when you were blocked is important data. Don't record it retroactively.
Blocker types: dependency → waiting on another task, PR, or service to be ready waiting_on_human → needs human decision, approval, or response technical → technical problem with no clear solution yet external → blocked by something outside the team unclear_requirements → requirements are ambiguous other → doesn't fit above
Auto-behavior: if task_id is provided, the task status is automatically set to 'blocked'.
Inputs: workflow_id (required), title (required), blocker_type, task_id, +1 more.
cph_blocker_escalateEscalate BlockerAIdempotent
Mark a blocker as escalated — open but needs urgent attention.
Use when a blocker has been open too long and needs to be surfaced to stakeholders.
Inputs: blocker_id (required), reason (required).
cph_blocker_listList BlockersARead-onlyIdempotent
List blockers by workflow and/or status.
Call this when user asks about blockers. session_init already surfaces open blockers — don't duplicate.
Inputs: workflow_id, status, limit, offset.
cph_blocker_resolveResolve BlockerAIdempotent
Mark a blocker as resolved.
Always provide a resolution note — this is training data for predicting future blockers and is the most valuable signal in the system after actual_minutes on tasks.
Auto-behavior: if blocker has a task_id and unblock_task=true, task is set back to in_progress.
Inputs: blocker_id (required), resolution (required), unblock_task.
cph_codebase_indexIndex Codebase AreasAIdempotent
Register or update file area ownership for a workflow.
Use this during plan mode to declare which parts of the codebase are relevant to the current workflow, what their responsibilities are, and their dependencies.
Each area is a path pattern (e.g. "src/auth/**") with an optional responsibility description and dependency list.
Upserts by workflow_id + path_pattern — safe to call multiple times.
Inputs: workflow_id (required), areas (required).
cph_context_syncSync ContextARead-onlyIdempotent
Synchronize project context with the database.
Call this at the start of every session and after completing each task.
First call (or full_refresh=true): returns full context snapshot like session_init. Subsequent calls: returns only changes (deltas) since last sync, within token budget.
If a tool returns a conflict error, call this to get current state before retrying.
Args:
workflow_id: The workflow for this project (from CLAUDE.md)
cwd: Current working directory for git context
depth: How much context to load (minimal | standard | deep)
full_refresh: Force a full snapshot instead of deltas
Returns: { context, deltas, synced_at }
Inputs: workflow_id (required), cwd, depth, full_refresh.
cph_decision_attach_commitAttach Commit to Recent DecisionsAIdempotent
Internal: Called by the post-commit git hook to link recent decisions to a commit.
Do NOT call this manually. The hook calls it automatically after every commit.
Attaches commit_hash and diff_stat to decisions recorded in the last 30 minutes that don't already have a commit attached.
Inputs: workflow_id (required), commit_hash (required), diff_stat.
cph_decision_getGet DecisionARead-onlyIdempotent
Get full details of a single decision including rationale and alternatives.
Use after cph_decision_search returns relevant IDs.
Inputs: decision_id (required).
cph_decision_listList DecisionsARead-onlyIdempotent
List decisions for a workflow. Returns summary view only.
Call this when user explicitly asks to see decisions. session_init surfaces relevant ones automatically.
Inputs: workflow_id (required), tag, limit, offset.
cph_decision_recordRecord DecisionA
Record an architectural, design, or process decision.
This is the institutional memory of the project. Future sessions — and future engineers — will use this to understand why things are built the way they are.
Record a decision when:
You chose between two or more approaches
You made an assumption about requirements
The word "because" appears in your reasoning
You're doing something non-obvious that someone will question later
The post-commit hook will automatically attach the commit hash to recent decisions — you don't need to provide it manually.
Args:
workflow_id, title, decision: Required
context: What problem were you solving? What constraints existed?
rationale: Why this option over the alternatives?
alternatives_considered: Structured list of options evaluated and why rejected
trade_offs: What does this choice cost or foreclose?
tags: Comma-separated (e.g. "auth,database,performance") or array
reversibility: How hard is it to undo? (reversible | costly | irreversible)
confidence: How confident are you? (low | medium | high)
files_affected: Which files does this decision impact?
forcing_constraint: What external force required this decision now?
revisit_if: Under what conditions should this be revisited?
Inputs: workflow_id (required), title (required), decision (required), context, +13 more.
cph_decision_searchSearch DecisionsARead-onlyIdempotent
Search decisions by keyword across title, decision, context, and rationale.
CALL THIS before making any significant architectural choice to check if it was already decided. This is the primary anti-repetition tool.
Returns summary view (id + title + decision only) to preserve context budget. Use cph_decision_get for full details on a specific result.
Inputs: query (required), workflow_id, limit.
cph_detect_workflowDetect Workflow from Git ContextARead-onlyIdempotent
Detect which workflow matches the current git branch.
Call this if you don't have a workflow_id in CLAUDE.md yet, or if you're on an unfamiliar branch and want to know if a workflow already exists for it.
Returns either a matched workflow or a suggestion to create one.
Inputs: cwd.
cph_session_initInitialize Claude Project History SessionARead-onlyIdempotent
CALL THIS FIRST at the start of every Claude Code session.
Returns the minimum context needed to orient yourself: active tasks, open blockers, and decisions relevant to the files you're currently working on.
This is the ONLY tool you need to call proactively. Everything else is on-demand.
Args:
workflow_id: The workflow for this project (from CLAUDE.md)
cwd: Current working directory (pass process.cwd() equivalent)
depth: How much context to load minimal = active tasks + open blockers only (~300 tokens) standard = + relevant decisions (~600 tokens, DEFAULT) deep = + teammate activity + patterns (~1200 tokens)
Returns: SessionContext with workflow state, active work, open blockers, relevant decisions, and a hint.
After calling this, DO NOT call workflow_summary, task_list, or decision_list unless the user explicitly asks. Pull individual records on demand with their ID.
Inputs: workflow_id (required), cwd, depth.
cph_set_depthSet Retrieval Depth PreferenceAIdempotent
Set your personal retrieval depth preference for session init.
This is saved by your git email and applied automatically on every future session.
minimal = active tasks + open blockers only (fastest, smallest context cost) standard = + relevant decisions (default, recommended) deep = + teammate activity + historical patterns (use when debugging complex issues)
Inputs: depth (required), engineer_id.
cph_statusClaude Project History StatusARead-onlyIdempotent
Get overall Claude Project History status: storage summary and active workflow count.
Use this to check that the plugin is working, not to get project context. For project context, use cph_session_init.
Inputs: no named parameters.
cph_task_cancelCancel TaskAIdempotent
Cancel a task that is no longer needed.
State machine: pending | in_progress | blocked → cancelled
Args:
task_id: The task to cancel
reason: Why the task is being cancelled (optional but recommended)
Inputs: task_id (required), reason.
cph_task_completeComplete TaskAIdempotent
Mark a task as completed.
State machine: in_progress → completed (rejects if not in_progress)
Args:
task_id: The task to complete
actual_minutes: Actual time spent. CRITICAL for estimation training. This is the ground truth that improves future predictions. Provide even if the task was blocked for part of the time.
completion_notes: What was done, any gotchas, what to know next time (optional)
Inputs: task_id (required), actual_minutes, completion_notes.
cph_task_createCreate TaskA
Create a task within a workflow.
Call this when beginning any discrete piece of work that will take more than ~5 minutes. Create BEFORE starting work, not after.
Args:
workflow_id: Which workflow
title: What you're doing (e.g. "Implement JWT refresh token rotation")
description: Acceptance criteria and requirements (optional)
parent_task_id: If this is a subtask (optional)
priority: low | medium | high | critical
estimated_minutes: Your estimate. ALWAYS provide this even if rough. Skipping this excludes the task from estimation accuracy analysis. Guess if unsure — a bad estimate is more useful than no estimate.
Returns: Created task. Call cph_task_start immediately after.
Inputs: workflow_id (required), title (required), description, parent_task_id, +2 more.
cph_task_getGet TaskARead-onlyIdempotent
Get full details of a single task including subtasks and open blockers.
Inputs: task_id (required).
cph_task_listList TasksARead-onlyIdempotent
List tasks filtered by workflow and/or status.
Returns ID and title only for efficiency. Use cph_task_get for full details on a specific task.
Call this only when explicitly asked — session_init already provides active tasks.
Inputs: workflow_id, status, include_subtasks, limit, +1 more.
cph_task_startStart TaskAIdempotent
Mark a task as in_progress and record start time.
CALL THIS BEFORE writing any code or making any changes for this task. The hook system uses the existence of an in_progress task to allow file writes.
State machine: pending → in_progress (only valid transition from this tool)
Inputs: task_id (required).
cph_task_updateUpdate TaskAIdempotent
Update task fields. For starting/completing, prefer task_start and task_complete.
Inputs: task_id (required), title, description, priority, +2 more.
cph_thinking_summaryThinking Time SummaryARead-onlyIdempotent
Get inferred thinking-time breakdown for recent turns.
Claude Code's extended thinking is not directly observable. This tool infers thinking time from the gaps between tool calls:
Initial gap: time from user prompt to first tool use
Interleaved gaps: time between consecutive tool calls
Final gap: time from last tool to response
Returns per-turn breakdowns, aggregate stats, tool baselines, and a caveat explaining inference limitations.
Args:
session_id: Filter to a specific session (optional)
workflow_id: Filter to a specific workflow (optional)
limit: Number of recent turns to return (default 10)
Inputs: session_id, workflow_id, limit.
cph_who_is_workingWho Is WorkingARead-onlyIdempotent
Show active agents/developers and what they're working on.
Returns annotated list of active sessions with:
Developer name and identity
Current task (if any)
Current blocker (if any)
Status: active | blocked | idle_with_task | available
Summary counts
Use this to understand team state before starting work.
Inputs: workflow_id.
cph_workflow_createCreate WorkflowA
Create a new workflow (project container for tasks, blockers, decisions).
Create one per feature branch, sprint, or meaningful engineering effort.
Args:
name: Short name (e.g. "OAuth Migration", "API v2", "Payments Refactor")
description: Goals and scope (optional)
git_branch_pattern: Branch pattern for auto-detection (e.g. "feature/auth-", "fix/") Set this so cph_detect_workflow automatically finds this workflow on matching branches.
Returns: Created workflow with ID. PUT THIS ID IN YOUR CLAUDE.md.
Inputs: name (required), description, git_branch_pattern.
cph_workflow_listList WorkflowsARead-onlyIdempotent
List workflows filtered by status.
Returns: Array of workflows with ID, name, status. No task counts (use cph_workflow_summary for that).
Inputs: status.
cph_workflow_reconstructReconstruct Workflow HistoryARead-onlyIdempotent
Reconstruct the full history of a workflow for handoff or review.
Aggregates tasks, decisions, blockers, sessions, and activity into a comprehensive reconstruction object. Identifies dead ends (cancelled tasks and resolved blockers) to show the journey, not just the destination.
Use this when:
Handing off a workflow to another developer
Reviewing what happened during a project
Debugging why certain decisions were made
Inputs: workflow_id (required).
cph_workflow_summaryGet Workflow SummaryARead-onlyIdempotent
Get a full status summary of a workflow.
Returns task counts by status, open blocker count, decision count, and estimation accuracy ratio.
Use this when a user explicitly asks for project status. Don't call proactively.
Inputs: workflow_id (required).
cph_workflow_updateUpdate WorkflowBIdempotent
Update a workflow's name, description, status, or git branch pattern.
Inputs: workflow_id (required), name, description, status, +1 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 30 tools
Each tool has a clearly distinct purpose within its domain (blockers, tasks, decisions, workflows, etc.). Overlap is minimal and well-handled by descriptions, e.g., cph_decision_list vs cph_decision_search serve different intents.
All tools follow a consistent cph_verb_noun pattern in snake_case. Prefix establishes namespace, and every name clearly indicates the action and resource, e.g., cph_task_create, cph_blocker_resolve.
At 30 tools, the set is on the larger side but serves a comprehensive project history system. A couple of tools (cph_decision_attach_commit, cph_set_depth) could be internal or merged, but overall each tool addresses a legitimate need.
The tool surface covers the full lifecycle for tasks, blockers, decisions, and workflows, including creation, reading, updating, and deletion/closure. Additionally, it includes context management, team awareness, and activity tracking, leaving no obvious gaps.
Maintenance
Related MCP Connectors
Persistent context for Claude. Your AI always knows your projects and next actions across sessions.
Opinionated sprint tracker. Read/update tickets, sprints, velocity from Claude/Cursor/Zed.
Shared work memory for Claude Code, Codex, Cursor and chat, scoped to each repository.
A self-hostable feed of reminders, learnings and work that Claude and ChatGPT can read and write
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA lightweight journal/memory system for Claude Code with no ML dependencies, using SQLite for fast local storage.6MIT
- AlicenseBqualityDmaintenanceProvides persistent memory, skill tracking, failure indexing, and context sharing for Claude Code using SQLite with FTS5 full-text search.237 npm1MIT
- AlicenseNot gradedqualityDmaintenanceProvides persistent, searchable memory for Claude Code using local SQLite, semantic embeddings, and full-text search, enabling Claude to recall and retrieve context across sessions and projects without external services.23 npm4MIT
- AlicenseBqualityDmaintenanceTracks working context and code structure in a portable local SQLite database, enabling seamless context and task continuity across different AI coding tools.121MIT