AGENTS.md · git:20260831.f88e9d9 · 2026-08-31 · sha256 021a3eaad231a7c7
AGENTS.md git:20260831.f88e9d9A
Immutable. This exact content is served forever at /api/v1/blob/021a3eaad231a7c7.
# Using VERA as an AI agent
This file teaches AI coding agents how to use VERA to retrieve context from documents.
## What is an `.vera` file?
A single SQLite vector database containing ready-made chunks, JSON metadata,
pre-computed embeddings, and optional opaque attachments. Extraction may record
pages, headings, figures, and regions as metadata or attachments. You can search
it instantly — no parsing, chunking, embedding API calls, or retrieval service. See
[docs/vera-spec-v0.2.md](docs/vera-spec-v0.2.md) for the current format specification.
## Quick reference
All one-shot commands support `--json` for machine-readable output on stdout.
`vera mcp` is a long-running stdio server and does not accept `--json`.
```bash
# Search a document (hybrid = semantic + keyword, best default)
vera search manual.vera "stormwater detention requirements" --top-k 5 --json
# Search a folder of .vera files as one corpus (results include "file")
vera search ./library "stormwater detention requirements" --top-k 5 --json
# Search nested folders directly, or build a persistent local library index
vera search ./library "stormwater detention requirements" --recursive --json
vera index build ./library --recursive --json
vera index update ./library --json
vera index status ./library --json
# Include figure/table metadata near each result
vera search manual.vera "pipe sizing chart" --json --figures
# Include adjacent text context around each hit
vera search manual.vera "stormwater detention requirements" --json --context-chunks 1
# Keyword-only or semantic-only search
vera search manual.vera "section 4.2" --mode keyword --json
vera search manual.vera "how big should the pond be" --mode semantic --json
# Include highlight regions (page + bounding boxes) for visual grounding
vera search manual.vera "detention requirements" --json --regions
# Export the original source document (e.g. the PDF) back out
vera export manual.vera exported.pdf --json
# List stored figures, or write PNGs an agent can attach
vera figures manual.vera --json
vera figures manual.vera --out-dir ./figures --json
# What's in this file?
vera inspect manual.vera --json
# Fetch one stored chunk by id (citation-ready text, no score)
vera get manual.vera chunk_0042 --json
# Is this file well-formed? (exit code 0 = valid, 1 = invalid)
vera validate manual.vera --json
# Create an .vera from a PDF, Markdown, or (with Docling) Office/HTML file
vera convert manual.pdf manual.vera --json
vera convert notes.md notes.vera --json
vera convert memo.docx memo.vera --json
vera convert notes.html notes.vera --json
# Docling (optional CLI extra: vera-cli[docling] or --extra docling; not in the 0.3.0 desktop app)
vera convert scan.pdf scan.vera --parser docling --json
vera convert scan.pdf scan.vera --parser docling --pipeline-option pdf_backend=pypdfium2 --json
# Provider-owned embedder options (hashing dimension; OpenAI batch_size)
vera convert manual.pdf --model hashing --embedder-option dimension=256 --json
vera convert manual.pdf --model openai:text-embedding-3-small --json
vera convert filing.md out.vera --metadata company=GRID --metadata source_id=src_aaa --json
# Batch-convert a nested PDF, Markdown, and (with Docling) Office/HTML library
vera convert ./proposals --recursive --json
# Scope a library search by path include and stored metadata (filter before top_k)
vera search ./archives "adding capacity" --where company=GRID --json
vera search ./research --recursive --include "companies/GRID/archives/**" --json
# List or fetch curated Tesseract OCR language data (non-English)
vera ocr-languages list --json
vera ocr-languages download fra --json
```
Conversion selectively OCRs image-based low-text pages through the default
`vera-ingest-pymupdf` pipeline (PyMuPDF + Tesseract with bundled English data;
`--ocr auto|off|force`, `--ocr-language`, `--ocr-dpi` as compatibility aliases;
prefer repeatable `--pipeline-option KEY=VALUE` for provider-owned settings)
and publishes a validated temporary sibling atomically. PDFs with no searchable
chunks after OCR fail with an OCR-specific message. Markdown files with no
searchable text fail with a generic empty-file message. Directory conversion
skips an existing `.vera` only when it validates and its stored
`source_file_hash` matches the current source file, and reports malformed archives
in `malformed_existing`. Python `convert()` / `batch_convert()` callers should
pass `parser` (omitted: choose from the file extension), `pipeline_options`, and embedder settings
(`model` / `embedding_function` / `embedder_options`); legacy kwargs such as
`chunk_size`, `overlap`, `ocr_mode`, `ocr_language`, `ocr_dpi`, and
`ocr_download` are compatibility aliases forwarded only when explicitly
provided and the selected pipeline advertises them. Omitted aliases mean
the pipeline's own default.
### Search result shape (`--json`)
```json
{
"query": "stormwater detention requirements",
"mode": "hybrid",
"results": [
{
"chunk_id": "chunk_0042",
"score": 0.91,
"page_start": 117,
"page_end": 118,
"heading_path": "Chapter 4 > 4.2 Detention Design",
"source_filename": "manual.pdf",
"document_id": "document_0001",
"text": "..."
}
]
}
```
Directory searches add `file` to each result and a top-level `index` status
object. They also add top-level `skipped_files` diagnostics for malformed
archives excluded from the search and `skipped_semantic_model_groups` for
indexed model groups omitted because the query embedder was unavailable or
dimension-incompatible. Result order is the rank; the CLI does not emit a
`rank` field.
## Rules for agents
1. **Always cite sources.** Every result includes `page_start`/`page_end` and
`heading_path`. Quote them when answering from a document, e.g.
*"(p. 117, Chapter 4 > 4.2 Detention Design)"*.
2. **Prefer `--mode hybrid`** (the default). Use `keyword` only for exact phrases,
IDs, or section numbers; use `semantic` for paraphrased natural-language questions.
3. **Use `--figures`** when the question involves charts, diagrams, maps, or
captions — results gain a `figures` array with `asset_id`, captions, and page
locations. To **see** a stored raster, run `vera figures FILE --out-dir DIR`
(or MCP `vera_get_figure`). Tables are usually markdown in chunk text, not
figure attachments. Missing `asset_id` values mean no stored raster (vector
art or decorative marks), not that you should crop the PDF.
4. **Use `--context-chunks N`** when an answer needs surrounding prose — results gain
`before_chunks` and `after_chunks` arrays with citation-ready neighboring chunks.
5. **Use `--regions`** when a viewer needs to highlight where a chunk came from —
results gain a `regions` array. PDF hits include
`{kind, block_id, page_number, bbox, page_width, page_height}` (bbox in page points,
origin top-left). Markdown hits use `{kind: "text_span", start, end}` line/column
locators instead of page bounding boxes.
6. **Check exit codes.** Parse stdout as JSON on exit 0. `validate`, `index status`,
`eval`, a failed `export`, a failed `figures`, a failed `get`, and a failed `convert` can also print a structured JSON
report on exit 1; `convert --json` uses the same `{ok, error}` object on exit 2
for an unknown `--parser` / `--model`. Most other missing-path/runtime errors
instead write an unstructured traceback to stderr.
7. **Don't read the SQLite file directly** unless the CLI is unavailable — the schema
is documented in the spec, but the CLI/MCP tools are the stable interface.
8. **Reload a known `chunk_id` with `vera get`** when you need the stored chunk body
or to verify that a quoted span is still in `text`. Searching again is not a
substitute: rank can change, and keyword search can miss a short quote.
9. **Filter with `--where` / `--include`, not by dropping search JSON.** `--where`
matches stored archive and chunk metadata and is applied before `top_k`.
Distinct keys are AND; `KEY=a,b` is IN. `--include` is directory discovery
(OR of patterns, then `--exclude`). Do not post-filter the `results` array
after a search — that under-fills `top_k` and makes rank lie. Convert stamps
caller tags with `--metadata KEY=VALUE` onto the archive and every chunk.
Reserved citation and format keys are rejected. When a metadata filter cannot
run inside a collection index, `index.used` is false and `index.reasons`
includes `chunk metadata filter not in collection index`.
For the complete reusable workflow, load [skills/vera/SKILL.md](skills/vera/SKILL.md).
Its [CLI reference](skills/vera/references/cli-reference.md) documents every flag,
JSON shape, exit code, and filesystem side effect. See
[docs/agent-skills.md](docs/agent-skills.md) to install the skill in Hermes,
OpenClaw, Cursor, or another Agent Skills client.
## MCP server
VERA ships an MCP server (stdio) exposing the same capabilities as tools:
| Tool | Purpose |
|------|---------|
| `vera_search` | Hybrid/semantic/keyword search with optional figure metadata and highlight regions |
| `vera_corpus_search` | Search every .vera file in a directory as one corpus; results attributed per file |
| `vera_inspect` | Document metadata, page/chunk counts, embedding model |
| `vera_validate` | Integrity check |
| `vera_figures` | List figures/images with captions, optionally by page range |
| `vera_get_figure` | Fetch one stored figure as native image content plus citation metadata |
| `vera_get_page` | Full text of a specific page |
| `vera_get_chunk` | Fetch one stored chunk by id as citation-ready JSON |
| `vera_get_chunk_regions` | Page numbers + bounding boxes a chunk's text came from (visual grounding) |
Requires the integration package: `pip install "vera-cli[mcp]"` or `pip install vera-mcp`. Example VS Code config
(`.vscode/mcp.json`):
```json
{
"servers": {
"vera": {
"command": "uv",
"args": ["run", "--extra", "mcp", "vera", "mcp"]
}
}
}
```
## Working on this repository
Contributor setup, checks, and package layout live in
[CONTRIBUTING.md](CONTRIBUTING.md). Keep human and agent documentation current.
Any user-visible feature change must update the relevant [README](README.md),
human guide under [docs](https://dkylewillis.github.io/vera/), examples,
portable [agent skill](skills/vera/SKILL.md), and documentation-contract tests
in the same change. Changes to CLI commands or flags, JSON output, exit codes,
MCP tools, installation requirements, or retrieval behavior must also update
the relevant files under [skills/vera/references](skills/vera/references).
The desktop sidecar lives in
[packages/vera-app/src/vera_app](packages/vera-app/src/vera_app).
Do not merge a feature whose public behavior is only documented in
implementation code or tests.
## Cursor Cloud specific instructions
The startup update script already runs `uv sync --extra dev --extra ml --extra app --extra mcp --extra docling --extra onnx`
and `npm --prefix packages/vera-app install`, so dependencies are ready. Notes below are
non-obvious caveats for this environment; standard commands live in the sections above,
[README.md](README.md), and [docs/desktop-app-getting-started.md](docs/desktop-app-getting-started.md).
- `uv` installs to `~/.local/bin`, which is not on `PATH` for non-interactive shells. It is
added to `~/.bashrc` (so interactive shells work); otherwise invoke it as
`~/.local/bin/uv` or `export PATH="$HOME/.local/bin:$PATH"`. The uv venv lives at
`/workspace/.venv`.
- Standard checks: `uv run --extra dev python -m pytest -q` (or `npm test`) for Python,
`npm run app:typecheck` and `npm --prefix packages/vera-app run test:unit` for the app.
- Desktop app: `npm run app:dev` works on Linux, macOS, and Windows. It vendors
the MiniLM ONNX graph into `packages/vera-app/build/minilm` before Electron
starts. Electron
spawns the Python sidecar as `python -m vera_app.sidecar`, so set
`VERA_APP_PYTHON=/workspace/.venv/bin/python` (the venv Python has numpy/pymupdf/pdfplumber);
otherwise the sidecar fails to import its deps. In the cloud VM also set `DISPLAY=:1` and
`ELECTRON_DISABLE_SANDBOX=1`. The dbus/GLib warnings Electron prints in the container are
harmless.
- The desktop app's "Ask"/chat feature requires configuring an external or local LLM provider
(OpenAI/OpenRouter/Ollama/LM Studio) — there is no offline/extractive answer mode, so Ask is
blocked without a provider/API key. For fully offline testing use the left-sidebar **Search**
view (pure hybrid/semantic/keyword retrieval with grounded citations and highlights) or the
**Convert** view. Convert lists PyMuPDF (PDF) and the bundled `markdown`
pipeline. OpenAI embeddings are
bundled (`openai:text-embedding-3-small` / `-large`); hashing remains the
default. Save `OPENAI_API_KEY` under **File > Settings → Embeddings** (or
export it for CLI convert). Archives converted with OpenAI are not portable
for semantic search. Docling is a CLI extra
(`uv sync --extra docling`; `vera convert --parser docling`), not a desktop
pipeline in 0.3.0. The packaged
Windows sidecar freezes ONNX Runtime and vendors a VERA-exported
`all-MiniLM-L6-v2` graph (`VERA_ONNX_MINILM_HOME` /
`VERA_SENTENCE_TRANSFORMERS_HOME`);
packaged `HF_HOME` stays under userData. `app:dev` leaves `HF_HOME` unset
and vendors MiniLM into `packages/vera-app/build/minilm` before launch. Convert
timing lines (`elapsed_ms`) go to
sidecar stderr and are teed to `userData/logs/sidecar.log`; open it from
**File > Open convert log...**. Ask is
blocked without a provider/API key.
- MCP server (optional): `uv run --extra mcp vera mcp` (long-running stdio; no `--json`).
- There are no PDFs in the repo; generate one with the `reportlab` dev dependency when you need
a sample to `vera convert`.