The missing memory layer for your team and your AI agents.
Every team loses knowledge constantly. Decisions get made in Slack threads, Zoom calls, and late-night emails — but only the outcome gets written down. The why disappears. When your AI agent starts a new task, it knows nothing about why you made past choices.
ContextMesh fixes this.
ContextMesh is an MCP (Model Context Protocol) server that gives your AI agents your team's full institutional memory. It captures team decisions with their complete reasoning, stores them in a SQLite knowledge base with full-text search, and exposes them to Claude Code, Cursor, Copilot, or any MCP-compatible AI agent.
Stop watching your AI agents make choices that contradict last quarter's hard-won decisions. Give them memory.
Slack thread / Meeting notes / Email / PR description
│
▼ (Claude AI extraction)
ContextMesh DB (SQLite + FTS5)
│
▼ (MCP protocol)
Claude Code · Cursor · Copilot · Your agents
| Feature | Description |
|---|---|
| 🎯 Capture decisions with reasoning | Save any decision with full context, rationale, alternatives rejected, and outcome — not just the final choice |
| 🤖 AI-powered extraction | Paste a raw Slack thread, meeting transcript, email, or PR — Claude automatically extracts and structures every decision |
| 🔍 Full-text search | SQLite FTS5 powers instant natural-language queries across all your organization's knowledge |
| 🔌 MCP server | Works with Claude Code, Cursor, GitHub Copilot, and any MCP-compatible AI agent out of the box |
| 📊 7 MCP tools | capture_decision, ingest_content, query_context, list_decisions, get_decision, update_outcome, memory_stats |
| 🌐 Universal | Engineering, healthcare, legal, finance, product, education — decisions are universal |
| 💾 Zero-config storage | SQLite database stored at ~/.contextmesh/contextmesh.db — no server, no Docker, no cloud required |
| ⚡ Lightweight | TypeScript, Node.js, better-sqlite3. Fast, local-first, and private |
git clone https://github.com/srinathsankara/contextmesh
cd contextmesh
npm installcp .env.example .envEdit .env:
ANTHROPIC_API_KEY=sk-ant-your-key-hereGet your API key at console.anthropic.com.
npm run build# Ingest a decision from raw text (Slack, email, meeting notes...)
npm run ingest -- --text "We chose Postgres over MongoDB for auth-service. ACID compliance was critical for our financial transactions. MongoDB was rejected because it lacks proper join support." --source slack --project auth-service
# Ingest from a file (meeting transcript, PR description, etc.)
npm run ingest -- --file ./meeting-notes.txt --source meeting --project backend
# Search your organizational memory
npm run query -- --q "why did we choose postgres"
# List all captured decisions
npm run query -- --list
# Filter by project
npm run query -- --list --project auth-service
# Get memory stats
npm run query -- --statsSample output:
$ npm run query -- --q "why did we choose postgres"
1 result(s) for: "why did we choose postgres"
════════════════════════════════════════════════════════════
📌 Database selection for auth-service
────────────────────────────────────────────────────────────
ID: a3f2b1c4-...
Project: auth-service
Tags: postgres, database, architecture, acid
Source: slack
Date: 2026-05-07
CONTEXT
Team debated database choice for the new auth service during Sprint planning.
DECISION
Use PostgreSQL as the primary database for auth-service.
REASONING
ACID compliance is non-negotiable for financial transactions. The team has
deep Postgres expertise which reduces operational risk. Relational joins are
critical for the user-role-permission model we need.
ALTERNATIVES REJECTED
MongoDB: No native join support, would require application-level joins which
add complexity. MySQL: Weaker JSONB support, less mature full-text search.
Add ContextMesh to your Claude Code MCP configuration so Claude automatically has access to your organizational memory before starting any task.
Edit ~/.claude/claude_desktop_config.json:
{
"mcpServers": {
"contextmesh": {
"command": "node",
"args": ["/absolute/path/to/contextmesh/dist/index.js"],
"env": {
"ANTHROPIC_API_KEY": "sk-ant-your-key-here"
}
}
}
}Or using npx (after building):
{
"mcpServers": {
"contextmesh": {
"command": "npx",
"args": ["tsx", "/absolute/path/to/contextmesh/src/index.ts"],
"env": {
"ANTHROPIC_API_KEY": "sk-ant-your-key-here"
}
}
}
}After restarting Claude Code, it will automatically query your memory before working on tasks.
Open Cursor Settings → MCP → Add Server and paste:
{
"name": "contextmesh",
"command": "node",
"args": ["/absolute/path/to/contextmesh/dist/index.js"],
"env": {
"ANTHROPIC_API_KEY": "sk-ant-your-key-here"
}
}ContextMesh speaks standard MCP over stdio. Any client that supports the Model Context Protocol can connect:
{
"command": "node",
"args": ["/path/to/contextmesh/dist/index.js"],
"env": {
"ANTHROPIC_API_KEY": "sk-ant-your-key-here"
}
}Once connected, your AI agent has access to 7 tools:
Manually capture a decision with its full reasoning context.
| Parameter | Type | Required | Description |
|---|---|---|---|
title |
string | ✅ | Short label for the decision (max 10 words) |
context |
string | ✅ | What situation or problem led to this decision? |
decision |
string | ✅ | What was actually decided? |
reasoning |
string | ✅ | Why was this choice made? |
alternatives |
string | ➖ | What other options were considered and why rejected? |
tags |
string | ➖ | Comma-separated keywords (e.g. architecture,database) |
project |
string | ➖ | Which project, team, or area does this apply to? |
decided_by |
string | ➖ | Who made this decision? |
source |
string | ➖ | Where does this come from? (slack, meeting, email, manual) |
Example:
capture_decision(
title: "Switch auth to JWT tokens",
context: "Session-based auth was causing scaling issues with horizontal pod scaling.",
decision: "Move to stateless JWT authentication for all services.",
reasoning: "JWTs are stateless so any pod can validate without shared session store. Team has JWT expertise. Industry standard for microservices.",
alternatives: "Redis sessions: adds operational complexity and single point of failure. Sticky sessions: limits autoscaling ability.",
tags: "auth,jwt,security,architecture",
project: "platform",
decided_by: "engineering lead"
)
Paste raw text from any source — Claude AI automatically extracts all decisions.
| Parameter | Type | Required | Description |
|---|---|---|---|
content |
string | ✅ | Raw text: Slack thread, meeting notes, email, PR, document |
source |
string | ➖ | Where is this from? (slack, meeting, email, pr, document) |
project |
string | ➖ | Which project or team does this relate to? |
Example:
ingest_content(
content: "...[paste full Slack thread or meeting notes here]...",
source: "slack",
project: "backend"
)
Claude (claude-opus-4-5) reads the raw text and extracts every decision with its full context, reasoning, and alternatives — automatically.
Search your organization's memory using natural language.
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string | ✅ | Natural language query — e.g. "why did we pick PostgreSQL" |
limit |
number | ➖ | Max results (default: 5) |
Example:
query_context(query: "authentication approach", limit: 3)
query_context(query: "why did we reject Redis")
query_context(query: "API versioning strategy")
Uses SQLite FTS5 full-text search with fallback to LIKE search for robustness.
List recent decisions with optional filters.
| Parameter | Type | Required | Description |
|---|---|---|---|
limit |
number | ➖ | How many to return (default: 10) |
project |
string | ➖ | Filter by project name |
tag |
string | ➖ | Filter by tag |
source |
string | ➖ | Filter by source |
Get the full details of a specific decision by ID.
| Parameter | Type | Required | Description |
|---|---|---|---|
id |
string | ✅ | Full UUID or first 8 characters |
Close the feedback loop — record what actually happened as a result of a past decision.
| Parameter | Type | Required | Description |
|---|---|---|---|
id |
string | ✅ | The decision ID to update |
outcome |
string | ✅ | What happened? Was it the right call? |
Example:
update_outcome(
id: "a3f2b1c4",
outcome: "Postgres was the right call. Zero issues after 6 months in production. The ACID compliance proved critical when we added payment processing."
)
Get statistics about your organizational memory.
memory_stats()
Returns total decisions, breakdown by source and project.
# Before starting a refactor, check what decisions were made:
query_context("why did we choose this auth approach")
query_context("API versioning decisions")
# After a sprint retro, ingest the meeting notes:
ingest_content("[paste full meeting transcript]", source="meeting", project="platform")
# Capture an architecture decision record (ADR):
capture_decision(
title: "Use event sourcing for order service",
context: "Order history needed for audit, refunds, and analytics. Mutable records made this complex.",
decision: "Implement event sourcing with an append-only event store for the order service.",
reasoning: "Perfect audit trail. Enables time-travel debugging. Decouples downstream consumers via event bus. Team studied Martin Fowler's CQRS patterns.",
alternatives: "Mutable DB + audit log table: fragile, often incomplete. Snapshot-only: loses fine-grained history needed for dispute resolution.",
tags: "architecture,event-sourcing,orders,cqrs",
project: "order-service"
)
# After a planning meeting:
ingest_content("Today we decided to delay v2 launch by 2 weeks because QA found 3 P0 bugs in the checkout flow. We considered shipping with known bugs but rejected this due to chargeback risk.", source="meeting", project="v2-launch")
# Before a prioritization session:
query_context("why did we de-prioritize mobile app")
capture_decision(
title: "Switch ICU patients to Protocol B",
context: "Rising antibiotic resistance rates observed over 6 months of data. Protocol A success rate dropped from 94% to 71%.",
decision: "Adopt Protocol B as first-line treatment for ICU patients effective next quarter.",
reasoning: "Internal data shows 40% better outcomes. Lower resistance profile confirmed by three peer-reviewed studies. Hospital formulary already stocks required antibiotics.",
alternatives: "Protocol C: effective but 3x cost, rejected for budget reasons. Continuing Protocol A: too high failure rate given resistance trends.",
tags: "clinical-protocol,icu,antibiotics",
project: "critical-care"
)
ingest_content(
"We removed the arbitration clause from the consumer contract. Client's jurisdiction (California) restricts mandatory arbitration for consumer agreements under the CA Arbitration Act. Alternative of voluntary arbitration with opt-in was considered but rejected — client preferred clean contract. We retained arbitration for B2B contracts.",
source: "contract-review",
project: "consumer-terms-2026"
)
contextmesh/
├── src/
│ ├── index.ts # MCP server entry point (stdio transport)
│ ├── server.ts # 7 MCP tools: capture, ingest, query, list, get, update, stats
│ ├── types.ts # Decision, DecisionInsert, QueryResult, IngestResult interfaces
│ ├── db/
│ │ ├── schema.ts # SQLite setup, WAL mode, FTS5 virtual table, triggers
│ │ └── queries.ts # insertDecision, searchDecisions, filterDecisions, listDecisions, getStats...
│ ├── extractors/
│ │ └── claude-extractor.ts # Claude claude-opus-4-5 extraction + claude-haiku-4-5 enrichment
│ └── cli/
│ ├── ingest.ts # CLI: npm run ingest -- --file / --text / stdin
│ └── query.ts # CLI: npm run query -- --q / --list / --stats / --id
├── .env.example # Environment variable template
├── package.json
└── tsconfig.json
ContextMesh stores all decisions in a local SQLite database at ~/.contextmesh/contextmesh.db (configurable via CONTEXTMESH_DB_DIR environment variable).
Schema:
decisionstable — stores all fields:id,title,context,decision,reasoning,alternatives,outcome,tags,source,project,decided_by,created_at,updated_atdecisions_fts— SQLite FTS5 virtual table for full-text search across all text fields- Three triggers keep the FTS index synchronized automatically:
decisions_ai(insert),decisions_au(update),decisions_ad(delete) - WAL journal mode for safe concurrent reads
Search: FTS5 search tokenizes queries and uses SQLite's built-in BM25 ranking. Multi-word queries are expanded as OR conditions. Falls back to LIKE search if FTS fails.
| Environment Variable | Default | Description |
|---|---|---|
ANTHROPIC_API_KEY |
— | Required. Anthropic API key for Claude AI extraction |
CONTEXTMESH_DB_DIR |
~/.contextmesh |
Directory for the SQLite database |
- Web UI — Browse, edit, and visualize decisions in a browser dashboard
- Slack bot — Auto-ingest decisions from Slack channels in real time
- GitHub integration — Auto-capture decisions from PR descriptions and ADR files
- Vector embeddings — Semantic similarity search beyond keyword matching
- Team sharing — Multi-user support with a shared remote memory server
- Notion / Confluence sync — Two-way sync with existing knowledge bases
- Decision templates — Domain-specific templates (ADR, clinical protocol, legal memo, post-mortem)
- VS Code extension — Capture decisions inline from your editor
- Export to Markdown — Generate formatted ADR documents from captured decisions
Contributions are welcome! ContextMesh is designed to be the foundation for a richer organizational memory ecosystem.
- Fork the repo
- Create a feature branch:
git checkout -b feat/my-feature - Make your changes, ensuring TypeScript compiles:
npm run build - Open a PR with a clear description
Good first issues:
- Add support for importing Notion pages
- Add a
--format jsonflag to the CLI query output - Write tests for the FTS5 query builder
- Add a
searchalias forquery_contextin the MCP server
| Script | Command | Description |
|---|---|---|
build |
npm run build |
Compile TypeScript to dist/ |
start |
npm run start |
Run the compiled MCP server |
dev |
npm run dev |
Run MCP server with tsx (no compile step) |
ingest |
npm run ingest -- [options] |
CLI: extract and save decisions from text/file |
query |
npm run query -- [options] |
CLI: search and list decisions |
MIT — see LICENSE for details.
Built with TypeScript · Claude AI · SQLite FTS5 · MCP Protocol