CLI¶
The main kglite wheel includes the kglite command for working with .kgl
graph files without starting a server. It has two modes:
one-shot commands for scripts and agents
an interactive Cypher shell for humans
Install the Python API and CLI together:
pip install kglite
For a standalone CLI-only installation:
pip install kglite-cli
# or build the libpython-free binary from crates.io
cargo install kglite-cli
Both routes expose the same Rust CLI implementation. Do not install both into
one environment because they provide the same kglite command name.
Code-Review Skill¶
The code-review Agent Skill ships with codingest, the project that builds the code graphs it queries:
codingest skill install
A copy installed by the earlier kglite skill install is migrated
automatically: codingest skill install removes the CLI-managed legacy
directory when it installs its own, and leaves an unmanaged copy alone.
The skill still drives this CLI for querying. Build a working-tree graph, or a graph that spans a committed base and head revision:
# Code-graph builds moved to the codingest project (its CLI builds the .kgl):
# see the codingest README. Example shape:
# codingest build . --output .kglite/code-review.kgl
# codingest status --output .kglite/code-review.kgl
build writes a metadata sidecar with the source/revision fingerprint.
status reports fresh, stale, or missing without loading the graph. The
review workflow still calls describe before Cypher and verifies structural
results against exact source lines.
One-Shot Commands¶
Run a read-only Cypher query and exit:
kglite query app.kgl "MATCH (n:Person) RETURN n.name AS name" --format json
--format json emits one object per row, with the keys in the query’s own
column order — RETURN 1 AS zz, 2 AS aa yields {"zz": 1, "aa": 2}, the
same order --format csv writes its header in. The top-level shape is a
plain array, so jq '.[0].name' addresses the first row’s column.
Query deadlines¶
The CLI applies no query deadline by default. That is a declared
divergence, not an oversight: the Python API and the MCP server both default
to 180,000 ms, and the CLI does not, because Ctrl-C cancels a running read
here and a batch query over a Wikidata-scale graph legitimately runs for hours.
A silent three-minute kill would be the regression.
Bound one call with --timeout-ms, on query and on write:
kglite query app.kgl "MATCH (a)-[*1..6]-(b) RETURN count(*) AS n" --timeout-ms 30000
The query exits non-zero with the engine’s timeout message. --timeout-ms 0
is the same as omitting the flag. row_limit — the Python knob that caps the
rows a call retains — has no CLI spelling; write LIMIT n in the query,
which is what a one-shot command wants anyway.
Run a write statement and save the graph:
kglite write app.kgl "CREATE (:Task {id:'t1', status:'todo'})" \
--save \
--write-scope Task \
--git-sha abc123 \
--modified-by agent
--write-scope restricts a statement’s writes to the listed node
types. A node write—CREATE, INSERT, MERGE’s create arm, SET, REMOVE,
DELETE, NODETACH DELETE, DETACH DELETE, and index/constraint DDL—is judged by the
node’s stored type, so a pattern label cannot widen the scope. A
relationship write (a CREATE/INSERT relationship pattern, DELETE r, SET r.p,
REMOVE r.p) is allowed when at least one endpoint’s stored type is
listed: linking to a matched out-of-scope node is permitted, an edge
between two out-of-scope nodes is not. Relationship types themselves are
not scoped, and neither is db.cdc.enable/db.cdc.disable. Deleting a
node in scope removes its relationships whatever they point at.
--git-sha and --modified-by stamp provenance on auto_timestamp
types.
Inspect a dependency frontier:
kglite ready-set app.kgl \
--done 'n.status = "done"' \
--node-type Task \
--format csv
Print the agent-oriented graph description:
kglite describe app.kgl
kglite describe app.kgl --types Task
kglite describe app.kgl --cypher
kglite describe app.kgl --connections
describe returns the same XML schema document exposed by the Python API
and MCP server, including focused views for labels, Cypher support, and
connection types.
Agent Sessions¶
Use session when an agent needs multiple operations against the same
graph. The process keeps one graph loaded in memory and accepts JSONL
requests on stdin:
kglite session app.kgl --format json
Example request stream:
{"op":"help"}
{"op":"describe","types":["Task"]}
{"id":"w1","op":"write","query":"CREATE (:Task {id:'t1', status:'todo'})"}
{"id":"q1","op":"query","query":"MATCH (t:Task) RETURN count(t) AS n","format":"json"}
{"op":"save"}
{"op":"exit"}
Responses echo id when provided. In JSON mode, query and write
return typed rows; table and CSV modes return rendered output.
CSV is a machine format: integers, floats, timestamps, and values nested in lists or maps retain their available text precision, and RFC quoting preserves commas, quotes, CR, and LF. Table mode remains compact for people. As in normal CSV, an empty string and NULL are both empty fields; use JSON when that distinction matters.
{"op":"help"} answers with the op table — every op and its request
shape — so a driver that only has the pipe can discover the protocol from
inside it; an unknown op names the valid ops in its error.
For focused descriptions, agents can use compact or explicit object forms:
{"op":"describe","connections":true}
{"op":"describe","connections":["KNOWS"]}
{"op":"describe","connections":{"detail":"overview"}}
{"op":"describe","connections":{"types":["KNOWS"]}}
The same object style works for types, cypher, and fluent detail
selectors where applicable.
Interactive Shell¶
Open the shell with a graph path:
kglite app.kgl
Run with no path for a scratch in-memory graph:
kglite
Cypher statements execute when terminated by ;, so a query can span
multiple lines. Dot-commands execute on Enter. Tab completion covers
dot-commands and graph labels.
Piped input runs the same way, with two allowances for scripts: a
dot-command line terminates a statement still waiting for its ;, and so
does the end of input, so kglite app.kgl <<< 'MATCH (n) RETURN count(n)'
prints its result instead of exiting silently. A tail left unbalanced by
an unclosed quote or bracket runs nothing, names itself on stderr, and
exits non-zero. Table output is only width-capped on a terminal (honoring
COLUMNS); piped output renders every value in full.
Common dot-commands:
.help— list commands.quit/.exit— leave the shell.labels/.rels/.schema/.indexes— inspect schema.mode table|csv|json— set output format.import <file.csv> <NodeType> [--id <col>] [--title <col>]— import CSV rows as nodes.dump <dir>— export CSV files plus ablueprint.json.read <file>— run Cypher statements from a file.save [path]— save the graph to a.kglfile.timing on|off— show query wall time
Ctrl-C cancels a running query. Ctrl-D exits.
Other Commands¶
export-text prints the deterministic text projection used by git
textconv:
kglite export-text app.kgl
diff compares two graph projections:
kglite diff before.kgl after.kgl
export-sqlite writes a SQLite-dialect SQL script — node types become
tables, connection types become link tables — so the graph can leave
KGLite entirely. Give it an output path, or omit one to write to stdout:
kglite export-sqlite app.kgl dump.sql
sqlite3 app.db < dump.sql
kglite export-sqlite app.kgl | sqlite3 app.db # or pipe it straight through
Deterministic (the same graph always produces byte-identical SQL) and dependency-free — no SQLite library is linked into KGLite. The full mapping and its trade-offs are in the import/export guide.
schema-version reads, and with --set writes, the graph’s
user-schema version — your own data-model revision, distinct from the
.kgl format version, which the engine stores but never interprets:
kglite schema-version app.kgl # prints e.g. 3
kglite schema-version app.kgl --set 2 # stamp without running anything
migrate applies pending Cypher migrations and advances that stamp.
Migrations are <version>_<name>.cypher files in one directory, applied
in ascending version order:
kglite migrate app.kgl migrations --dry-run # show the plan, change nothing
kglite migrate app.kgl migrations # apply
Re-running is a no-op, statements run against an in-memory copy so a
failure part-way leaves the .kgl byte-identical, and a stamp the
migration set cannot explain is refused rather than guessed at. See the
schema-migrations guide.