Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Embedded CLI

drsg is the command-line interface. It opens the database directly — it is embedded, not a client of a running server — which makes it suited to local scripting, bulk ingestion, inspection, backup, and operations. Every invocation takes a global --db <path> (default graph.drsg); most commands also take a --plane (default startup).

Because it opens the database in-process, drsg cannot operate on a database that a drsg serve — or another drsg — currently holds open: the database takes an exclusive lock, and a second open fails with a clear error rather than corrupting it. Use the SDKs or the RPC API against the server for concurrent access, and the CLI for offline operations.

Command reference

CommandPurpose
init [--dir] [--rebuild]bootstrap this repository for agents: digest it, spawn serve watch detached, write .mcp.json (Chapter 10). In a --no-default-features build without digest, it creates an empty database instead — as most commands do on first use
plane list | create | drop | showplane lifecycle
import <file> --planeload JSONL nodes/edges
export --planedump a plane as JSONL
get <node> --planefetch one node by id or @external-key
query <plan> --planerun a serialized logical plan (JSON, or -)
cypher <query> --planerun an openCypher-subset statement (or -)
catalog [--plane]print the soft schema (one plane or the whole database)
algo <name> --planerun a graph algorithm
hybrid <query> --planefused vector + keyword + graph-proximity search
index ensure | keyworddeclare a vector or keyword index
ask <question> --planenatural-language query
digest <file|dir|url> --plane [--mode]ingest a document, a repository, or a page and its links
search <query> --planesemantic lookup: embeds the query, returns the nearest nodes
context | describe | trace | impact | fathom <name> --planethe agent verbs over a digested code plane
impact <name> --plane [--depth] [--across [attached|all]]--across widens the radius past this repository: the planes this one attaches, or every plane this instance holds
snippet <name | path:start-end> --planea symbol’s source text, or a range of any file in the parsed tree
grep <pattern> --plane [--regex] [--path] [--all-files]text search over that tree, ignored files excluded unless --all-files; each hit names the symbol it falls in
traverse <key> --plane [--edge-type]the neighbours a hop (or several) away
history --plane [--limit]the repository behind a plane: HEAD, branch and tag tips, rebases, newest commits
deployed [<target>] --plane [--ops] [--history]what commit a running thing was built from, and what runs a commit: the ops plane joined to the history beside it through the revision an image’s tag carries
recall <name> --at <rev> --plane [--vs <rev>] [--pattern]code as it was at a revision: a file, a range, a directory or a symbol; a search of that tree; or a diff from an older revision
wire <path | name> --plane [--verb]what serves an HTTP path and what asks for it, across every language in the plane and across the planes it attaches
attach <name> --plane [--url] [--as] [--both]record a plane this one may ask: one here, or one another drsg serves
detach <name> --planeforget an attachment (an absent name is reported, not an error)
attachments --plane [--probe]what a plane attaches; --probe asks each remote one whether it answers now
mount <path> [--as] [--url]serve another database’s planes on a running drsg, now — these three speak its RPC rather than opening a file, since the server holds the store’s lock
unmount <name> [--url]stop serving a mount, releasing its store’s lock — said when a fold in flight still holds it (an absent name is reported, not an error)
mounts [--url]what that server serves: each mount with its directory and planes, and every plane with the tree it records
queries [<id>] [--limit]the Cypher queries that have run; cypher --history <id> runs one again
vectorize --planeembed a plane’s nodes for similarity search
plugin install | list | removemanage preprocessor plugins (sandboxed wasm parsers)
snapshot <out> / restore <in>whole-database backup and restore
stats / checksummary counts / integrity scan
serve [--addr]run the web dashboard + JSON-RPC API + MCP endpoint
serve watch [--dir]serve, and keep a code plane synced to every commit
update [--bin] [--dir]replace this binary with a newer release, if there is one

A digested file may be Markdown or plain text, or any of Word, PowerPoint, Excel, OpenDocument, RTF, EPUB, CSV and PDF — those are converted to Markdown first, so the model reads headings, tables and lists rather than loose characters. The format is detected from the file’s contents, so a wrong extension still works. A directory is walked and routed per file: source code goes through the installed parser plugins as facts, documents go to the model as prose.

Global options are --db <path> and --config <path> (the configuration file, Chapter 2).

Planes

$ drsg --db graph.drsg plane create social
$ drsg --db graph.drsg plane list
$ drsg --db graph.drsg plane show social
$ drsg --db graph.drsg plane drop social

Data in and out

Import and export use JSONL — one node or edge per line — so a plane round-trips through the file system and integrates with other tooling:

$ drsg --db graph.drsg import nodes.jsonl --plane social
$ drsg --db graph.drsg export --plane social > social.jsonl
$ drsg --db graph.drsg get @ada --plane social

A node’s external_key is its identity within a plane, so --on-conflict decides what happens when an imported key is already there:

