Get started

From empty laptop to a scoped, leak-proof query in five minutes

This is the one path we recommend you take first. Five commands, every decision already made for you, copy-paste top to bottom. By the end you'll have booted Verity, ingested a real directory, run a permission-filtered query, watched a second agent get zero results on the same data, and wired a live agent over MCP. No menus, no branching — when you want the depth behind a step, follow the link at the end of it.

prerequisites A recent Rust toolchain (cargo) and Docker running — that's it. dev pulls a Postgres image, builds the server, and writes its config to ~/.verity/config.toml; you don't install a database or edit a config by hand.

1 · Boot the whole local plane

One command stands up everything Verity needs and leaves you with a working, org-wide scope handle already saved. It is fully idempotent — re-run it anytime.

sh
cargo run --release -p verity-cli -- dev

what you'll see

console
verity dev — local memory plane, five minutes

  ✓ postgres       docker compose up -d (paradedb pg17)
  ✓ server         http://127.0.0.1:7717  (/healthz ok)
  ✓ tenant         "dev" → c1e6…
  ✓ scope handle   saved to ~/.verity/config.toml (org-wide, principals [1])
  ✓ config         ~/.verity/config.toml

  Verity is up.
    server         http://127.0.0.1:7717
    tenant (dev)   c1e6…
    scope handle   saved to ~/.verity/config.toml (org-wide, principals [1])

You just booted a Postgres, the Rust server, a dev tenant, and an org-wide scope handle (principals [1]) — the one credential Verity issues. Every command below reuses the handle from that config; you never paste it.

What each piece is, and how to run against an existing server instead: Ingestion → verity-cli.

2 · Ingest something real

Point add at a directory. It recurses over text-like files (.txt/.md/.json/.csv/.html), chunks and embeds each, and uploads them under a scope whose principals are exactly your --visibility tokens. --visibility has no default — Verity never guesses who may see a memory, so you always name it. Here, 1 is the org-wide token from step 1.

sh
verity-cli add ./docs --visibility 1

what you'll see

console
  ingesting ./docs (recursive over .txt/.md/.json/.csv/.html, ≤200 files)

  1/9  ingestion.html   → 34 chunk(s)
  2/9  permissions.html → 28 chunk(s)
  …
   214 chunk(s) indexed from 9 file(s) — try  verity-cli query "<something in it>"

You just filled the memory with real, permission-tagged content — and saw the exact chunk count go in. Every one of those chunks carries admin-assigned provenance: the visibility was an explicit decision (--visibility 1), not a mirrored source ACL.

Files, URLs, stdin, entity tags, and narrower visibility: Ingestion → add. Connecting a live SaaS source instead of files: Connecting your systems.

3 · Query it back — scoped, with provenance

Ask a natural-language question. query uses the handle dev saved, runs scoped hybrid recall, and prints each hit with its score, kind, and ACL-provenance tag.

sh
verity-cli query "what does an entity tag do?"

what you'll see

