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

Command Reference

Global Options

Every command accepts these options:

OptionEnvironment VariableDefaultDescription
--index-dir <PATH>LAURUS_INDEX_DIR./laurus_indexPath to the index data directory
--format <FORMAT>tableOutput format: table or json
# Example: use JSON output with a custom data directory
laurus --index-dir /var/data/my_index --format json search "title:rust"

create — Create a Resource

create index

Create a new index. If --schema is given, uses that TOML file; otherwise launches the interactive schema wizard.

laurus create index [--schema <FILE>] [--train-pq-codebook <JSONL>]

Arguments:

FlagRequiredDescription
--schema <FILE>NoPath to a TOML file defining the index schema. When omitted, the command checks if a schema.toml already exists in the index directory and uses it; otherwise the interactive wizard is launched.
--train-pq-codebook <JSONL>NoTrain shared PQ codebooks as part of creation (Issue #920). Every HNSW field configuring ProductQuantization (or, with the pq-fastscan feature, ProductQuantizationFastScan) + pq_codebook_path is trained from this JSONL file (the put docs / add docs shape with pre-computed Vector values) immediately after the index is created, so the very first commit can already encode against the codebook — removing the create → train pq-codebook → ingest ordering the failure policy otherwise requires you to manage manually. Errors before creating anything if the file is missing or no field is eligible.

Schema file format:

The schema file follows the same structure as the Schema type in the Laurus library. See Schema Format Reference for full details. Example:

default_fields = ["title", "body"]

[fields.title.Text]
stored = true
indexed = true

[fields.body.Text]
stored = true
indexed = true

[fields.category.Text]
stored = true
indexed = true

Examples:

# From a schema file
laurus --index-dir ./my_index create index --schema schema.toml
# Index created at ./my_index.

# Interactive wizard (no --schema flag)
laurus --index-dir ./my_index create index
# === Laurus Schema Generator ===
# Field name: title
# ...
# Index created at ./my_index.

# Create and train the shared PQ codebook in one step (Issue #920)
laurus --index-dir ./my_index create index --schema schema.toml \
    --train-pq-codebook train.jsonl
# Index created at ./my_index.
# Training PQ codebook for field 'embedding' on 300 vectors...
# Trained codebook 'embedding.pqcb' (m = 4, k = 256, sub_dim = 8, dimension = 32) from 300 vectors.

Note: If both schema.toml and store/ already exist, an error is returned. Delete the index directory to recreate. If only schema.toml exists (e.g. after an interrupted creation), running create index without --schema recovers the index by creating the missing storage from the existing schema.

create schema

Interactively generate a schema TOML file through a guided wizard.

laurus create schema [--output <FILE>]

Arguments:

FlagRequiredDefaultDescription
--output <FILE>Noschema.tomlOutput file path for the generated schema

The wizard guides you through:

  1. Field definition — Enter a field name, select the type, and configure type-specific options
  2. Repeat — Add as many fields as needed
  3. Default fields — Select which lexical fields to use as default search fields
  4. Preview — Review the generated TOML before saving
  5. Save — Write the schema file

Supported field types:

TypeCategoryOptions
TextLexicalindexed, stored, term_vectors
IntegerLexicalindexed, stored
FloatLexicalindexed, stored
BooleanLexicalindexed, stored
DateTimeLexicalindexed, stored
GeoLexicalindexed, stored
Geo3dLexicalindexed, stored
BytesLexicalstored
HnswVectordimension, distance, m, ef_construction
FlatVectordimension, distance
IvfVectordimension, distance, n_clusters, n_probe

Example:

# Generate schema.toml interactively
laurus create schema

# Specify output path
laurus create schema --output my_schema.toml

# Then create an index from the generated schema
laurus create index --schema schema.toml

get — Get a Resource

get stats

Display statistics about the index.

laurus get stats

Table output example:

Document count: 42

Vector fields:
╭──────────┬─────────┬───────────╮
│ Field    │ Vectors │ Dimension │
├──────────┼─────────┼───────────┤
│ text_vec │ 42      │ 384       │
╰──────────┴─────────┴───────────╯

JSON output example:

laurus --format json get stats
{
  "document_count": 42,
  "fields": {
    "text_vec": {
      "vector_count": 42,
      "dimension": 384
    }
  }
}

get schema

Display the current index schema as JSON.

laurus get schema

Example:

laurus get schema
# {
#   "fields": { ... },
#   "default_fields": ["title", "body"],
#   ...
# }

get docs

Retrieve all documents (including chunks) by external ID.

laurus get docs --id <ID>

Table output example:

╭──────┬─────────────────────────────────────────╮
│ ID   │ Fields                                  │
├──────┼─────────────────────────────────────────┤
│ doc1 │ body: This is a test, title: Hello World │
╰──────┴─────────────────────────────────────────╯

JSON output example:

laurus --format json get docs --id doc1
[
  {
    "id": "doc1",
    "document": {
      "title": "Hello World",
      "body": "This is a test document."
    }
  }
]

add — Add a Resource

add doc

Add a document to the index. Documents are not searchable until commit is called.

laurus add doc --id <ID> --data <JSON>

Arguments:

FlagRequiredDescription
--id <ID>YesExternal document ID (string)
--data <JSON>YesDocument fields as a JSON string

The JSON is the document’s serde shape: a fields object mapping each field name to an externally-tagged value (Text, Int64, Float64, Bool, VectorValue, …):

{
  "fields": {
    "title": {"Text": "Introduction to Rust"},
    "body": {"Text": "Rust is a systems programming language."},
    "year": {"Int64": 2024}
  }
}

Example:

laurus add doc --id doc1 --data '{"fields":{"title":{"Text":"Hello World"},"body":{"Text":"This is a test document."}}}'
# Document 'doc1' added. Run 'commit' to persist changes.

Tip: Multiple documents can share the same external ID (chunking pattern). Use add doc for each chunk.

add docs

Bulk-add document chunks from a JSONL file — one {"id": "...", "document": {"fields": {...}}} entry per line, where document uses the same JSON shape as add doc --data. Entries are applied through the engine’s batch API (one WAL fsync per batch) and, unlike add doc, the command commits automatically: every --commit-every applied documents and once at the end.

laurus add docs --file <JSONL> [--batch-size 1000] [--commit-every 0]

Arguments:

FlagRequiredDescription
--file <JSONL>YesPath to the JSONL file to ingest
--batch-size <N>NoDocuments per engine batch call (default 1000)
--commit-every <N>NoCommit every N applied documents; 0 = only the final commit (default)

Repeated IDs accumulate as chunks. On a mid-file failure the error names the offending line, the applied prefix is committed, and re-running the remaining lines continues the ingest.


put — Put (Upsert) a Resource

put doc

Put (upsert) a document into the index. If a document with the same ID already exists, all its chunks are deleted before the new document is indexed. Documents are not searchable until commit is called.

laurus put doc --id <ID> --data <JSON>

Arguments:

FlagRequiredDescription
--id <ID>YesExternal document ID (string)
--data <JSON>YesDocument fields as a JSON string

Example:

laurus put doc --id doc1 --data '{"fields":{"title":{"Text":"Updated Title"},"body":{"Text":"This replaces the existing document."}}}'
# Document 'doc1' put (upserted). Run 'commit' to persist changes.

Note: Unlike add doc, put doc replaces all existing chunks for the given ID. Use add doc when you want to append chunks, and put doc when you want to replace the entire document.

put docs

Bulk-upsert documents from a JSONL file — one {"id": "...", "document": {"fields": {...}}} entry per line, applied through the engine’s batch API (one WAL fsync per batch). Duplicate IDs dedup in order (the last occurrence wins). Like add docs, the command commits automatically.

laurus put docs --file <JSONL> [--batch-size 1000] [--commit-every 0]

Arguments are the same as add docs. On a mid-file failure the error names the offending line and the applied prefix is committed; because puts are idempotent, re-running the whole file (or its remaining suffix) is safe.

Example:

cat > docs.jsonl <<'JSONL'
{"id": "doc1", "document": {"fields": {"title": {"Text": "Hello"}}}}
{"id": "doc2", "document": {"fields": {"title": {"Text": "World"}}}}
JSONL
laurus put docs --file docs.jsonl
# 2 documents put (upserted) and committed.

add field

Dynamically add a new field to an existing index.

laurus add field --index-dir ./data \
    --name category \
    --field-option '{"Text": {"indexed": true, "stored": true}}'

The --field-option argument accepts a JSON string using the same externally-tagged format as the schema file. The schema is automatically persisted after the field is added.


delete — Delete a Resource

delete docs

Delete all documents (including chunks) by external ID.

laurus delete docs --id <ID>

Example:

laurus delete docs --id doc1
# Documents 'doc1' deleted. Run 'commit' to persist changes.

delete field

Remove a field from the index schema.

laurus delete field --name <FIELD_NAME>

Example:

laurus delete field --name category
# Field 'category' deleted.

Existing indexed data for the field remains in storage but becomes inaccessible. Per-field analyzers and embedders are unregistered.


commit

Commit pending changes (additions and deletions) to the index. Until committed, changes are not visible to search.

laurus commit

Example:

laurus --index-dir ./my_index commit
# Changes committed successfully.

train

train pq-codebook

Train a shared PQ codebook for an HNSW vector field (Issue #631). The codebook is trained once on a representative sample and then reused by every subsequent commit and merge, instead of re-training k-means per segment — commits on PQ fields get dramatically faster, and even tiny per-commit segments stay on PQ.

laurus train pq-codebook --field <FIELD> (--input <JSONL> | --from-index) \
    [--sample-size <N>] [--output <NAME>] [--update-schema]
ArgumentDescription
--fieldThe HNSW vector field to train for. Must be configured with a ProductQuantization quantizer (or ProductQuantizationFastScan when the pq-fastscan feature is enabled — the codebook is then trained with k=16, Issue #920).
--inputJSONL training file — the same {"id": "...", "document": {"fields": {...}}} shape as put docs / add docs. The field value must be a pre-computed Vector (embedder-generated input is not supported). Exactly one of --input and --from-index must be given.
--from-indexSample the vectors already committed to this index instead of reading a file (Issue #920) — no JSONL export needed. Exactly one of --input and --from-index must be given. Note: on a field that is already PQ-encoded, the sampled vectors are lossy reconstructions; the intended flow is to train from vectors committed before enabling PQ on the field.
--sample-sizeUse only the first N vectors (deterministic: file order for --input, ascending doc_id for --from-index). Omit to use all of them; thousands of representative vectors are enough.
--outputStorage-relative codebook file name. Defaults to the field’s configured pq_codebook_path, else {field}.pqcb. Use to train a v2 codebook alongside a live one.
--update-schemaRewrite schema.toml so the field’s pq_codebook_path names the trained file.

Commits use the codebook only when the schema’s pq_codebook_path names it (see Schema Format) — pass --update-schema to set it as part of training. A commit made while pq_codebook_path is set but the codebook has not been trained yet fails with an error naming this command; there is no silent fallback to per-segment training. The codebook is picked up when the index is opened, so train before the ingesting add / put / commit invocation (each CLI invocation opens the index fresh, so any subsequent command sees it).

Example:

cat > train.jsonl <<'JSONL'
{"id": "t1", "document": {"fields": {"embedding": {"Vector": [0.1, 0.2, 0.3, 0.4]}}}}
{"id": "t2", "document": {"fields": {"embedding": {"Vector": [0.5, 0.6, 0.7, 0.8]}}}}
JSONL
laurus train pq-codebook --field embedding --input train.jsonl --update-schema
# Training PQ codebook for field 'embedding' on 2 vectors...
# Trained codebook 'embedding.pqcb' (m = 2, k = 256, sub_dim = 2, dimension = 4) from 2 vectors.
# Updated schema.toml: embedding.pq_codebook_path = "embedding.pqcb".

Or sample directly from the vectors already committed to the index — no JSONL export needed:

laurus train pq-codebook --field embedding --from-index --sample-size 5000 --update-schema

Execute a search query using the Query DSL.

laurus search <QUERY> [--limit <N>] [--offset <N>]

The query string is analyzed with each field’s own configured analyzer — a field declared with a Japanese (Lindera) analyzer in schema.toml, for example, is analyzed the same way at query time as it was at index time. Referencing a field that is not declared in the schema is rejected with an error naming the field (helpful for catching typos); the reserved _id field is always queryable even though it does not appear in the schema.

Arguments:

Argument / FlagRequiredDefaultDescription
<QUERY>YesQuery string in Laurus Query DSL
--limit <N>No10Maximum number of results
--offset <N>No0Number of results to skip

Query syntax examples:

# Term query
laurus search "body:rust"

# Phrase query
laurus search 'body:"machine learning"'

# Boolean query
laurus search "+body:programming -body:python"

# Fuzzy query (typo tolerance)
laurus search "body:programing~2"

# Wildcard query
laurus search "title:intro*"

# Range query
laurus search "price:[10 TO 50]"

# 3D geographic queries (sphere / bounding box / k-NN)
laurus search "position:geo3d_distance(-3955182, 3350553, 3700276, 5000)"
laurus search "position:geo3d_bbox(-4000000, 3300000, 3650000, -3900000, 3400000, 3750000)"
laurus search "position:geo3d_nearest(-3955182, 3350553, 3700276, 10)"

Table output example:

╭──────┬────────┬─────────────────────────────────────────╮
│ ID   │ Score  │ Fields                                  │
├──────┼────────┼─────────────────────────────────────────┤
│ doc1 │ 0.8532 │ body: Rust is a systems..., title: Intr │
│ doc3 │ 0.4210 │ body: JavaScript powers..., title: Web  │
╰──────┴────────┴─────────────────────────────────────────╯

JSON output example:

laurus --format json search "body:rust" --limit 5
[
  {
    "id": "doc1",
    "score": 0.8532,
    "document": {
      "title": "Introduction to Rust",
      "body": "Rust is a systems programming language."
    }
  }
]

repl

Start an interactive REPL session. See REPL for details.

laurus repl

serve

Start the gRPC server (and optionally the HTTP Gateway).

laurus serve [OPTIONS]

For startup options, configuration, and usage examples, see the laurus-server documentation:


mcp

Start the Model Context Protocol (MCP) server on stdio. The MCP server lets AI assistants such as Claude Code or Claude Desktop drive a running laurus-server through a standard set of tools (create_index, add_document, search, etc.).

laurus mcp [--endpoint <URL>]

Arguments:

FlagEnvironment VariableRequiredDescription
--endpoint <URL>LAURUS_ENDPOINTNogRPC endpoint of a running laurus-server (e.g. http://localhost:50051). If omitted, the server starts without a connection; clients can call the connect MCP tool later to attach.

Examples:

# Start the MCP server pre-connected to a local laurus-server
laurus mcp --endpoint http://localhost:50051

# Start the MCP server without a connection; clients call `connect` first
laurus mcp

For the full list of MCP tools exposed by this server and how to wire it into Claude Code or Claude Desktop, see the laurus-mcp documentation.