Architecture

Eight layers, three databases, one runtime contract. Syntax is deterministic. Meaning is agent-driven. Every claim carries its grounding.

on this page

Layered model

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.

LayerContentProduced by
L0 Code Structuresymbols, calls, imports, fields, SQL tablesdeterministic (tree-sitter / regex DDL)
L0.5 Code Analysisper-file summaries, architectural layer, tagstree-sitter structure + agents (FileAnalyzer · ArchitectureAnalyzer)
L1 Conversationssessions, turns, tool callsdeterministic (file parsers)
L1.5 TriageRelevance / Domain / Quality / Linkage labelsagent (Triage)
L2 Factsdecisions, business rules, intents, problems, solutionsagents (Decision · BusinessLogic · Intent · ProblemSolution) + syntax pass
L2.5 Domain enrichmentdependencies, skills, entities, relationships, industry, gapsmanifests + SQL (structural) · Reconciler · agents (TechnicalProfiler · DomainModeler · IndustryClassifier · IndustryEnricher)
L3 Conceptsclustered facts with names + structured summaries, scope-taggedagents (Clusterer · Summarizer)
L4 Cross-Projectshared concepts between reposmechanical (exact + SimHash) + agent (Linker)
L5 Skill graphtechnical + industry skills aggregated across all projectsmechanical aggregation over L2.5 evidence

Scope × grounding

Two tags on every knowledge node keep objective fact separate from inference. They are the mechanism behind "based on facts, never assume."

scopetechnical (architecture) · industry (business domain) · meta.

groundingmeaningsource
structuralobjective, parsed from artifactscode symbols, SQL schema, manifests
statedasserted in a conversationextracted facts
corroboratedstated and matched to a code entitythe Reconciler
externalcited from outside the projectresearch backend (opt-in)
modelthe agent's own inferenceenrichment 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.

Pipeline

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.

flowchart TB raw[L1 raw turns] --> seg[Window Segmenter] seg --> syn[Syntax Pass] seg --> tri[Triage Agent] tri -->|kept| ded[Dedupe Agent] ded -->|novel| route{Route by domain} route --> dec[Decision] route --> biz[BusinessLogic] route --> int[Intent] route --> ps[ProblemSolution] syn --> facts[L2 facts] dec --> facts biz --> facts int --> facts ps --> facts facts --> res[Code Resolver] facts --> clu[Clusterer] clu --> sum[Summarizer] sum --> concepts[L3 concepts] facts --> enr[L2.5 Enrichment] code[L0 code + manifests] --> enr enr --> entities[entities / relationships / skills / industry / gaps] concepts --> link[Linker + mechanical] entities --> link link --> global[L4 links + L5 skills] facts --> ver[Verifier]

Enrichment stages (L2.5)

Deterministic stages

Agent stages

The agent layer

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).

AgentInputOutputDefault routing
triageturn window text4-axis labels + kept/droppedevery new window
dedupetextembedding vectorevery kept window + every new fact
decisionwindowdecisions / constraints / patternskept windows with signal-grade quality
businessLogicwindowbusiness rules / entities / constraintsdomain ∈ {business_logic, architecture}
intentwindowuser intentsmost engineering domains
problemSolutionwindow(problem, solution) pairsdomain ∈ {debugging, implementation}
clusterernew fact + top-K candidate conceptsattach / create / mergeeach new fact
summarizerconcept + member factsname + structured summaryeach touched concept
fileAnalyzerfile defs + imports + calls + source slicesummary + layer + tags + conceptsanalysis (L0.5), per file
architectureAnalyzerper-directory layer histogramcanonical layer per directoryanalysis (L0.5)
technicalProfilerlanguages + dependenciestechnical skillsenrichment (L2.5)
domainModelerentities + evidencerelationships / gaps (evidence-enforced)enrichment (L2.5)
industryClassifierstack + symbols + README + entities + rulesindustry label + confidence + evidenceenrichment (L2.5)
industryEnricherindustry + present conceptsindustry-standard concepts (model/external)enrichment (L2.5)
domainAnalyzerindustry + skills + layers + factscomposite portfolio highlights (evidence-cited)enrichment (L2.5)
profileWriterglobal industries + skills + highlightsportfolio/background markdownprofile --prose (global)
linkertwo cross-project conceptssame_as / variant_of / supersedes / contradicts / nonecross-project candidate pairs
verifierpair of same-cluster factsconsistent / contradicts / supersedesperiodic sweep

Agent runtime

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

Storage

<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.

Languages

ExtensionsLanguageEngine
.ts .tsx .mts .cts .js .jsx .mjs .cjsTypeScript / JavaScripttree-sitter
.pyPythontree-sitter
.dartDarttree-sitter
.goGotree-sitter
.rsRusttree-sitter
.javaJavatree-sitter
.csC#tree-sitter
.sql .ddlSQL DDLregex 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.

Conversation sources

SourceLocationCoverage
Cursor~/.cursor/projects/<slug>/agent-transcripts/<uuid>/<uuid>.jsonlfull + tool calls
Claude Code~/.claude/projects/<slug>/*.jsonlfull + tool calls
Codex CLI~/.codex/sessions/**/*.jsonlfiltered by cwd metadata
GitHub Copilot ChatVS Code workspace storagebest-effort (private API)

Design trade-offs