console
  1.  0.782  [content] [admin-assigned]  Memory is tagged with the entities it concerns (account:acme…
        entities account:acme  ·  provenance cli:add
  2.  0.741  [content] [admin-assigned]  a chunk touching two entities is retrievable only in a scope that…
        provenance cli:add

  every hit passed the scope's visibility pre-filter in-index — nothing above is post-filtered.

You just got a scoped hit back with its provenance visible on the lineadmin-assigned tells you exactly how much to trust the filter. There is no post-hoc filtering step to forget: the scope was compiled into the index query itself.

Custom k, raw JSON, and the four provenance tags: Ingestion → query and ACL provenance.

4 · The “aha”: watch the wall hold

Now the thing Verity actually exists to do. Tag a memory to one account, then mint a second scope handle — same org, different entity scope — and prove it can't see it. This is the eve-bot guarantee in miniature, done prescriptively.

First, write a memory tagged to account:acme under your org handle, then mint an Acme scope and a Globex scope from the same principals — entity scope is the only difference:

bash
# read the values dev saved (server, tenant, and the org-wide handle)
export V=http://127.0.0.1:7717
export TENANT=$(grep tenant_id ~/.verity/config.toml | cut -d'"' -f2)
export H=$(grep scope_handle ~/.verity/config.toml | cut -d'"' -f2)

# a memory only an Acme-scoped agent should ever see
curl -s -X POST "$V/v1/episodes" -H 'content-type: application/json' -d "{
  \"scope_handle\":\"$H\",
  \"observation\":\"Acme's renewal quote is \$84,000 net-30.\",
  \"entities\":[\"account:acme\"]}"

# two handles, SAME principals [1], different entity scope — that is the whole trick
mint() { curl -s -X POST "$V/v1/scopes" -H 'content-type: application/json' \
  -d "{\"tenant_id\":\"$TENANT\",\"principals\":[1],\"entity_scope\":$1,\"actor_azp\":\"$2\"}" | jq -r .scope_handle; }
ACME=$(mint   '["account:acme"]'   agent:sales-bot)
GLOBEX=$(mint '["account:globex"]' agent:eve-bot)

Now run the same recall under each handle:

bash
# the Acme-scoped agent finds it
curl -s -X POST "$V/v1/recall" -H 'content-type: application/json' \
  -d "{\"scope_handle\":\"$ACME\",\"text\":\"acme renewal quote\",\"k\":5}" | jq length
# → 1

# the Globex-scoped agent — same org token, different entity scope — sees nothing
curl -s -X POST "$V/v1/recall" -H 'content-type: application/json' \
  -d "{\"scope_handle\":\"$GLOBEX\",\"text\":\"acme renewal quote\",\"k\":5}" | jq length
# → 0

You just proved the core property yourself: the second agent holds a legitimate org credential — it is not an outsider — yet it got 0 results, not because a model chose to withhold, but because the entity-scope filter excluded every Acme chunk inside the index query. A prompt-injected “ignore your scope” can't widen it, because the filter was never in the prompt to override.

note The grep lines above pull $TENANT and $H straight out of the config dev wrote — the same values printed in the step 1 summary. The full multi-agent version — adding restricted pricing, a support purpose-clamp, and org-wide analytics — is the Permissions walkthrough.

5 · Connect a real agent over MCP

Finally, hand this memory to an agent. mcp install prints the exact claude mcp add line for your config — identity (tenant, principals, actor) is baked into the environment, never a tool argument the agent can talk its way around.

sh
verity-cli mcp install

what you'll see

console
  Wire Claude Code to Verity:

      claude mcp add verity \
        -e VERITY_URL=http://127.0.0.1:7717 \
        -e VERITY_TENANT_ID=c1e6… \
        -e VERITY_PRINCIPALS=1 \
        -e VERITY_ACTOR_SUB=user:me \
        -e VERITY_ACTOR_AZP=agent:claude-code \
        -- /path/to/verity/target/release/verity-mcp

  tools: memory_open_scope, memory_recall, memory_get, memory_remember,
  memory_record_action, memory_activity, memory_brief, the ingest trio,
  memory_forget, memory_whoami.

  re-run with --run to execute this command now.

You just got the exact command to give any MCP-capable agent (Claude Code, Cursor, …) permission-aware memory. Run that claude mcp add line — or verity-cli mcp install --run to have it executed for you — and the agent opens a scope with memory_open_scope, then recalls, remembers, and records actions through the same in-index enforcement you just tested.

All 14 MCP tools and when to reach for each: API reference → MCP tools.

Where to next

You have a working, scoped, agent-connected memory. Pick the tier that matches what you're actually doing — each goes as deep as you need and no deeper.

in a hurry? The Cookbook is the same commands as copy-paste recipes — “scope an agent to one account”, “ingest a HubSpot account”, “connect an agent over MCP” — each answering one goal with minimal prose.