How the Cypher Query Engine in DeusData's codebase-memory Executes openCypher-Style Queries Against the Code Graph
The Cypher query engine translates a subset of OpenCypher syntax into read-only SQLite SQL statements, executing them against the cbm_store graph database while enforcing strict safety limits on recursion and variable binding.
The DeusData/codebase-memory-mcp repository implements a lightweight, read-only Cypher query engine that enables developers to explore code relationships using familiar graph query syntax. Unlike full graph databases, this engine compiles openCypher-style queries into efficient SQL operations against an underlying SQLite store, making it ideal for static analysis of repository structures without external dependencies.
Architecture of the Cypher Query Engine
The engine resides entirely within the src/cypher package and consists of five tightly integrated components that transform query strings into result sets:
- Lexer – Tokenizes input strings into identifiers, literals, and operators via the
cbm_lexfunctions defined insrc/cypher/cypher.c(lines 145-190). - Parser – A recursive-descent parser constructs an abstract syntax tree (AST) for clauses like MATCH, WHERE, RETURN, OPTIONAL MATCH, and UNION, respecting a nesting depth limit of approximately 5 levels specified in
src/foundation/recursion_whitelist.h. - Planner – Walks the AST to resolve labels, relationship types, and variable bindings, producing a logical plan that maps graph traversals to SQL joins. The planner rejects unsupported write operations (CREATE, DELETE, MERGE) early with explicit error messages (lines 817-839 of
cypher.c). - Executor – Renders the logical plan into a safe SQL string and dispatches it to
cbm_storeviacbm_sql_execute, streaming rows back as JSON values. - Safety Layer – Sandboxes the translation step to ensure only read-only SQL constructs are generated, with the SQLite authorizer blocking privileged statements like
ATTACH.
Lexing and Parsing Pipeline
Query processing begins in src/cypher/cypher.c where the cbm_lex tokenizer breaks the input into a token stream. The parser then builds an AST while enforcing hard limits on query complexity.
The recursive-descent parser specifically monitors nesting depth using constants defined in src/foundation/recursion_whitelist.h (lines 7-12). If a query exceeds the configured depth limit or attempts to bind more than CYP_MAX_VARS (16) variables, the engine returns an error before planning begins.
Query Planning and SQL Translation
Once parsed, the AST enters the planning phase where graph patterns convert to relational operations. The planner analyzes node labels and relationship types to generate efficient SQLite join structures that represent graph traversals.
Write operations are explicitly prohibited during this phase. If the planner encounters CREATE, DELETE, or MERGE clauses, it immediately aborts with a clear error message, ensuring the cbm_store remains immutable from the query interface.
Execution Flow and Safety Guarantees
The execute_cypher_query function (lines 324-360 of cypher.c) orchestrates the final execution:
- Input Validation – Accepts the Cypher string through the
query_graphinterface. - SQL Generation – Converts the logical plan into a parameterized SQLite query.
- Authorization Check – The SQLite authorizer validates that no privileged operations (e.g.,
ATTACH,PRAGMA) are present, as verified by test cases intests/test_security.c(lines 293-314). - Result Streaming – Executes against
cbm_storeand converts SQLite types to JSON for API consumption or tabular output for CLI users.
This read-only architecture guarantees that even compromised query strings cannot modify the underlying code graph.
Invoking the Engine via query_graph
The engine exposes functionality through the query_graph tool, available in both the CLI and JSON-RPC API.
Command Line Usage:
# List all functions that call `init` (up to 20 results)
query_graph --query "MATCH (caller)-[:CALLS]->(callee {name: 'init'}) RETURN caller.name, callee.name LIMIT 20"
JSON-RPC API:
POST /api/query_graph
Content-Type: application/json
{
"query": "MATCH (n:Function)-[:CALLS]->(m:Function) WHERE n.name =~ '.*parse.*' RETURN n.name, m.name LIMIT 5"
}
Programmatic C Integration:
const char *cypher = "MATCH (a)-[:IMPORTS]->(b) RETURN a.name, b.name LIMIT 3";
struct cbm_result *res = NULL;
int rc = cypher_execute(store, cypher, &res);
if (rc == 0) {
// iterate over `res` rows …
}
Summary
- The Cypher query engine in DeusData/codebase-memory-mcp compiles openCypher-style queries into read-only SQLite SQL, executing against the cbm_store backend.
- The implementation spans
src/cypher/cypher.c(core engine),src/cypher/cypher.h(public API), andsrc/mcp/mcp.c(CLI routing). - Security is enforced through recursive depth limits, variable count caps (16 max), and SQLite authorizer hooks that block write operations.
- Developers access the engine via the
query_graphtool or thecypher_execute()C function, receiving results as JSON or tabular data.
Frequently Asked Questions
Is the Cypher query engine write-capable?
No. The engine is explicitly read-only. The parser rejects CREATE, DELETE, and MERGE clauses during the planning phase, and the SQLite authorizer blocks any SQL that attempts to modify the database schema or data, as demonstrated in tests/test_security.c.
What openCypher features are supported?
The engine supports MATCH, WHERE, RETURN, OPTIONAL MATCH, and UNION clauses. It handles node labels, relationship types, property filters, and limited regular expressions. Complex features like path variables, unwind operations, and subqueries are not implemented in the current version.
How does the engine prevent recursive query attacks?
The parser enforces a nesting depth limit of approximately 5 levels using the recursion whitelist defined in src/foundation/recursion_whitelist.h. Additionally, queries are limited to 16 variables (CYP_MAX_VARS), preventing resource exhaustion through deeply nested patterns.
Why translate Cypher to SQLite instead of using a native graph database?
Translating to SQLite allows the codebase-memory tool to remain self-contained without external database dependencies. The cbm_store is a single file that can be versioned, copied, and queried using standard SQL tooling while still presenting a familiar graph interface to developers via the Cypher query engine.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →