Eight layers, three databases, one runtime contract. Syntax is deterministic. Meaning is agent-driven. Every claim carries its grounding.
The layers map loosely onto the DIKW pyramid: raw data at the bottom, derived meaning at the top. Each layer has its own SQLite table family. Edges cross layers explicitly via foreign keys.
| Layer | Content | Produced by |
|---|---|---|
| L0 Code Structure | symbols, calls, imports, fields, SQL tables | deterministic (tree-sitter / regex DDL) |
| L0.5 Code Analysis | per-file summaries, architectural layer, tags | tree-sitter structure + agents (FileAnalyzer · ArchitectureAnalyzer) |
| L1 Conversations | sessions, turns, tool calls | deterministic (file parsers) |
| L1.5 Triage | Relevance / Domain / Quality / Linkage labels | agent (Triage) |
| L2 Facts | decisions, business rules, intents, problems, solutions | agents (Decision · BusinessLogic · Intent · ProblemSolution) + syntax pass |
| L2.5 Domain enrichment | dependencies, skills, entities, relationships, industry, gaps | manifests + SQL (structural) · Reconciler · agents (TechnicalProfiler · DomainModeler · IndustryClassifier · IndustryEnricher) |
| L3 Concepts | clustered facts with names + structured summaries, scope-tagged | agents (Clusterer · Summarizer) |
| L4 Cross-Project | shared concepts between repos | mechanical (exact + SimHash) + agent (Linker) |
| L5 Skill graph | technical + industry skills aggregated across all projects | mechanical aggregation over L2.5 evidence |
Two tags on every knowledge node keep objective fact separate from inference. They are the mechanism behind "based on facts, never assume."
scope — technical (architecture) ·
industry (business domain) · meta.
| grounding | meaning | source |
|---|---|---|
structural | objective, parsed from artifacts | code symbols, SQL schema, manifests |
stated | asserted in a conversation | extracted facts |
corroborated | stated and matched to a code entity | the Reconciler |
external | cited from outside the project | research backend (opt-in) |
model | the agent's own inference | enrichment agents |
Project-truth queries default to structural / stated /
corroborated. external and model are
opt-in and always filterable, so "fill the gap" knowledge never gets mistaken
for what your project actually does. codegps status breaks every
layer down by both scope and grounding.
Each ingest run pulls new turns, segments them into windows, and routes each window through the deterministic syntax pass and the agent stack. Inputs flow top-down; outputs accumulate as edges back into earlier layers.
Enrichment stages (L2.5)
dependency / tool facts (structural). Monorepos with nested manifests are fully covered.entity facts and foreign keys to relates_to edges (structural).same_as and upgrades grounding to corroborated.model/external learning targets.knowledge_gap nodes; names the gap, never the answer.Deterministic stages
code.db and write a k_to_code edge.Agent stages
There are eighteen chat agents and one embedding-only agent. Each has a
versioned prompt, a JSON schema, and a model reference resolved from
config. All share a single runtime that handles caching, validation, and
persistence. Agent-bound calls run with bounded concurrency
(config.concurrency).
| Agent | Input | Output | Default routing |
|---|---|---|---|
triage | turn window text | 4-axis labels + kept/dropped | every new window |
dedupe | text | embedding vector | every kept window + every new fact |
decision | window | decisions / constraints / patterns | kept windows with signal-grade quality |
businessLogic | window | business rules / entities / constraints | domain ∈ {business_logic, architecture} |
intent | window | user intents | most engineering domains |
problemSolution | window | (problem, solution) pairs | domain ∈ {debugging, implementation} |
clusterer | new fact + top-K candidate concepts | attach / create / merge | each new fact |
summarizer | concept + member facts | name + structured summary | each touched concept |
fileAnalyzer | file defs + imports + calls + source slice | summary + layer + tags + concepts | analysis (L0.5), per file |
architectureAnalyzer | per-directory layer histogram | canonical layer per directory | analysis (L0.5) |
technicalProfiler | languages + dependencies | technical skills | enrichment (L2.5) |
domainModeler | entities + evidence | relationships / gaps (evidence-enforced) | enrichment (L2.5) |
industryClassifier | stack + symbols + README + entities + rules | industry label + confidence + evidence | enrichment (L2.5) |
industryEnricher | industry + present concepts | industry-standard concepts (model/external) | enrichment (L2.5) |
domainAnalyzer | industry + skills + layers + facts | composite portfolio highlights (evidence-cited) | enrichment (L2.5) |
profileWriter | global industries + skills + highlights | portfolio/background markdown | profile --prose (global) |
linker | two cross-project concepts | same_as / variant_of / supersedes / contradicts / none | cross-project candidate pairs |
verifier | pair of same-cluster facts | consistent / contradicts / supersedes | periodic sweep |
Every agent call goes through one function. Inputs are a typed payload
plus the agent's prompt and schema; outputs are validated JSON, cached
by content hash, and persisted to agent_runs for audit.
interface Agent<I, O> {
name: string;
promptVersion: number; // bump invalidates cache
modelKey?: string; // overrides config lookup
schema: JsonSchema; // strict validation
prompt(input): ChatMessage[];
postprocess?(o, input): { output, confidence };
}
interface AgentRuntime {
run<I, O>(agent, input): Promise<{ output, confidence, model, cached }>;
// 1. hash(agent.name + model + prompt_version + input) -> cache lookup
// 2. call backend (Ollama / OpenAI-compatible / Anthropic)
// 3. parse JSON; validate against schema; one repair retry on failure
// 4. write to agent_runs (success or failure)
}
Cache invariants
promptVersion → all prior runs ignored, agent re-runs<project>/.codegps/
├── code.db # L0 — codegraph-compatible schema
│ ├── nodes (id, kind, name, qualified_name, file_path, ...)
│ ├── edges (source, target, kind, line, col, provenance)
│ ├── files (path, content_hash, indexed_at, ...)
│ ├── file_analysis (L0.5 — summary, layer, tags per file)
│ ├── nodes_fts (FTS5 over names / signatures / docstrings)
│ └── unresolved_refs
│
├── knowledge.db # L1, L1.5, L2, L2.5, L3 + agent cache
│ ├── sessions / turns / tool_calls
│ ├── turns_fts (FTS5 over turn text)
│ ├── turn_windows / triage_labels
│ ├── k_nodes (+ scope, grounding, source_url columns)
│ ├── k_edges / k_provenance / k_to_code
│ ├── k_nodes_fts (FTS5 over fact titles + summaries)
│ ├── k_node_embeddings (sidecar — keeps k_nodes lean)
│ ├── concepts (+ scope, grounding columns)
│ ├── research_cache (external lookups, opt-in)
│ └── agent_runs (cache + audit)
│
└── canvas/ # generated .canvas.tsx artifacts
~/.codegps/
├── global.db
│ ├── projects
│ ├── concepts_global (mirrors per-project concepts with embeddings)
│ ├── concept_links (a, b, kind, score, source)
│ ├── skills (L5 — name, scope, evidence_weight, project_count)
│ ├── skill_evidence (per-project evidence behind each skill)
│ ├── industries (classified business domains across projects)
│ ├── highlights (composite portfolio statements per project)
│ └── agent_runs (cache + audit for global agents, e.g. ProfileWriter)
└── config.json
Three databases, three responsibilities. The split keeps the code DB
drop-in for codegraph
users and lets the knowledge schema evolve independently. Knowledge-schema
columns (scope, grounding, …) are added via additive
migrations, so existing databases upgrade in place.
| Extensions | Language | Engine |
|---|---|---|
.ts .tsx .mts .cts .js .jsx .mjs .cjs | TypeScript / JavaScript | tree-sitter |
.py | Python | tree-sitter |
.dart | Dart | tree-sitter |
.go | Go | tree-sitter |
.rs | Rust | tree-sitter |
.java | Java | tree-sitter |
.cs | C# | tree-sitter |
.sql .ddl | SQL DDL | regex parser |
Adding a language: a new entry in src/code/languages.ts plus
~50 lines of node-type handlers in src/code/extractor.ts.
Tree-sitter WASMs for Swift, Kotlin, PHP, Ruby, C, and C++ are already
shipped in tree-sitter-wasms and only need wiring.
| Source | Location | Coverage |
|---|---|---|
| Cursor | ~/.cursor/projects/<slug>/agent-transcripts/<uuid>/<uuid>.jsonl | full + tool calls |
| Claude Code | ~/.claude/projects/<slug>/*.jsonl | full + tool calls |
| Codex CLI | ~/.codex/sessions/**/*.jsonl | filtered by cwd metadata |
| GitHub Copilot Chat | VS Code workspace storage | best-effort (private API) |
(agent, model, input_hash, prompt_version). Bumping the prompt version invalidates the cache by design.codegps link --rebuild triggers a full recompute when the drift becomes visible.codegps ingest (or call codegps_ingest via MCP) to pick up new sessions.project_metadata JSON rather than schema changes.triage audit --dropped lets you tune.