Powered by AdoptNow.AI. AdoptNow.AI is currently a project domain, not a registered company.
Graph-based knowledge storage for AI coding agents — works with any IDE via MCP.
ContextForge captures your conversations with AI coding agents (Copilot, Cursor, JetBrains AI, etc.), extracts structured knowledge into a graph database, and makes it available across all your projects and workspaces. Instead of agents starting every conversation from scratch, they can build on past decisions, patterns, and context.
Distributed as a single binary — no source code, no npm install, no runtime dependencies.
From a fresh ContextForge checkout, run:
npm run setupThis is the primary setup path. It installs dependencies, downloads the semantic-search model into the correct user cache, and builds the MCP server. It is safe to run again and reuses cached model files.
After setup completes, configure your MCP client using the instructions below. For OS-specific details, see SETUP-MAC.md or SETUP-WINDOWS.md.
cp -r release/ ~/.contextforge/
chmod +x ~/.contextforge/contextforgenpm run setup downloads the model from Hugging Face into ~/.contextforge/models/Xenova/all-MiniLM-L6-v2/. The MCP server uses this local copy and does not access the network during searches. To only download the model after dependencies are already installed, use npm run download:model --workspace packages/core.
For a packaged release, the release builder copies this cached model beside the binary when it is present. Set CONTEXTFORGE_MODEL_DIR if the model is stored elsewhere.
- The Problem
- How It Works
- Quick Start
- Architecture
- MCP Tools
- Knowledge Graph Design
- Extraction Engine
- Configuration
- Data Storage
- Project Structure
- Tech Stack
- License
AI coding agents are stateless. Every new conversation starts from zero — the agent doesn't remember:
- What files were changed last week and why
- What architectural decisions were made
- What errors were encountered and how they were fixed
- What libraries, patterns, and conventions the project uses
Raw conversation logs are huge (50-200KB each) and full of noise (tool output, repeated system prompts, file contents). Storing and searching them is expensive and slow.
ContextForge solves this with a 3-step pipeline:
Step 1: Capture Step 2: Extract Step 3: Query
┌──────────────┐ ┌────────────────────┐ ┌───────────────────┐
│ Agent talks │──────▶│ Extractor pulls │────▶│ Graph DB stores │
│ to user │ │ entities, facts, │ │ only structured │
│ (50-200KB) │ │ relations │ │ knowledge (2-5KB) │
└──────────────┘ └────────────────────┘ └───────────────────┘
│ │
▼ ▼
Raw text DISCARDED Graph is queryable
across all projects
Result: 96% smaller storage, instant graph queries, knowledge that persists across workspaces and IDEs.
The agent calls MCP tools automatically — no manual invocation needed. The tools are available to any IDE that supports MCP (VS Code, Cursor).
| Extracted | Example |
|---|---|
| Files | auth.ts, middleware.ts, package.json |
| Functions/Classes | handleLogin(), UserService, AuthMiddleware |
| Libraries | express, react, jsonwebtoken |
| Errors | TypeError: Cannot read property 'id' of undefined |
| Decisions | "Used JWT instead of sessions because it scales better" |
| Relationships | auth.ts → uses → jsonwebtoken, auth.test.ts → tests → auth.ts |
- Raw file contents that were shown to the agent
- Tool call outputs (grep results, terminal output)
- System prompts and context blocks
- Repeated/duplicate content
VS Code / Cursor — open the global MCP config (Cmd+Shift+P → "MCP: Open User Configuration") and add:
{
"servers": {
"contextforge": {
"command": "/Users/<username>/.contextforge/contextforge",
"type": "stdio"
}
}
}Replace <username> with your macOS username. This is global — works across all projects.
MCP registration and agent instructions are separate. Register the server first, then install or enable the client-specific instructions so the agent actually retrieves and saves memory.
| Client | MCP registration location | Instruction location |
|---|---|---|
| VS Code / Copilot | Project: .vscode/mcp.json; global: MCP: Open User Configuration |
Project: .github/instructions/contextforge-memory.instructions.md; global: ~/Library/Application Support/Code/User/prompts/contextforge.instructions.md |
| Claude Code | Project: .mcp.json; global: claude mcp add --scope user ... |
Project: CLAUDE.md; global: add the same rules to your user-level Claude instructions |
| Other CLI MCP clients | The client's MCP JSON/config file, using a stdio server entry | The client's instruction or rules file; there is no universal CLI location |
For a packaged installation, use the absolute executable path in the MCP entry:
{
"contextforge": {
"type": "stdio",
"command": "/Users/<username>/.contextforge/contextforge",
"args": []
}
}VS Code uses the servers wrapper:
{
"servers": {
"contextforge": {
"type": "stdio",
"command": "/Users/<username>/.contextforge/contextforge",
"args": []
}
}
}Claude Code uses the mcpServers wrapper. The project command is:
claude mcp add --transport stdio --scope project contextforge -- /Users/<username>/.contextforge/contextforgeFor a source checkout, replace the packaged command with an absolute Node executable and the built server path. Set CONTEXTFORGE_MODEL_DIR to packages/core/release/models when semantic search model files are not bundled beside the server. After changing configuration, reload or restart the client and confirm that contextforge is connected.
The MCP server alone makes tools available — but agents won't use them unless instructed. This step ensures every conversation automatically stores and retrieves knowledge.
VS Code / Cursor — create the file ~/Library/Application Support/Code/User/prompts/contextforge.instructions.md:
---
description: "Use when: starting any conversation, recalling past work, ending a conversation. Manages persistent memory across all workspaces using the contextforge MCP tools."
---
# ContextForge
You have access to a persistent knowledge graph via MCP tools that remembers context across all conversations and workspaces.
## At the start of every conversation
1. Call `get_workspace_context` with the current workspace path to load known entities, decisions, patterns, and facts from past conversations.
2. Use this context to avoid re-asking questions the user already answered, and to build on past decisions.
## During the conversation
- When the user asks about past work, decisions, or patterns, call `search_memory` to find relevant entities.
- When the user asks to refer to a Rally ticket (for example `US12345` or `TF6789`), call `get_rally_work_item` to fetch the latest details from Rally.
- When a notable decision, pattern, or convention is established, call `add_fact` to persist it immediately.
## At the end of a meaningful conversation
- When significant work was done (code changes, architectural decisions, bug fixes, new patterns), call `save_conversation` with the workspace path and the conversation messages.
- This extracts entities, relationships, and facts into the graph. Raw text is discarded.
- Skip this for trivial questions or one-off lookups.
## Tool summary
| Tool | When to use |
|------|-------------|
| `get_workspace_context` | Start of conversation — load past knowledge |
| `search_memory` | Recall past work, decisions, errors, patterns |
| `add_fact` | Persist a decision, convention, or insight immediately |
| `get_rally_work_item` | Fetch live Rally details for TF/US references |
| `save_conversation` | End of meaningful conversation — extract and store knowledge |
| `memory_status` | Check how much is stored, which workspaces have data |
| `cleanup_memory` | Remove old knowledge by time range (optionally per workspace) |
| `forget_workspace` | Completely remove all knowledge for a workspace |This file is user-level — it applies globally across all projects automatically.
Steps 2-3 set up the read side (agent retrieves knowledge) and instruction-driven write (agent calls save_conversation). The capture extension adds automatic write — conversations are saved to the knowledge graph without the agent needing to cooperate.
VS Code / Cursor:
# Install the VSIX from the release folder
code --install-extension release/contextforge-capture-0.1.0.vsixOr: Open VS Code → Cmd+Shift+P → "Extensions: Install from VSIX..." → select the .vsix file.
The extension automatically:
- Watches Copilot Chat session files for completed conversations
- Extracts messages and writes them to
~/.contextforge/inbox/ - The MCP server processes the inbox on its next call
You'll see a status bar item: $(database) Memory: active.
Chat commands:
@memory /save— manually save the current conversation immediately@memory /status— show capture status
Settings (via VS Code Settings UI → "ContextForge"):
contextforge.autoCapture— enable/disable auto-capture (default: true)contextforge.captureDelaySeconds— seconds to wait after last write before capturing (default: 30)contextforge.minMessages— minimum messages to capture a session (default: 2)
Start a new conversation with your AI agent and check:
- The agent should call
get_workspace_contextat the start - Ask: "What do you know about this project from past conversations?" — it should call
search_memory - On first use, results will be empty — the database populates as you have conversations
WRITE PATH READ PATH
────────── ─────────
┌──────────────────────────────────┐ ┌──────────────────────────────────┐
│ Capture Extension (in IDE) │ │ Agent (in IDE) │
│ │ │ │
│ Watches chat sessions, │ │ MCP resource auto-injected │
│ extracts messages, │ │ into context on start. │
│ writes to inbox. │ │ MCP tools called on demand. │
│ (VS Code extension) │ │ │
└─────────────┬────────────────────┘ └───────────────┬──────────────────┘
│ │
▼ │
~/.contextforge/inbox/ │
(JSON files: sessionId, │
workspace, messages) │
│ │
▼ ▼
┌──────────────────────────────────────────────────────────┐
│ MCP Server (contextforge binary) │
│ │
│ On startup + before reads: processInbox() │
│ → parse inbox JSON → extract knowledge → ingest │
│ │
│ Tools (8): search_memory, get_workspace_context, │
│ save_conversation, add_fact, get_rally_work_item, │
│ memory_status, cleanup_memory, forget_workspace │
│ │
│ Resource: contextforge://workspace/{path} │
│ → auto-injected into agent context │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Extractor │ │MemoryDatabase│ │
│ │ (no LLM) │ │ (SQLite) │ │
│ └──────────────┘ └──────┬───────┘ │
└───────────────────────────┼─────────────────────────────┘
│
▼
~/.contextforge/contextforge.db
┌─────────────────────────────────────┐
│ 1. User chats with Copilot in IDE │
│ (VS Code) │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 2. IDE writes session to disk │
│ chatSessions/<id>.jsonl │
│ (JSONL event log format) │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 3. Capture Extension detects │
│ change via FileSystemWatcher │
│ (30-second debounce) │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 4. Extension parses JSONL, │
│ extracts messages, writes │
│ JSON to inbox │
│ ~/.contextforge/inbox/ │
│ session-<id>-<ts>.json │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 5. MCP Server processInbox() │
│ runs on startup + before │
│ each resource read │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 6. Extractor (rule-based, no LLM) │
│ extracts entities, relations, │
│ facts from messages │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 7. SQLite Database │
│ ~/.contextforge/contextforge.db │
│ Entities, Facts, Relations │
│ stored permanently │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ 1. New conversation starts │
│ IDE auto-reads MCP resource │
│ contextforge://workspace/... │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 2. MCP Server queries SQLite DB │
│ Returns entities, facts, │
│ relationships for workspace │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 3. Knowledge injected into agent │
│ context — agent sees past │
│ decisions, patterns, errors │
│ before first user message │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 4. During conversation, agent │
│ calls search_memory, add_fact │
│ on demand via MCP tools │
└─────────────────────────────────────┘
Each file in ~/.contextforge/inbox/ is a JSON document:
{
"sessionId": "abc123-...",
"workspace": "/Users/you/src/my-project",
"title": "Fix auth middleware bug",
"messages": [
{ "role": "user", "content": "The login endpoint returns 401..." },
{ "role": "assistant", "content": "The JWT expiry check in auth.ts..." }
],
"capturedAt": 1776885043000
}The MCP server reads this, runs the Extractor, ingests into the graph DB, and deletes the file. Failed files are renamed to .error for debugging.
| Piece | What it does | Where it lives |
|---|---|---|
| MCP config | Tells the IDE where to find the server binary | mcp.json (VS Code) |
| Agent instructions | Tells the agent when and how to call tools + when to save | instructions.md (VS Code) |
| Capture extension | Automatically writes conversations to inbox for MCP processing | VS Code extension |
The capture extension is optional — without it, the agent still saves conversations via instructions. The extension adds reliability (auto-capture) and catches conversations where the agent forgot to call save_conversation.
- MCP protocol — works with any IDE that supports MCP, no custom plugins needed
- Single binary — no Node.js, no npm install, no runtime dependencies for end users
- One global database — all workspaces write to the same graph, so agents remember context from any project
- stdio transport — the IDE starts/stops the process automatically, no port management
- No LLM required — extraction is rule-based, works offline, zero API costs
The MCP server exposes 8 tools (agent calls on demand) and 1 resource template (IDE auto-attaches to context).
URI template: contextforge://workspace/{workspace_path}
The IDE reads this resource automatically and injects it into the agent's context at the start of every conversation. The agent doesn't need to call anything — the IDE attaches the workspace knowledge before the first message.
This is what makes it work with any model, including cheaper ones that can't reliably follow tool-calling instructions. The knowledge is just... there.
| What the IDE does | What the agent sees |
|---|---|
Calls resources/list → gets known workspaces |
(nothing, this is invisible) |
Calls resources/read for current workspace |
Agent's context now includes all entities, facts, and relationships from past conversations |
Search the knowledge graph for entities (files, functions, libraries, errors, decisions, patterns). Use this to recall past work, decisions, and context from previous conversations across all workspaces.
| Parameter | Required | Description |
|---|---|---|
query |
Yes | Entity name or partial name (e.g. "auth.ts", "JWT", "LoginService") |
type |
No | Filter by entity type: file, function, class, service, library, pattern, error, decision, config, endpoint, test |
workspace |
No | Filter to a specific workspace path |
depth |
No | Graph traversal depth (default: 2) |
limit |
No | Max results (default: 20) |
Get all known entities, relationships, and facts for a workspace. Use this at the start of a conversation to load relevant context from past work.
| Parameter | Required | Description |
|---|---|---|
workspace |
Yes | Workspace path to get context for |
limit |
No | Max entities to return (default: 200, override with CONTEXTFORGE_CONTEXT_LIMIT) |
Save a completed conversation. Extracts entities, relationships, and facts into the knowledge graph. Raw text is discarded after extraction. Call this when a meaningful conversation ends.
| Parameter | Required | Description |
|---|---|---|
workspace |
Yes | Workspace path where the conversation took place |
title |
No | Short title summarizing the conversation |
messages |
Yes | Array of {role, content} messages |
Store a specific fact about an entity. Use this to record decisions, patterns, conventions, or other knowledge that should persist.
| Parameter | Required | Description |
|---|---|---|
entityName |
Yes | Name of the entity (file, function, service, etc.) |
entityType |
Yes | Type of entity |
workspace |
Yes | Workspace path |
key |
Yes | Fact key (e.g. "pattern", "convention", "reason", "note") |
value |
Yes | Fact value |
Fetch Rally work item details by FormattedID (for example US12345 or TF6789).
| Parameter | Required | Description |
|---|---|---|
reference |
Yes | Rally FormattedID to fetch |
includeDescription |
No | Include Description/Notes text in the response (default: false) |
workspaceRef |
No | Optional Rally workspace ref (for example /workspace/123456789) |
projectRef |
No | Optional Rally project ref (for example /project/987654321) |
Show how much knowledge is stored across all workspaces. Returns entity, fact, and relation counts per workspace along with timestamp ranges.
No parameters.
Remove old knowledge by time range. Useful for clearing stale data without deleting everything.
| Parameter | Required | Description |
|---|---|---|
olderThanDays |
Yes | Delete knowledge older than this many days |
workspace |
No | Limit cleanup to a specific workspace (default: all workspaces) |
Completely remove all knowledge for a workspace — entities, facts, relations, and conversation metadata.
| Parameter | Required | Description |
|---|---|---|
workspace |
Yes | Workspace path to forget |
The database uses SQLite with better-sqlite3 (WAL mode), sqlite-vec for vector search, and FTS5 for full-text search. All data is stored in a single file.
| Node Table | Properties | Purpose |
|---|---|---|
Entity |
id, type, name, workspace, metadata, createdAt, updatedAt | Files, functions, libraries, errors, decisions, patterns, etc. |
Fact |
id, key, value, confidence, sourceConversationId, createdAt, updatedAt | Key-value knowledge about an entity |
Conversation |
id, workspace, projectName, ide, title, startedAt, endedAt | Metadata only — no raw text stored |
| Edge Table | From → To | Purpose |
|---|---|---|
RELATES_TO |
Entity → Entity | Typed relationships (uses, depends_on, tests, caused_by, etc.) |
HAS_FACT |
Entity → Fact | Links facts to their entity |
MENTIONED_IN |
Entity → Conversation | Tracks which conversations referenced an entity |
file, function, class, service, library, pattern, error, decision, config, endpoint, test
uses, depends_on, modifies, tests, calls, caused_by, fixed_by, replaces, contains, implements, configures
-- "What do we know about auth.ts?"
MATCH (e:Entity {name: 'auth.ts'})-[r:RELATES_TO]->(related:Entity)
RETURN e, r, related
-- "What libraries does the project use?"
MATCH (e:Entity {type: 'library', workspace: '/my/project'})
RETURN e.name
-- "What errors have been fixed?"
MATCH (err:Entity {type: 'error'})-[r:RELATES_TO {type: 'fixed_by'}]->(fix:Entity)
RETURN err.name, fix.name
-- "Everything about JWT" (2-hop traversal)
MATCH (e:Entity)-[*1..2]-(related:Entity)
WHERE e.name CONTAINS 'JWT'
RETURN e, relatedThe agent doesn't need to use the same words the user used. The graph stores entities and relationships, not text blobs:
User says: "fix login bug"
│
Graph resolves: "login" → login.ts → auth.ts → JWT expiry bug → fix applied
(traverses relationships, not keyword matching)
No full-text search index needed. No embedding model needed. Just graph traversal.
When the user asks "Why did we choose JWT?", here's the exact code path that resolves the query to a graph answer:
┌─────────────────────────────────────┐
│ 1. User asks: │
│ "Why did we choose JWT?" │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 2. Agent parses intent │
│ Keyword: JWT │
│ Intent: decision / reason │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 3. Agent calls search_memory │
│ query='JWT', depth=2, limit=20 │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 4. mcp.ts search_memory handler │
│ Builds GraphQuery: │
│ entityName = 'JWT' │
└──────────────┬──────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ database.ts → query() │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Step 1: Find root entities │ │
│ │ MATCH (e:Entity) │ │
│ │ WHERE e.name CONTAINS 'JWT' │ │
│ │ ORDER BY e.updatedAt DESC │ │
│ │ LIMIT 20 │ │
│ │ │ │
│ │ Matches: │ │
│ │ [library] JWT │ │
│ │ [decision] JWT instead of sessions │ │
│ │ [error] JWT expiry bug │ │
│ └────────────────┬───────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Step 2: Walk relationships (depth=2) │ │
│ │ For each root entity: │ │
│ │ MATCH (a)-[r:RELATES_TO*1..2]->(b) │ │
│ │ WHERE a.id = rootId │ │
│ │ │ │
│ │ Discovers connected entities: │ │
│ │ auth.ts, jsonwebtoken, login.ts, │ │
│ │ auth.test.ts ... │ │
│ └────────────────┬───────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Step 3: Get direct relations │ │
│ │ Between all found entity IDs: │ │
│ │ MATCH (a)-[r:RELATES_TO]->(b) │ │
│ │ │ │
│ │ auth.ts --uses--> JWT │ │
│ │ auth.test.ts --tests--> auth.ts │ │
│ │ error --caused_by--> auth.ts │ │
│ └────────────────┬───────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Step 4: Get facts │ │
│ │ For each entity ID: │ │
│ │ MATCH (e)-[:HAS_FACT]->(f) │ │
│ │ │ │
│ │ decision entity → │ │
│ │ key = 'reason' │ │
│ │ value = 'scales better than sessions' │ │
│ └────────────────┬───────────────────────────────────┘ │
└───────────────────┼──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 5. mcp.ts formats GraphResult │
│ into text response: │
│ │
│ [library] JWT (/my/project) │
│ [decision] JWT instead of sessions │
│ reason: scales better │
│ │
│ Relationships: │
│ auth.ts --uses--> JWT │
│ auth.test.ts --tests--> auth.ts │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 6. Agent synthesizes answer: │
│ "We chose JWT over sessions │
│ because it scales better. │
│ It's used in auth.ts." │
└─────────────────────────────────────┘
If no entities match "JWT" in Step 1, the agent gets No entities found matching "JWT" and responds that it has no record of that decision.
Key details:
- Substring matching — the query uses
e.name CONTAINS 'JWT', not semantic search. The entity name must literally contain the search term. - No ranking — all matching entities are returned sorted by
updatedAt DESC. A[decision]entity with the "reason" fact might appear alongside[file]and[library]entities. - Graph traversal — the 2-hop walk from root entities pulls in connected files, libraries, and errors, giving the agent a subgraph of related context.
- Agent synthesis — the MCP server returns raw graph data. The agent (LLM) is responsible for picking the relevant pieces and forming a coherent answer.
The Extractor class uses rule-based pattern matching — no LLM, no API keys, no internet connection required.
| Category | How it works |
|---|---|
| File references | Regex matching file paths with known extensions (.ts, .py, .java, .go, etc.) |
| Library imports | Matches import ... from 'x', require('x'), Python import x patterns |
| Function/class names | Matches function, class, arrow function, method definition patterns |
| Error patterns | Matches Error:, Exception:, ENOENT, TypeError, Cannot find, etc. |
| Decisions | Matches "I'll use X because Y", "X instead of Y", "we should X" patterns |
| Relation | Detection method |
|---|---|
| File → uses → Library | Both mentioned within 500 chars of each other |
| TestFile → tests → SourceFile | File name contains .test. or .spec. + matching source file found |
| Error → caused_by → File | Error and file mentioned within 500 chars |
| File → contains → Function | Function and file mentioned within 500 chars |
- Entities are keyed by
type + name + workspace— same entity is updated, not duplicated - Relations are keyed by
source + target + type— existing relations get their context updated - Facts are keyed by
entity + key— new values overwrite old ones with updated confidence scores
| Variable | Default | Description |
|---|---|---|
CONTEXTFORGE_DB_PATH |
~/.contextforge/contextforge.db |
Override database path |
CONTEXTFORGE_CONTEXT_LIMIT |
500 |
Max entities returned by get_workspace_context and the resource template |
ContextForge is a local memory tool only — it does not connect to Rally, GitHub, or the Knowledge Hub itself. Those are separate MCP servers the agent connects to directly, each added as its own entry in VS Code's MCP config. See the "Connect the other MCP sources" step in SETUP-MAC.md / SETUP-WINDOWS.md. Rally is used read-only (lookup/search/hierarchy).
All data is stored locally:
~/.contextforge/
├── contextforge # MCP server binary
├── contextforge.db # SQLite database (all workspaces, all IDEs)
├── models/ # ONNX embedding model (optional, for vector search)
│ └── Xenova/all-MiniLM-L6-v2/
├── inbox/ # Conversations queued by capture extensions
│ ├── <session-id>.json # Pending conversations (processed on next MCP call)
│ └── .processed # Log of already-processed session IDs
└── node_modules/ # Native addons
└── better-sqlite3/ # SQLite native binding
# Agent instructions (VS Code / Cursor)
~/Library/Application Support/Code/User/prompts/
└── contextforge.instructions.md # Tells agents to use memory tools automatically
# MCP config (VS Code / Cursor)
~/Library/Application Support/Code/User/mcp.json
- Binary + native addon: ~69 MB
- Typical database size: 1-10 MB for hundreds of conversations
- Compare: raw conversation storage would be 100-1000 MB for the same data
# Simply copy the database file
cp ~/.contextforge/contextforge.db ~/backup/contextforge.db# Delete the database and start fresh
rm -rf ~/.contextforge/contextforge.db
# The next MCP tool call will create a new empty databaseagent-plugin-optimize-prompt-history/
├── package.json # Root workspace config
├── tsconfig.base.json # Shared TypeScript config
├── packages/
│ ├── core/ # MCP server + graph engine
│ │ ├── src/
│ │ │ ├── index.ts # Public API exports
│ │ │ ├── models.ts # TypeScript types (Entity, Relation, Fact, etc.)
│ │ │ ├── schema.ts # SQLite schema initialization (tables, indexes, FTS5, vec0)
│ │ │ ├── database.ts # MemoryDatabase — SQLite wrapper with graph-like queries
│ │ │ ├── extractor.ts # Rule-based knowledge extraction
│ │ │ ├── mcp.ts # MCP stdio server (entry point for binary)
│ │ │ └── __tests__/
│ │ │ └── extractor.test.ts # Unit tests for extraction (7 tests)
│ │ ├── build.js # Build pipeline (esbuild → obfuscate → pkg → release)
│ │ ├── package.json
│ │ └── tsconfig.json
│ ├── vscode-extension/ # VS Code capture extension
│ │ ├── src/
│ │ │ ├── extension.ts # Main entry point, command registration
│ │ │ ├── capture.ts # Chat session file watcher + debounced capture
│ │ │ ├── sessionParser.ts # JSONL event log parser for Copilot Chat sessions
│ │ │ ├── chatParticipant.ts # @memory chat participant (manual save/search/status)
│ │ │ ├── inbox.ts # Writes to ~/.contextforge/inbox/ queue
│ │ │ └── statusBar.ts # Status bar integration
│ │ └── package.json # Extension manifest with contributions
| Component | Technology | License |
|---|---|---|
| Database | SQLite (better-sqlite3 + sqlite-vec + FTS5) | MIT / Public Domain |
| MCP protocol | @modelcontextprotocol/sdk | MIT |
| Bundler | esbuild | MIT |
| Binary packaging | @yao-pkg/pkg | MIT |
| Code protection | javascript-obfuscator | BSD-2 |
| Monorepo | npm workspaces | — |
Everything runs 100% locally. No cloud services, no API keys, no telemetry, no internet required.
| Capability | Copilot Native | ContextForge |
|---|---|---|
| Search current workspace files | ✅ | ✅ |
| Remember decisions across conversations | ❌ (forgets on close) | ✅ |
| Recall "why did we choose X?" weeks later | ❌ | ✅ |
| Headless agents (no IDE) get memory | ❌ | ✅ |
| Per-agent isolated memory (test ≠ dev) | ❌ | ✅ |
| Works with any LLM (Claude, GPT, Llama) | ❌ (Copilot only) | ✅ |
| Time-based queries ("what broke last week?") | ❌ | ✅ |
| Survives machine rebuild (backup/restore) | ❌ | ✅ |
-
Close VS Code, reopen, ask "what was the last decision we made?" — Copilot draws a blank, ContextForge answers immediately.
-
Spin up a headless test agent — it already knows the codebase conventions from past runs without re-reading everything.
-
Ask "what errors have we hit in this project?" — ContextForge recalls the full history; Copilot only knows what's in the current code/logs.
-
Two agents, same repo, different roles — show test-agent has zero knowledge of developer-agent's shortcuts/biases.
Copilot searches your code. ContextForge searches your decisions — across sessions, agents, and time.
The workspace search Copilot does is just grepping files. ContextForge stores the reasoning and context that isn't in any file — architecture decisions, past errors, why something was done a certain way.
Copyright 2026 Vikas Rai
Licensed under the Apache License, Version 2.0. See LICENSE for the full license text.