NxtSoftLabs
CGRAPH DOCS — CONTENTS
CGRAPH

Design Decisions

CGraph makes a handful of load-bearing decisions. This page states each one, why it was made, and what it costs.

Deterministic extraction

Decision. Extraction is deterministic — the same source tree always produces the same graph.

Why. An agent's answers shouldn't drift between runs, and a deterministic graph can be diffed. That diffability is what makes incremental updates and background persistence correct: the daemon can fold a change into the previous graph because it knows the previous graph was reproducible.

Tradeoff. Determinism means resolution is static. Dynamic dispatch, reflection, and runtime wiring can't always be resolved from source, so some edges are approximate. CGraph accepts approximate dynamic edges in exchange for a reproducible, diffable graph.

One operation handler

Decision. The MCP server's tool calls route through the same daemon operation handler as the thin client.

Why. An agent and a shell should get identical semantics. Sharing one code path means there's a single place to reason about correctness, and no drift between "what the CLI does" and "what the agent sees".

Tradeoff. The handler has to be general enough to serve both a human at a terminal and an agent over MCP — but that generality is cheaper than maintaining two parallel implementations.

A warm daemon

Decision. Offer a long-lived daemon (graphd) alongside the one-shot CLI.

Why. Rebuilding the graph on every query is wasteful for interactive use. Keeping it warm and folding edits in incrementally turns repeated queries from "rescan each time" into "answer from memory".

Tradeoff. A daemon is a process to manage — start, watch, idle-timeout, shut down. The one-shot cgraph stays available for CI and scripts where a resident process isn't wanted.

Adaptive gather

Decision. Default agent context to adaptive gather rather than a fixed k-hop.

Why. Expanding every third hop is expensive; expanding none loses relevant context. Adaptive gather keeps the full 2-hop core and expands the third hop only along query-relevant nodes — most of the recall for a fraction of the tokens (see Benchmarks).

Tradeoff. Adaptive gather needs a query to gate on; without one the relevance gate is a no-op and it falls back to fixed behavior.

Host-driven semantic enrichment

Decision. Semantic enrichment is host-driven: the host writes fragments; CGraph validates them and manages cache state.

Why. It keeps the deterministic core separate from open-ended semantic work. CGraph owns extraction, validation, and local mutation; the semantic model is supplied rather than guessed, and content-hash cache records keep it from being recomputed needlessly.

Tradeoff. Enrichment isn't automatic — it's a workflow the host drives. The base graph is useful on its own; enrichment is an opt-in layer.

Native C++

Decision. Build the engine in native C++20.

Why. Extraction and query latency are the product. A native engine keeps both low and makes the deterministic, incremental design practical at speed.

Tradeoff. A C++ build with CMake and vcpkg is heavier to set up than a scripting runtime (see Installation) — the cost paid once for speed paid back on every query.