Architecture Overview
System components, data flow, and how everything connects.
System Components
ContextManager is a VS Code extension with the following core subsystems:
graph TB
LMT[Language Model Tools - 5 tools] --> PM[Project Manager]
DASH[Dashboard - 5 tabs] --> PM
PM --> AC[Auto-Capture Service]
AC --> AL[Auto-Learn Pipeline]
AC --> SI[Search Index - SQLite FTS4]
HW[Hook Watcher] --> AC
GI[GitHub Instructions Manager] --> PM
HW -.-> HQ
subgraph FS[File System]
HQ[hook-queue.jsonl]
SC[capture.ps1 / capture.sh]
CTX[session-context.txt]
end
style LMT fill:#1f6feb,stroke:#388bfd,color:#fff
style DASH fill:#1f6feb,stroke:#388bfd,color:#fff
style PM fill:#1158c7,stroke:#388bfd,color:#fff
style AC fill:#1158c7,stroke:#388bfd,color:#fff
style AL fill:#1158c7,stroke:#388bfd,color:#fff
style SI fill:#238636,stroke:#3fb950,color:#fff
style HW fill:#9e6a03,stroke:#d29922,color:#fff
style GI fill:#238636,stroke:#3fb950,color:#fff
Technology Stack
| Component | Technology |
|---|---|
| Language | TypeScript (ES2022) |
| Runtime | VS Code Extension Host (Node.js) |
| Database | SQLite via sql.js (WebAssembly) — FTS4 with BM25 |
| Storage | JSON files on disk (globalStorageUri) |
| Dashboard | WebView (HTML/CSS/JS, Content Security Policy) |
| Rendering | Markdown + KaTeX (LaTeX) + Mermaid (styled blocks) |
| Search | BM25 from matchinfo('pcnalx') with per-column weights |
| Agent Hooks | PowerShell/Bash scripts via VS Code chat hooks API |
| AI | VS Code Language Model API (vscode.lm) |
| Testing | Vitest |
Component Details
1. Language Model Tools (5 tools)
Registered via vscode.lm.registerTool(). Available to all agents:
// Registration pattern (src/tools/index.ts → registerTools())
vscode.lm.registerTool('contextManager_ctx', handler); // #ctx — unified search/list/learn/getCard/queue/fetch/retrospect
vscode.lm.registerTool('contextManager_getCard', handler); // #getCard — read full card by ID
vscode.lm.registerTool('contextManager_saveKnowledgeCard', handler); // #saveCard
vscode.lm.registerTool('contextManager_editKnowledgeCard', handler); // #editCard
vscode.lm.registerTool('contextManager_organizeKnowledgeCards', handler); // #organizeCards — folder management
Each tool includes disambiguation entries that help Copilot decide when to auto-invoke.
Conditional registration: ctx requires SearchIndex. If the dependency isn’t available at activation, the tool won’t be registered at runtime.
Dead/orphaned tool files: projectContextTool.ts (deprecated), projectIntelligenceTool.ts (orphaned — functionality merged into CtxTool), todoManagerTool.ts (imported but never registered).
2. Project Manager
Central data store (src/projects/ProjectManager.ts, ~2000 lines) managing:
- Projects — metadata, root paths, goals, conventions
- Session routing state — tracked chat sessions, binding segments, pending hook events
- Knowledge Cards — CRUD, folders, flags, progressive disclosure
- Project Intelligence — conventions, tool hints, working notes
- Todos — user-managed task items
- Events —
onDidChangeActiveProject,onDidChangeProjects,onDidChangeSessionTracking,onDidChangeCache
Data persists to JSON files in globalStorageUri with in-memory caching for zero-overhead reads. Storage layer (storage.ts) handles disk I/O and globalState for metadata, including projects.json and session-routing.json.
3. Auto-Capture Service
Listens to all chat interactions from all participants (src/autoCapture.ts, ~1050 lines):
graph LR
A[Model Response] --> B[Strip Private Tags]
B --> C[DJB2 Content Hash]
C --> D[Dedup Check - 30s window]
D --> E[Typed Observation Buffer]
E --> F[FTS4 Indexing]
E --> G[Intelligence Extraction]
G --> H[Conventions]
G --> I[Working Notes]
style A fill:#1f6feb,stroke:#388bfd,color:#fff
style E fill:#1158c7,stroke:#388bfd,color:#fff
style G fill:#1158c7,stroke:#388bfd,color:#fff
style H fill:#238636,stroke:#3fb950,color:#fff
style I fill:#238636,stroke:#3fb950,color:#fff
Key features:
- Content-hash deduplication — dual DJB2 hash with 30-second window (
DEDUP_WINDOW_MS) - Typed observations — 6 types: bugfix, feature, discovery, decision, refactor, change (classified via keyword scoring)
- Privacy tag stripping —
<private>...</private>replaced with[REDACTED] - Multi-turn extraction — iterative convention extraction for PreCompact events
- Auto-distill — periodic background distillation to knowledge card candidates (rate-limited, min 4 observations)
- Anchor extraction — identifies load-bearing tool results for knowledge cards
- Tool call capture — separate path (
captureToolCalls()) creating per-tool-call observations - Configurable buffer — default
MAX_OBSERVATIONS = 50, overridable via settings
4. Auto-Learn Pipeline
Intelligence extraction via LLM (src/autoLearn.ts, ~790 lines):
- LLM extraction — lightweight calls (~200 input tokens) for conventions and working notes
- Regex fallback — if no LM available, regex-based extraction for tool hints (always regex, high precision)
- Hard caps with decay — 30 working notes, 20 tool hints, 15 conventions; oldest-inferred eviction
- Feedback loop — discard counters suppress over-discarded categories; confirming resets
- All intelligence saved as
confidence: 'inferred'— nothing auto-confirmed
5. Search Index
SQLite FTS4 via sql.js WebAssembly with 8 virtual tables (src/search/SearchIndex.ts, ~1450 lines):
| Table | FTS-Indexed Columns | Weights (title/primary=10, content=5) |
|---|---|---|
cards_fts | title, content, category, tags, source | 10, 5, 2, 1, 1 |
cache_fts | symbol_name, content, file_path | 5, 5, 2 |
learnings_fts | subject, content, related_files, related_symbols | 10, 5, 2, 2 |
observations_fts | prompt, response_summary, files_referenced, tool_calls | 10, 5, 3, 2 |
agent_messages_fts | content | 5 |
todos_fts | title, description, notes | 10, 5, 3 |
projects_fts | name, description, goals, conventions | 5, 3, 3, 2 |
sessions_fts | branch_name, task, goal, current_state, approaches, decisions, next_steps, blockers | 5, 10, 5, 3, 2, 2, 2, 2 |
BM25 ranking uses JavaScript-computed scores from matchinfo('pcnalx') with standard parameters (k1=1.2, b=0.75). Over-fetches 3× the limit from SQLite, ranks in JS, then trims. Automatic OR fallback if AND query returns 0 results.
6. Hook Watcher
File system watcher on ~/.contextmanager/hook-queue.jsonl (src/hooks/HookWatcher.ts, ~400 lines):
- Uses native
fs.watch()with 400ms debounce - Reads queue file as raw Buffer for accurate byte offsets with multi-byte UTF-8
- Parses new JSONL lines into typed
HookEntryobjects - Routes to handler by
hookType— 4 handled event families:SessionStart→ tracked-session registration and session metadata refresh (no capture materialization)Stop→autoCapture.onModelResponse()+ card queue candidate (gated byhooks.stopsetting)PostToolUse→ tool-call observation with parsed input summary (gated byhooks.postToolUsesetting)PreCompact→ multi-turn extraction viaextractMultiTurnLearnings()+distillAndSaveBackground()(gated byhooks.preCompactsetting)
- Advances byte offset and persists to
~/.contextmanager/.queue-offset - On startup, processes any backlog before starting the watcher; snaps to end if offset exceeds file size
Queueing behavior in multi-project mode: if a hook event arrives for an unbound session and no exact project hint resolves it, the event is queued as pending until the user binds that session from the Dashboard → Sessions tab.
Configured but unhandled hooks: SubagentStart and UserPromptSubmit remain shell-script level only.
7. Supporting Services
| Service | File | Role |
|---|---|---|
| GitHubInstructionsManager | githubInstructions.ts | Syncs .github/copilot-instructions.md with pinned cards and tool discovery hints |
| ConfigurationManager | config.ts | Centralized, type-safe access to all extension settings |
| ExplanationCache | cache.ts | Internal cache of explanations — used by dashboard and commands (not exposed as LM tools) |
| BackgroundTasks | backgroundTasks.ts | Background task queue running LLM agent loops with live dashboard progress |
| FileSync | fileSync.ts | File-based sync for knowledge cards via git-tracked .contextmanager/ directory |
| Sidebar | sidebar/ProjectsTreeProvider.ts | Tree view provider for the Projects sidebar panel |
Data Flow
Knowledge Card Lifecycle
graph LR
subgraph Discovery
A1["saveAsCard command"]
A2["save tool"]
A3[Card Queue Distill]
A4[Auto-Distill]
end
subgraph Curation
B1[Dashboard Edit]
B2["edit tool"]
B3["organize tool"]
B4[Smart Merge via LLM]
end
subgraph Injection
C1[copilot-instructions.md]
C2["#ctx tool - search/list"]
C3["#getCard - full content"]
end
A1 --> B1 --> C1
A2 --> B2 --> C2
A3 --> B3 --> C3
A4 --> B4 --> C3
Intelligence Pipeline
graph TD
A[Any Chat Response] --> B[Auto-Capture]
B --> C["Observation Buffer (default 50)"]
C --> D["Auto-Learn (LLM or regex fallback)"]
D --> E[Conventions + Tool Hints + Working Notes]
E --> F1["GitHubInstructionsManager → copilot-instructions.md"]
F1 --> F1a[Pinned cards + tool discovery]
E --> F2["#ctx tool — on-demand search/list/learn/retrospect"]
C --> G["Auto-Distill → Card Queue candidates"]
style A fill:#1f6feb,stroke:#388bfd,color:#fff
style C fill:#1158c7,stroke:#388bfd,color:#fff
style D fill:#1158c7,stroke:#388bfd,color:#fff
style E fill:#238636,stroke:#3fb950,color:#fff
style F1 fill:#238636,stroke:#3fb950,color:#fff
style F2 fill:#238636,stroke:#3fb950,color:#fff
style G fill:#238636,stroke:#3fb950,color:#fff
Hook Pipeline (VS Code Copilot)
graph TD
A[VS Code Copilot Chat] --> B[PostToolUse hook fires]
B --> C[capture.ps1 / capture.sh]
C --> D[Find Copilot transcript]
D --> E[Get-LastCompletedTurn]
E --> F[Write Stop entry to queue]
F --> G["HookWatcher detects change (fs.watch + 400ms debounce)"]
G --> H[Card Queue Candidate]
G --> I[Typed Observation Buffer]
I --> J[FTS4 Index]
style A fill:#1f6feb,stroke:#388bfd,color:#fff
style C fill:#9e6a03,stroke:#d29922,color:#fff
style G fill:#1158c7,stroke:#388bfd,color:#fff
style H fill:#238636,stroke:#3fb950,color:#fff
style I fill:#238636,stroke:#3fb950,color:#fff
style J fill:#238636,stroke:#3fb950,color:#fff
Dashboard
The WebView dashboard has 5 tabs:
| Tab | ID | Contents |
|---|---|---|
| 🧠 Intelligence | intelligence | Auto-Learn & Auto-Capture controls, observation stats (24h/90d), toggle switches |
| Knowledge | knowledge | 3 sub-tabs: Workbench (conventions, notes, hints), Knowledge Cards (full card list + editor), Card Queue (AI candidates) |
| Sessions | sessions | Tracked chat sessions, pending capture counts, bind/rebind actions, dismiss/forget controls |
| Context | context | Project context editor (goals, conventions, tech stack) included in AI prompts |
| ⚙ Settings | settings | Extension settings UI with grouped sections |
Directory Structure
ContextManager/
├── src/
│ ├── extension.ts # Activation — wires all subsystems
│ ├── autoCapture.ts # Auto-capture service (~1050 lines)
│ ├── autoLearn.ts # Intelligence extraction via LLM (~790 lines)
│ ├── backgroundTasks.ts # Background task queue with LLM agent loops
│ ├── cache.ts # ExplanationCache — internal data layer
│ ├── commands.ts # VS Code command registrations
│ ├── config.ts # ConfigurationManager — type-safe settings
│ ├── fileSync.ts # Git-tracked .contextmanager/ sync + markdown import
│ ├── githubInstructions.ts # copilot-instructions.md managed block
│ ├── prompts.ts # System prompt templates for explanation commands
│ │
│ ├── dashboard/
│ │ ├── DashboardPanel.ts # WebView dashboard (5 tabs, ~1500 lines)
│ │ ├── cardCanvas.ts # Card tile rendering & tool-call viewer
│ │ ├── index.ts # Barrel export
│ │ ├── htmlHelpers.ts # HTML generation (escapeHtml, renderMarkdown, KaTeX)
│ │ ├── messageHandler.ts # WebView ↔ extension message handler (~1800 lines)
│ │ ├── styles.ts # Dashboard CSS (~1570 lines)
│ │ ├── webviewScript.ts # Client-side JS (~2700 lines)
│ │ └── __tests__/
│ │ └── htmlHelpers.test.ts
│ │
│ ├── hooks/
│ │ └── HookWatcher.ts # File watcher for hook-queue.jsonl
│ │
│ ├── projects/
│ │ ├── ProjectManager.ts # Central data store (~2000 lines)
│ │ ├── storage.ts # Persistence: globalStorageUri + globalState
│ │ └── types.ts # Interfaces & factory functions (~440 lines)
│ │
│ ├── search/
│ │ ├── SearchIndex.ts # SQLite FTS4 via sql.js (~1450 lines)
│ │ └── types.ts # Search entity types, result interfaces
│ │
│ ├── sidebar/
│ │ └── ProjectsTreeProvider.ts # Tree view provider for Projects panel
│ │
│ ├── tools/
│ │ ├── index.ts # Barrel + registerTools()
│ │ ├── searchTools.ts # CtxTool (~450 lines)
│ │ ├── knowledgeCardTools.ts # Save/Edit/Organize/GetCard tools (~450 lines)
│ │ ├── projectContextTool.ts # DEPRECATED — not registered
│ │ ├── projectIntelligenceTool.ts # ORPHANED — merged into CtxTool
│ │ └── todoManagerTool.ts # DEAD — imported but never registered
│ │
│ └── utils/
│ ├── gitUtils.ts # Git helpers (branch, diff, log)
│ ├── symbolUtils.ts # VS Code symbol/selection helpers
│ ├── toolFilter.ts # Tool filtering & name normalization
│ └── toolUsageExtractor.ts # Tool-call pattern extraction for cards
│
├── resources/
│ └── hooks/
│ ├── capture.ps1 # Agent hook script (Windows)
│ ├── capture.sh # Agent hook script (macOS/Linux)
│ └── hooks.json # Hook type declarations
│
├── media/
│ └── mermaid.min.js # Bundled Mermaid for dashboard rendering
│
├── out/ # Compiled JavaScript
├── docs/ # Documentation site (Jekyll)
└── package.json # Extension manifest