omnigraph/docs/user/cli-reference.md
aaltshuler 4c50170c77 feat(config): OMNIGRAPH_NO_LEGACY_CONFIG strict mode (RFC-008 stage 4)
Opt-in: with the env set, loading a legacy omnigraph.yaml is a hard
error pointing at config migrate — the regression guard for migrated
teams (a stray legacy file would otherwise silently outrank operator
config during the window) and the rehearsal for stage 5's removal.
Strict refuses the FILE, never its absence: flag-less invocations on
migrated setups are untouched. Inert unless set.

The RFC's stages-1-3-then-4 release gap collapsed honestly: no version
boundary was crossed between them, so all four ship in the same release
(noted in the RFC).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 00:03:10 +03:00

12 KiB

CLI Reference (omnigraph)

A reference for the omnigraph binary's command surface and omnigraph.yaml schema. For a quick-start guide, see cli.md.

Top-level command families and subcommands. Graph-targeting commands accept a positional URI, --uri, a --target <name> resolved against omnigraph.yaml, or --server <name> (an operator-defined server from ~/.omnigraph/config.yaml, optionally with --graph <id> for multi-graph servers; exclusive with the other forms); cluster commands use --config <dir>.

Top-level commands

Command Purpose
init --schema <pg> → initialize a graph (no longer scaffolds omnigraph.yaml — RFC-008; start cluster configs from the cluster.md quick-start or config migrate)
load bulk load a branch, local or remote (--mode overwrite|append|merge is required — overwrite is destructive, so there is no default). Without --from the target branch must exist; --from <base> forks a missing --branch from <base> first
ingest deprecated alias of load --from <base> (defaults: --from main --mode merge); prints a one-line warning to stderr
query (alias: read) run named read query; source via --query <path>, -e/--query-string <GQ>, or --alias <name> (exactly one). read is the deprecated previous name and prints a one-line warning to stderr
mutate (alias: change) run mutation query; same --query / -e / --alias mutual-exclusion as query. change is the deprecated previous name and prints a one-line warning to stderr
snapshot print current snapshot (per-table version + row count)
export dump to JSONL on stdout (--type T, --table K filters)
branch create | list | delete | merge branching ops
commit list | show inspect commit graph
schema plan | apply | show (alias: get) migrations
lint (alias: check) offline / graph-backed query validation. Replaces query lint / query check, which are kept as deprecated argv-level shims that print a one-line warning and rewrite to omnigraph lint
config migrate propose (or --write: apply) the RFC-008 split of a legacy omnigraph.yaml — team half → ready-to-review cluster.yaml, personal half → ~/.omnigraph/config.yaml (key-level merge, existing entries win), plus dropped-key reasons and manual steps
cluster validate | plan | apply | approve | status | refresh | import | force-unlock declarative cluster control plane. validate checks a local cluster.yaml folder and referenced schema/query/policy files; plan diffs it against local JSON state at __cluster/state.json, annotates dispositions, and embeds real schema-migration previews; apply converges the cluster — stored-query/policy catalog writes (content-addressed under __cluster/resources/), graph creates, schema updates (soft drops only; --as records the actor), and graph deletes behind a digest-bound approval from cluster approve <resource> --as <actor> (apply/approve default the actor from the per-operator omnigraph.yaml's cli.actor when --as is omitted; nothing else in that file affects cluster commands); what apply converges is what an omnigraph-server --cluster <dir> deployment serves on its next restart (omnigraph.yaml deployments are unaffected); status reads the state ledger; refresh/import explicitly update local JSON state from read-only graph observations; force-unlock <LOCK_ID> manually removes a held local state lock by exact id
optimize non-destructive Lance compaction (skips tables with Blob columns or uncovered drift; --json reports skipped)
repair [--confirm] [--force] preview or explicitly publish uncovered manifest/head drift. --confirm heals verified maintenance drift and exits non-zero if suspicious/unverifiable drift is refused; --force --confirm publishes suspicious/unverifiable drift after operator review
cleanup --keep N --older-than 7d --confirm destructive version GC
embed offline JSONL embedding pipeline
policy validate | test | explain Cedar tooling. Selects cli.graph, else server.graph, else top-level policy.file
version / -v print omnigraph 0.3.x

Config surfaces

Two config surfaces with single owners (RFC-007/RFC-008), plus a zero-config tier:

Surface Owner Location Declares
Cluster config the team, in a repo cluster.yaml + checkout (cluster-config.md) what the system is: graphs, schemas, queries, policies, storage
Operator config one person ~/.omnigraph/config.yaml (override dir with $OMNIGRAPH_HOME) who I am: identity, ergonomics
Flags / env per invocation everything, explicitly

omnigraph.yaml (below) is the legacy combined file — fully supported today, slated for staged deprecation (RFC-008); its keys' future homes are listed there.

~/.omnigraph/config.yaml (operator)

operator:
  actor: act-andrew     # default identity for every --as cascade:
                        #   --as > legacy cli.actor > operator.actor > none
servers:                # operator-owned endpoints; names key the credentials
  prod:
    url: https://graph.example.com     # no tokens in this file, ever
defaults:
  output: table         # read format default, below --json/--format/alias/legacy

Absent file = empty layer. Unknown keys warn and load (a file written for a newer CLI works on an older one). $OMNIGRAPH_CONFIG=<path> stands in for --config (the flag wins) in both the CLI and the server.

Credentials keyed by server name

omnigraph login <name> stores a bearer token in ~/.omnigraph/credentials (created 0600; group/world-readable files are refused). Token from --token, or — preferred, keeps it out of shell history — one line on stdin: echo $TOKEN | omnigraph login prod. omnigraph logout <name> removes it (idempotent).

Operator aliases — bindings, not content

An operator alias is a personal name for invoking a stored query on a named server — it carries no query content (the stored query in the catalog is the team's contract; the alias, its defaults, and its name are yours):

aliases:
  triage:
    server: intel-dev        # names an entry under servers:
    graph: spike             # optional (multi-graph servers)
    query: weekly_triage     # the STORED query's name — never a file
    args: [since]            # positional args -> params, in order
    params: { limit: 20 }    # fixed defaults; positionals/--params win
    format: table

omnigraph query --alias triage 2026-06-01 invokes POST <server>/graphs/spike/queries/weekly_triage with the keyed credential. A legacy omnigraph.yaml alias with the same name wins during the deprecation window (with a warning).

A remote command whose URL prefix-matches an operator server's url (the gh host model — no flags needed) resolves its token through:

Order Source
1 OMNIGRAPH_TOKEN_<NAME> env (prodOMNIGRAPH_TOKEN_PROD)
2 [<name>] section in ~/.omnigraph/credentials
3 the legacy chain unchanged (bearer_token_envOMNIGRAPH_BEARER_TOKENauth.env_file)

A token is only ever sent to the server it is keyed to: URLs matching no operator server use the legacy chain alone.

omnigraph.yaml schema (legacy combined file)

Deprecated (RFC-008). Loading this file prints a per-key notice naming each present key's new home (suppress in CI with OMNIGRAPH_SUPPRESS_YAML_DEPRECATION=1); omnigraph config migrate produces the split. The file keeps working through the deprecation window. Migrated teams can set OMNIGRAPH_NO_LEGACY_CONFIG=1 to turn any legacy-file load into a hard error (regression guard; the file's absence is always fine).

project: { name }
graphs:
  <name>:
    uri: <local|s3://|http(s)://>
    bearer_token_env: <ENV_NAME>
    queries:                      # per-graph stored-query registry (server-role; multi-graph mode)
      <query-name>:               # key MUST equal the `query <name>` symbol inside the .gq
        file: <path-to-.gq>       # relative to this config's directory
        mcp:
          expose: true            # default true: listed in the MCP catalog (GET /queries); set false to hide (still HTTP-callable)
          tool_name: <name>       # optional MCP tool-name override (defaults to <query-name>;
                                  #   must be unique across exposed queries)
server:
  graph: <name>
  bind: <ip:port>
cli:
  graph: <name>
  branch: <name>
  output_format: json|jsonl|csv|kv|table
  table_max_column_width: 80
  table_cell_layout: truncate|wrap
query:
  roots: [<dir>, …]   # search path for .gq files
auth:
  env_file: .env.omni
aliases:
  <alias>:
    # accepted values: `read` / `query` (read alias), `change` / `mutate`
    # (write alias). `query` and `mutate` are recommended; `read` and
    # `change` remain accepted forever for back-compat.
    command: read|change|query|mutate
    query: <path-to-.gq>
    name: <query-name>
    args: [<positional-name>, …]
    graph: <name>
    branch: <name>
    format: <output-format>
queries:                          # top-level registry — applies only to a bare-URI (anonymous) graph; a graph served by name uses its `graphs.<id>.queries`. Mirrors top-level `policy`.
  <query-name>: { file: <path-to-.gq> }   # mcp.expose defaults to true
policy:
  file: policy.yaml

Cluster config preview

omnigraph cluster validate --config company-brain
omnigraph cluster plan     --config company-brain --json
omnigraph cluster apply    --config company-brain --json
omnigraph cluster approve  graph.<id> --config company-brain --as <actor>
omnigraph cluster status   --config company-brain --json
omnigraph cluster refresh  --config company-brain --json
omnigraph cluster import   --config company-brain --json
omnigraph cluster force-unlock <LOCK_ID> --config company-brain --json

--config is a directory containing cluster.yaml; it defaults to .. Stage 3A accepts graphs, schemas, stored queries, and policy bundle file references. cluster plan reads local JSON state from <config-dir>/__cluster/state.json; a missing file means empty state. Plan, apply, refresh, and import acquire __cluster/lock.json by default and release it before returning. cluster apply executes only stored-query/policy catalog writes (content-addressed under __cluster/resources/) and requires an existing state.json; graph/schema changes are deferred with warnings, and applied resources do not serve traffic — the server still boots from omnigraph.yaml. cluster status reads state only and reports any existing lock metadata. force-unlock removes a lock only when the supplied id exactly matches the lock file. refresh requires an existing state.json; import creates one only when it is missing. Both observe declared graphs read-only at <config-dir>/graphs/<graph-id>.omni. External state backends, graph/schema apply, automatic stale-lock breaking, plan --refresh, pipelines, UI specs, embeddings, aliases, and bindings are reserved for later stages. See cluster-config.md.

Output formats (query command, alias: read)

  • json — pretty-printed object with metadata + rows
  • jsonl — one metadata line then one JSON object per row
  • csv — RFC 4180-ish quoting
  • table — fitted text table, honors table_max_column_width + table_cell_layout
  • kv — grouped per-row key/value blocks

Param resolution

Precedence (high to low): explicit --params / --params-file, alias positional args, omnigraph.yaml defaults. JS-safe-integer handling is built in (is_js_safe_integer_i64, JS_MAX_SAFE_INTEGER_U64) so 64-bit ids round-trip safely through JSON clients.

Bearer token resolution (CLI)

  1. graphs.<name>.bearer_token_env
  2. OMNIGRAPH_BEARER_TOKEN global env
  3. auth.env_file referenced .env

Duration parsing (cleanup)

s | m | h | d | w units, e.g. --older-than 7d.