The OMGDB command-line interface is a single binary named omgdb. It wraps the embedded engine end to end: create a store, write and query documents, manage indexes, plan auditable mutations, embed and search text, edit imported Markdown in place, and serve the database to coding agents over MCP. Errors are structured and specific — a typo’d collection name gets a did-you-mean hint, an unknown operator is named — so a human or an agent can repair a failed call without guesswork.
Almost every command follows the same shape: a subcommand, the store directory, then any positional or flag arguments. Documents, _ids, filters, projections, pipelines, and update specs are always passed as JSON strings. Multi-word commands use kebab-case (import-jsonl, create-index, plan-update).
omgdb <command> <store-path> [args...]
This page is the authoritative reference for the omgdb binary. There is no omg binary, and there are no init, ask, import, or debug-query commands — the real equivalents are below.
Command summary
Store lifecycle
| Command | Description |
|---|---|
create | Create a store; optionally define collections from a JSON or YAML spec. |
pack | Bundle a store into a single .omgdb archive. |
unpack | Unpack a .omgdb archive into a fresh store. |
Writing data
| Command | Description |
|---|---|
insert | Insert one JSON document; prints the assigned _id. |
insert-many | Atomically insert a JSON array of documents in one transaction. |
import-jsonl | Stream a JSON Lines file into a collection in atomic batches. |
update-one | Update the first matching document atomically, with optional explicit-seed upsert. |
update-many | Update every matching document in one bounded atomic commit. |
find-one-and-update | Atomically update the first match and print its before/after images. |
delete | Delete one document by exact _id. |
delete-many | Delete every matching document in one bounded atomic commit. |
bulk-write | Run an ordered program of CRUD operations as one atomic transaction. |
Collections
| Command | Description |
|---|---|
create-collection | Create an explicitly cataloged collection, including an empty one. |
list-collections | List every known collection in stable name order. |
drop-collection | Drop a collection with all of its documents and index metadata. |
Reading & querying
| Command | Description |
|---|---|
get | Fetch one document by its _id. |
find | Find documents matching a query filter, with sort, skip, limit, pagination, and projection. |
count-documents | Count matching documents through the direct query planner. |
distinct | Deterministic distinct values for a dotted field path. |
cursor-open | Open a persistent read cursor and print its first batch. |
cursor-next | Read the next batch from a persistent cursor. |
cursor-close | Close a persistent cursor and remove its state. |
aggregate | Run an aggregation pipeline. |
inspect | List collections and their document counts. |
describe | Print a Markdown manual of the database. |
dump | Print a deterministic canonical export of every document. |
explain | Explain how a query will run (index scan vs full scan). |
diagnose | Per-predicate selectivity — the “why-not” debugger. |
Indexes & schema
| Command | Description |
|---|---|
create-index | Create a secondary index — single-field, compound, unique, or partial, optionally with a stable name. |
list-indexes | List a collection’s ordinary indexes in stable name order. |
drop-index | Drop one ordinary index by stable name. |
suggest-indexes | Suggest indexes the planner can actually use for a query. |
validate | List documents that violate validation rules. |
Full-text search
Documented in depth on the full-text search page.
| Command | Description |
|---|---|
define-search-index | Define a versioned, op-log-backed search index from a typed JSON definition. |
search | Typed lexical, semantic, or hybrid search (--mode), with --filter, highlights, and --explain. |
search-index-status | Report derived generation state: boundary, digests, counts, rebuild reason. |
rebuild-search-index | Force a verified rebuild of one derived generation. |
drop-search-index | Drop one named search-index definition — also an op-log operation. |
models | pull / list / inspect pinned, checksum-verified local embedding models. |
Safe mutations
| Command | Description |
|---|---|
plan-update | Dry-run an update; returns a token, writes nothing. |
apply | Apply a planned change by token. |
rollback | Roll back a previously applied change. |
Vectors & context
| Command | Description |
|---|---|
vsearch | Semantic vector search over a text field. |
context | Build a token-budgeted context pack with citations. |
vsync | Persist embeddings into <collection>.__vectors. |
vstale | List _ids whose embeddings are stale. |
Markdown
| Command | Description |
|---|---|
import-md | Import a Markdown file as a document. |
md-set-section | Replace the body under one section id and refresh _sections. |
md-patch-frontmatter | Patch frontmatter fields on an imported Markdown document. |
Operations
| Command | Description |
|---|---|
verify | Re-prove the whole database: op-log replay plus every derived cache. |
repair | Recover a corrupt op-log. |
compact | Compact the op-log to its minimal form. |
mcp | Run an MCP server over stdio. |
Store lifecycle
create
Create (open) a store at <path>. With --from, the spec file defines each named collection up front — validation rules plus any unique entries, which become unique indexes.
omgdb create <path> [--from <spec>]
| Flag | Description | Default |
|---|---|---|
--from <PATH> | Spec file of the form {"collections":{"<name>":{"required":[..],"fields":{..},"refs":{..},"unique":[..]}}}. Parsed as YAML when the file ends in .yaml/.yml, JSON otherwise. | none |
On success it prints created store at <path>; with --from it also reports how many collections and unique indexes were defined.
# spec.json: {"collections":{"users":{"required":["name"],"fields":{"age":"long"},"unique":["email"]}}}
omgdb create app.omgdb --from spec.json
pack
Bundle a store directory into a single, legible .omgdb archive at <output>. The archive includes oplog.ndjson plus the pending/ and changes/ sidecars in deterministic order; transient LOCK, *.bak, and *.repairing files are excluded. Prints packed <path> into <output>.
omgdb pack <path> <output>
unpack
Unpack a .omgdb archive into a fresh store directory. Prints unpacked <n> file(s) into <path>. It refuses if <path> already contains a store, and rejects archives with bad magic or unsafe entry paths.
omgdb unpack <input> <path>
Note:
unpacktakes the archive first and the destination second — the reverse ofpack.
Writing data
insert
Insert a JSON object document into <collection>. The assigned _id (an ObjectId unless you supply your own) is printed as canonical JSON.
omgdb insert <path> <collection> <json>
omgdb insert app.omgdb users '{"name":"ana","age":30}' # prints {"$oid":"..."}
insert-many
Atomically insert a JSON array of documents in a single durable transaction — all of them commit or none do. Prints the assigned _ids as a JSON array.
omgdb insert-many <path> <collection> <json-array>
omgdb insert-many app.omgdb users '[{"name":"ana"},{"name":"bob"}]'
import-jsonl
Stream a UTF-8 JSON Lines file into a collection using atomic batch commits — one fsync per batch, not per document. This is the bulk-load path: it loads 50,000 documents in about 2 seconds. Prints {"inserted":N,"batches":M}.
omgdb import-jsonl <path> <collection> <file> [--batch-size <N>]
| Flag | Description | Default |
|---|---|---|
--batch-size <N> | Documents per atomic commit/fsync. | 1000 |
delete
Delete one document by exact _id (given as JSON). Prints {"deleted":true} or {"deleted":false} when nothing matched.
omgdb delete <path> <collection> <id>
omgdb delete app.omgdb users '{"$oid":"..."}'
update-one
Apply update operators to the canonical-_id first document matching a filter, atomically. Prints {"matchedCount":N,"modifiedCount":N} (plus upsertedId after an upsert). The change is appended to the log as a replace record inside a transaction frame — history, not an overwrite.
omgdb update-one <path> <collection> <filter> <update> [--array-filters <json>] [--upsert-document <json>] [--max-scanned-documents <n>]
| Flag | Description | Default |
|---|---|---|
--array-filters <json> | arrayFilters array for $[id] positional paths. | none |
--upsert-document <json> | Explicit no-match insert seed — OMGDB never synthesizes a document from the filter. The update is applied to the seed before insert; prints upsertedId. | none |
--max-scanned-documents <n> | Maximum visible documents decoded and tested against the filter; exceeding it is an error, never a partial answer. | 100000 |
omgdb update-one app.omgdb users '{"name":"lin"}' '{"$set":{"role":"lead"}}'
# {"matchedCount":1,"modifiedCount":1}
# Explicit-seed upsert: inserts the seed (with the update applied) only when nothing matches.
omgdb update-one app.omgdb users '{"name":"zoe"}' '{"$set":{"role":"dev"}}' \
--upsert-document '{"name":"zoe","age":25}'
# {"matchedCount":0,"modifiedCount":0,"upsertedId":{"$oid":"..."}}
update-many
Update every matching document in one bounded atomic commit: either the complete selected set commits, or nothing is appended.
omgdb update-many <path> <collection> <filter> <update> [--array-filters <json>] [--max-scanned-documents <n>] [--max-mutations <n>]
| Flag | Description | Default |
|---|---|---|
--array-filters <json> | arrayFilters array for $[id] positional paths. | none |
--max-scanned-documents <n> | Maximum visible documents tested against the filter. | 100000 |
--max-mutations <n> | Maximum documents that may be mutated atomically. | 10000 |
omgdb update-many app.omgdb users '{"active":true}' '{"$set":{"reviewed":true}}'
# {"matchedCount":2,"modifiedCount":2}
find-one-and-update
Atomically update the canonical-_id first matching document and print its before and after images along with the counts — one durable commit, no read-then-write race.
omgdb find-one-and-update <path> <collection> <filter> <update> [--array-filters <json>] [--max-scanned-documents <n>]
omgdb find-one-and-update app.omgdb users '{"name":"ana"}' '{"$inc":{"age":1}}'
# {"matchedCount":1,"modifiedCount":1,"before":{...,"age":36,...},"after":{...,"age":37,...}}
delete-many
Delete every matching document in one bounded atomic commit. Prints {"deletedCount":N}.
omgdb delete-many <path> <collection> <filter> [--max-scanned-documents <n>] [--max-mutations <n>]
omgdb delete-many app.omgdb sessions '{"expired":true}'
bulk-write
Execute one versioned, ordered program of CRUD operations as a single atomic transaction. Later steps read earlier writes from the same request; the whole program commits or nothing does. Unordered execution and implicit upsert synthesis are intentionally unsupported. Operations: insert_one, replace_one_by_id, delete_one_by_id, update_one, update_many, delete_many.
omgdb bulk-write <path> <request>
omgdb bulk-write app.omgdb '{"version":1,"operations":[
{"operation":"insert_one","arguments":{"collection":"orders","document":{"item":"monitor","price":320}}},
{"operation":"update_many","arguments":{"collection":"orders","filter":{"price":{"$lt":100}},"update":{"$set":{"budget":true}}}}
]}'
# {"version":1,"insertedCount":1,"matchedCount":2,"modifiedCount":2,"deletedCount":0,"upsertedCount":0,
# "results":[{"operation":"insert_one","value":{"insertedId":{"$oid":"..."}}}, ...]}
The request accepts optional maxOperations (default 1024), maxScannedDocumentsPerOperation (default 100000), and maxMutations (default 10000, across the whole batch) limits; exceeding a limit is an error before anything is written.
Collections
create-collection
Create an explicitly cataloged collection — including an empty one, which then shows up in list-collections, inspect, and describe before its first document. Prints {"collection":"<name>","created":true|false}.
omgdb create-collection <path> <collection>
list-collections
List every known collection — cataloged, indexed, or holding documents — in stable name order.
omgdb list-collections <path> [--json]
omgdb list-collections app.omgdb --json
# ["orders","users"]
drop-collection
Drop a collection with all of its documents and index metadata, as one authoritative op-log operation. Destructive, so it requires --yes. Prints {"collection":"<name>","dropped":true|false}.
omgdb drop-collection <path> <collection> --yes
Reading & querying
get
Fetch a single document by its _id — an ObjectId {"$oid":"..."} or a bare scalar such as 7. Prints the document as canonical JSON; exits non-zero with document not found on a miss.
omgdb get <path> <collection> <id>
find
Find documents matching a MongoDB-style JSON filter (positional, defaults to {} — match all). Each match prints as one canonical-JSON line; an unknown operator is named in the error.
omgdb find <path> <collection> [filter] [--sort <json>] [--skip <N>] [--limit <N>]
[--after-id <json>] [--after-sort-key <json>] [--project <json>]
| Flag | Description | Default |
|---|---|---|
--sort <json> | Sort spec ({"field":1,"other":-1}), applied before skip/limit. | none |
--skip <N> | Matching documents to skip before printing. | 0 |
--limit <N> | Maximum number of documents to print. | unlimited |
--after-id <json> | Cursor token: only matches whose _id sorts after this value. | none |
--after-sort-key <json> | Sorted-pagination cursor key; requires --sort. | none |
--project <json> | Projection: {"field":1} to include, {"field":0} to exclude. | none |
--after-id cannot be combined with --sort (use --after-sort-key for sorted pagination), and the two --after-* flags are mutually exclusive.
Note: querying a collection that does not exist keeps MongoDB’s empty-result semantics, but
findalso prints a warning on stderr with a did-you-mean hint, so a typo never fails silently.
omgdb find app.omgdb users '{"age":{"$gte":25}}' --sort '{"age":-1}' --limit 10
count-documents
Count documents matching a filter through the same direct query planner as find — an omitted filter counts the whole collection. Prints the bare count.
omgdb count-documents <path> <collection> [filter]
omgdb count-documents app.omgdb users '{"age":{"$gte":30}}'
# 2
distinct
Deterministic distinct values for a dotted field path, in canonical value order, optionally pre-filtered. Exceeding --max-values (default 10000) is an error, never truncation.
omgdb distinct <path> <collection> <field> [filter] [--max-values <n>]
omgdb distinct app.omgdb users role
# ["admin","lead"]
cursor-open
Open a persistent read cursor over a filter and print its first batch as JSON ({token, collection, count, exhausted, lastId, sort, lastSortKey, batch}). Cursor state lives in a sidecar file under the store, so it survives across processes.
omgdb cursor-open <path> <collection> [filter] [--batch-size <N>] [--sort <json>] [--project <json>]
| Flag | Description | Default |
|---|---|---|
--batch-size <N> | Matching documents per batch. | 100 |
--sort <json> | Sort spec, persisted in the cursor. | none |
--project <json> | Projection, persisted in the cursor. | none |
cursor-next
Read the next batch from a persistent cursor by its token. --batch-size overrides (and persists) the cursor’s stored batch size.
omgdb cursor-next <path> <token> [--batch-size <N>]
cursor-close
Close a persistent cursor and remove its sidecar state. Prints closed cursor <token>.
omgdb cursor-close <path> <token>
omgdb cursor-open app.omgdb users '{}' --batch-size 500 # prints {"token":"...","batch":[...],...}
omgdb cursor-next app.omgdb <token>
omgdb cursor-close app.omgdb <token>
aggregate
Run an aggregation pipeline given as a JSON array of stages. Each output document prints as one canonical-JSON line.
omgdb aggregate <path> <collection> <pipeline>
omgdb aggregate app.omgdb emp '[{"$group":{"_id":"$dept","total":{"$sum":"$sal"}}},{"$sort":{"_id":1}}]'
inspect
Print each collection and its document count — text lines by default, {"collections":[{"name":..,"count":..},..]} with --json.
omgdb inspect <path> [--json]
describe
Print a Markdown manual of the database: collections, inferred schema, and sample documents. See introspection.
omgdb describe <path>
dump
Print a deterministic canonical export of every document. Useful for diffs and golden snapshots.
omgdb dump <path>
explain
Explain how a query filter will be executed — index scan versus full scan. If the collection does not exist, explain refuses with a did-you-mean hint instead of producing confidently wrong advice.
omgdb explain <path> <collection> <filter>
diagnose
Diagnose why a query matches what it does — per-predicate selectivity, printed as canonical JSON. Like explain, it errors with a did-you-mean hint on a missing collection.
omgdb diagnose <path> <collection> <filter>
omgdb diagnose app.omgdb userz '{"age":{"$gte":25}}'
# Error: collection `userz` does not exist — did you mean `users`? (existing: users)
Indexes & schema
create-index
Create a secondary index on one field — or a compound index by listing several fields, used for equality-prefix and range planning. --unique rejects duplicate values (or tuples); --partial restricts the index to documents matching a predicate; --name gives the index a stable explicit identity for list-indexes/drop-index (omitted, a deterministic name is derived from the definition).
omgdb create-index <path> <collection> <field> [<field>...] [--name <name>] [--unique] [--partial <json>]
| Flag | Description | Default |
|---|---|---|
--name <name> | Stable explicit index name. | derived deterministic name |
--unique | Reject duplicate present scalar values/tuples for this index. | off |
--partial <json> | Partial-index predicate over supported query operators. | none |
omgdb create-index app.omgdb users email --name email_idx --unique
omgdb create-index app.omgdb events type ts # compound index on (type, ts)
omgdb create-index app.omgdb users age --partial '{"active":true}'
list-indexes
List a collection’s ordinary indexes — name, fields, uniqueness, partial predicate — in stable name order.
omgdb list-indexes <path> <collection> [--json]
omgdb list-indexes app.omgdb users --json
# [{"name":"email_idx","collection":"users","fields":["email"],"unique":true}]
drop-index
Drop one ordinary index by its stable name, as an authoritative op-log operation replayed like any other.
omgdb drop-index <path> <collection> <name>
suggest-indexes
Suggest indexes the current planner can actually use for a query filter — optionally sort-aware, so compound suggestions cover an ORDER-BY-shaped query too. Prints a JSON array of suggestions.
omgdb suggest-indexes <path> <collection> <filter> [--sort <json>]
omgdb suggest-indexes app.omgdb events '{"type":"click"}' --sort '{"ts":-1}'
validate
List documents in <collection> that violate its validation rules. Prints valid: no violations when clean; otherwise one <id>: <reason> line per offender, and exits non-zero.
omgdb validate <path> <collection>
Safe mutations
The plan-update → apply → rollback trio is the auditable change workflow: plan first, apply by token, reverse by change id. See agent mutations.
plan-update
Dry-run an update: compute the changes without writing anything. Takes a filter and an update spec ($set, $inc, array operators, positional $), and prints a plan summary — a token, the match count, and a before/after sample.
omgdb plan-update <path> <collection> <filter> <update> [--array-filters <json>]
| Flag | Description | Default |
|---|---|---|
--array-filters <json> | JSON array of arrayFilters for $[id] filtered positional updates. | none |
omgdb plan-update app.omgdb users '{"age":{"$gte":25}}' '{"$set":{"active":true}}'
apply
Apply a previously planned change by its <token>. Prints the apply result, including a change id, as canonical JSON.
omgdb apply <path> <token>
rollback
Roll back a previously applied change by its <change_id>. Prints rolled back <n> document(s).
omgdb rollback <path> <change_id>
Vectors & context
The vector commands use the engine’s offline, deterministic, dependency-free embedder — not an external service — so relevance is approximate. See vector search and context packs.
vsearch
Semantic search: rank documents by similarity of a text field to a query. Prints <score>\t<document> per hit.
omgdb vsearch <path> <collection> <field> <query> [--k <N>] [--filter <json>]
| Flag | Description | Default |
|---|---|---|
--k <N> | Number of results to return. | 5 |
--filter <json> | Structured pre-filter on candidates (hybrid search). | none |
context
Build a token-budgeted context pack for a task: the most relevant chunks of a text field, with citations, printed as canonical JSON (citations, chunks, budgetTokens).
omgdb context <path> <collection> <field> <query> [--budget <N>] [--filter <json>]
| Flag | Description | Default |
|---|---|---|
--budget <N> | Approximate token budget for the bundle. | 1000 |
--filter <json> | Structured pre-filter on candidates (hybrid retrieval). | none |
vsync
Persist embeddings for a text field into the sidecar collection <collection>.__vectors, with provenance; already-fresh embeddings are skipped. The vectors form an ordinary, inspectable collection.
omgdb vsync <path> <collection> <field>
vstale
List _ids whose persisted embedding is stale — missing, built from a different model, or built from text that has since changed. Ids go to stdout, a <n> stale embedding(s) summary to stderr.
omgdb vstale <path> <collection> <field>
Markdown
import-md
Import a Markdown file as one document: YAML frontmatter becomes queryable fields, headings become stored sections under _sections. Prints the assigned _id.
omgdb import-md <path> <collection> <file>
md-set-section
Replace the body under one imported-Markdown section (by its stable id from _sections[].sectionId) and refresh the stored document. Pass the replacement text positionally, or --file for multiline content — one or the other, not both. Prints the updated document.
omgdb md-set-section <path> <collection> <id> <section-id> [<text>] [--file <path>]
omgdb md-set-section app.omgdb docs '{"$oid":"..."}' overview "New section body."
md-patch-frontmatter
Patch frontmatter fields on an imported Markdown document: insert or replace fields from a JSON object, remove fields with repeatable --remove. Prints the updated document.
omgdb md-patch-frontmatter <path> <collection> <id> <patch> [--remove <field>]...
omgdb md-patch-frontmatter app.omgdb docs '{"$oid":"..."}' '{"status":"final"}' --remove draft
Operations
verify
Re-prove the entire database: replay the op-log, check that it reproduces the live state, and check every derived cache and checkpoint against it — at 50,000 documents this takes about a second. On success it prints an OK summary line plus one status line per derived cache; a stale or malformed cache is a stderr WARN (it is derived and rebuildable, never data loss), and a skipped torn trailing record from an interrupted write is warned about too. Exits non-zero with INCONSISTENT: ... if replay does not reproduce the live state.
omgdb verify <path>
repair
Recover a corrupt op-log. Because a corrupt store cannot be opened, repair operates directly on <path>/oplog.ndjson — but it takes the store lock first, and refuses to run while another process has the store open.
omgdb repair <path> [--truncate] [--yes]
| Flag | Description | Default |
|---|---|---|
--truncate | Truncate the log to the recoverable prefix (otherwise only report). | off |
--yes | Confirm the destructive truncate (required with --truncate). | off |
With no flags it is a non-destructive dry run: it prints OK: log is intact or CORRUPT at byte <g> of <total>: <reason> plus the recoverable prefix. With --truncate --yes it backs up the original to oplog.ndjson.corrupt.bak, then truncates to the recoverable prefix. --truncate without --yes refuses.
omgdb repair app.omgdb # dry run: report only
omgdb repair app.omgdb --truncate --yes # backup, then truncate
omgdb verify app.omgdb # now OK
compact
Compact the op-log to its minimal form, dropping superseded history. Prints compacted: <before> -> <after> records.
omgdb compact <path>
mcp
Run an MCP (Model Context Protocol) server over stdio, exposing the store to coding agents as scoped tools. It speaks newline-delimited JSON-RPC 2.0 and answers initialize, tools/list, and tools/call.
omgdb mcp [--scope <scope>]
| Flag | Description | Default |
|---|---|---|
--scope <scope> | Capability ceiling enforced on every tool call: read (alias ro), read-write (aliases write, rw), or dangerous (alias all). An invalid value aborts. | read-write |
A read server advertises and permits only the 23 read tools; read-write adds the 24 mutating tools; dangerous additionally unlocks drop_collection, the one tool that destroys a whole collection. The full tool contract — annotations, per-tool parameters, and a working wire example — is on the MCP server page.