PolicyEffect
error (default)Import nothing and name the colliding keys
skipKeep the existing node; drop the incoming one
updateOverwrite the existing node’s properties, and its labels when the line carries them
$ drsg --db graph.drsg import nodes.jsonl --on-conflict update
imported 0 nodes, 0 edges, 2 existing updated

Under skip and update, edges in the file still resolve to the node already in the plane, so relationships load against existing data. Edges themselves carry no key, so they are always appended — the policy governs node identity, not edge deduplication. Lines without an external_key cannot collide and are always inserted.

Querying

A statement may be the openCypher subset or a serialized plan; either accepts - to read from standard input. --param binds a $name placeholder to a JSON value:

$ drsg --db graph.drsg cypher --plane social \
    'MATCH (p:Person) WHERE p.age >= $min RETURN p' --param min=18

$ drsg --db graph.drsg query - --plane social < plan.json

$ drsg --db graph.drsg catalog --plane social

Every query that runs — from the CLI, the dashboard, or an agent over MCP — is recorded. queries lists what has run, newest first, as id, time, plane and the query folded onto one line; with an id it prints that one query’s text alone. cypher --history runs a recorded query again, against the plane it was written for unless --plane says otherwise:

$ drsg --db graph.drsg queries --limit 5
4	2026-09-05 08:14:02Z	social	MATCH (p:Person) WHERE p.age >= $min RETURN p
3	2026-09-05 08:11:47Z	social	MATCH (p:Person) RETURN count(*) AS people

$ drsg --db graph.drsg queries 3 > last.cypher
$ drsg --db graph.drsg cypher --history 3

The history is capped — two hundred entries by default — and the oldest is dropped as a new one arrives. Re-running the query most recently recorded restamps its entry rather than adding a second copy. Note that drsg history is a different command: that one is a repository’s commits.

Graph algorithms

$ drsg --db graph.drsg algo pagerank      --plane social --top 10
$ drsg --db graph.drsg algo components    --plane social
$ drsg --db graph.drsg algo shortest-path --plane social --src 1 --dst 42
$ drsg --db graph.drsg algo louvain       --plane social

Retrieval and ingestion

Declare indexes, run fused search, ask in natural language, and ingest documents (Chapter 3). The LLM-backed commands read provider keys from the environment:

$ drsg --db graph.drsg index ensure  Doc embedding --plane social
$ drsg --db graph.drsg index keyword Doc body      --plane social --lang english

$ drsg --db graph.drsg hybrid "how does time-travel work" \
    --plane social --label Doc --vector embedding --keyword body --graph-hops 1

$ drsg --db graph.drsg ask "which companies does Ada work for?" \
    --plane social --chat deepseek --embed qwen

$ drsg --db graph.drsg digest notes.md --plane social --apply

$ drsg --db graph.drsg digest paper.md --plane papers --mode super --apply

$ drsg --db graph.drsg digest https://example.com/paper --plane papers \
    --topic "attention mechanism" --pages 6 --apply

An http(s):// argument is fetched rather than read from disk: the page is converted to Markdown and its links followed under --pages / --depth, keeping what is relevant to the page’s own subject and to --topic if given (Chapter 3). The scheme is required — a bare example.com is a valid filename, and guessing which was meant would be worse than asking. The command prints what it kept and what it dropped; there is no selection prompt, which is what the dashboard’s page list is for.

--mode selects how thoroughly the extraction is cleaned up: coarse reconciles the label and edge-type vocabularies, fine (the default) also merges entities that name the same thing, and super also re-reads every entity against all of its passages — the most accurate, at roughly 15× the input token usage (Chapter 3).

Backup and integrity

snapshot writes a consistent whole-database bundle at one commit sequence; restore rebuilds it into an empty database, preserving ids, the commit sequence, and the built search indexes (Chapter 11). stats and check report counts and scan every plane for readability:

$ drsg --db graph.drsg snapshot backup.drsgsnap
$ drsg --db fresh.drsg  restore  backup.drsgsnap
$ drsg --db graph.drsg stats
$ drsg --db graph.drsg check

check also names storage runs written before block checksums existed. A compaction rewrites what it merges, so a store written to often upgrades itself, but one that settles below the compaction threshold keeps unchecked blocks for good — and corruption in them reads as data rather than an error. upgrade rewrites those runs, entry for entry, so nothing is reclaimed and the store holds what it held:

$ drsg --db graph.drsg upgrade
upgraded 2 storage runs to the checksummed format

Serving

serve is the exception to the embedded model: it opens the database and then exposes it over the network for the dashboard, the SDKs, and the MCP server.

$ DRSG_TOKEN=please-change-me drsg --db graph.drsg serve --addr 0.0.0.0:7700

See Chapter 2 for the server and its configuration, Chapter 5 for the dashboard, and Chapter 6 for the clients.

One setting from that configuration is not the server’s alone: [server] retain_commits — how many commits of history time-travel can reach — is applied by every command above that opens the database, so a store fed by import or cypher from the shell keeps the same window (20 by default, 0 for unbounded) as it would under serve.