Concepts

The mental model

Verity has a small number of load-bearing ideas. Once the memory layers, entity tags, scope handles, and the knowledge layer click, every route and tool in the rest of the docs reads as an application of them.

Architecture & deployment

Before the concepts, the shape of the system — because it is easy to over-read “the MCP server.” The MCP server is not Verity. It is a front door. Verity is one central, multi-tenant server; the adapters that agents connect through are thin, stateless, and cheap to multiply. Getting this picture right tells you where memory lives, where enforcement runs, and how to give two agents different reach.

One core server, many thin front doors Two agent runtimes each connect through their own verity-mcp adapter, one carrying identity A and one carrying identity B from its launch config; a custom app connects over REST or an SDK with a token. All three converge on one multi-tenant Verity server that holds all memory and enforces every scope decision, backed by Postgres plus optional SpiceDB, Qdrant, and MinIO. callers (many, cheap) agent runtime A e.g. a support agent agent runtime B e.g. a sales agent custom app / service framework adapter, script thin front doors (stateless) verity-mcp · identity A stdio proxy · no data / no enforce verity-mcp · identity B stdio proxy · no data / no enforce REST / SDK · token direct to the core server the verity server one, multi-tenant all memory · all enforcement Postgres + optional SpiceDB / Qdrant / MinIO stateful, security-critical — exactly one of it
Multiplicity is only at the adapter layer, and it is cheap: to give two agents different reach, you run two verity-mcp configs pointed at the same server. The red box is the one component that stores data and makes decisions.

One core server, many thin front doors

The core verity server (Rust + Postgres, plus optional SpiceDB, Qdrant, and MinIO) is the singular, stateful, security-critical component. All memory for all tenants lives here, and every scope decision is enforced here. It is multi-tenant — tenant is the first-position filter on every query — and there is one of it.

verity-mcp is a thin, stateless proxy: no data, no storage, no enforcement logic. Each instance is a small stdio shim that carries an identity from its launch config and forwards each MCP tool call to exactly one REST call against the core server. The analogy is a database client with a baked-in login: one database, many authenticated clients — the clients are not databases.

correction “The MCP server” is not Verity. It is a front door — a per-identity adapter. The server is the system: it is where memory is stored and where every visibility decision is made. An adapter with a tampered request still gets a 401 from the server; nothing is enforced in the shim.

Running many agents with different reach

To give two agents different reach today, you run two verity-mcp configs — different identity env, both pointing at the same server. That is a config entry, not a second Verity:

sh
# adapter for the support agent — scoped to support principals
VERITY_URL=https://verity.internal \
VERITY_TENANT_ID=acme \
VERITY_PRINCIPALS=user:support-bot,group:support \
VERITY_ACTOR_SUB=support-bot VERITY_ACTOR_AZP=agent:support \
  verity-mcp

# adapter for the sales agent — different identity, SAME server
VERITY_URL=https://verity.internal \
VERITY_TENANT_ID=acme \
VERITY_PRINCIPALS=user:sales-bot,group:sales \
VERITY_ACTOR_SUB=sales-bot VERITY_ACTOR_AZP=agent:sales \
  verity-mcp

An application that isn't an MCP client skips the shim entirely and speaks to the core server directly over REST or a framework SDK, passing its own token. Same server, same enforcement — a different door.

Identity: config today, per-request token tomorrow

This is the one place to be precise about built-vs-spec'd, because it is what makes the adapter multiplicity necessary in the first place.

Built now today
Identity is fixed per adapter config. A verity-mcp instance carries one identity from its env (VERITY_PRINCIPALS / VERITY_ACTOR_SUB / VERITY_ACTOR_AZP). The agent can narrow within that — open_scope's entity and purpose, and which handles it picks — but it can never widen past the configured principals, and it cannot set its identity at all. Identity is process configuration, never a tool argument.
Spec'd next not yet built
The SPEC's identity plane (§6/§9) describes per-request identity from the authenticated caller's token — the (user, agent, on-behalf-of) tuple from an MCP Enterprise-Managed Authorization / ID-JAG token. That would let one verity-mcp serve many identities, resolving principals live via SpiceDB per request — collapsing the adapter multiplicity entirely. The REST /v1/scopes route already accepts a subject that the server resolves through SpiceDB; the MCP shim does not use that path yet — it passes its configured principals.

So: per-request token identity is not yet built — today the shim uses configured principals, and multiplicity lives in the adapter layer. Once the token path lands, a single adapter can front many callers. The concepts below (scopes, handles, provenance) hold either way; only where identity enters changes.

The memory layers (L0–L3)

Everything written to Verity lands first in an immutable evidence log, then is derived forward into progressively more query-shaped tiers. No LLM ever touches the structured write path — derivation for facts is deterministic.

The four memory layers Writes land in the immutable L0 evidence log, derive into L1 bi-temporal canonical records and chunks, then L2 extracted facts, then L3 materialized per-entity briefs. Lineage links every derived tier back to L0. L0 · evidence log immutable, append-only · lineage from day one · crypto-shreddable for erasure L1 · canonical records + chunks bi-temporal facts (valid_from / valid_to) · a CRM row stays a row; updates supersede structurally L2 · extracted facts (subject, relation) supersession via L1 machinery L3 · entity briefs one-call current state; scope-re-filtered on read scoped hybrid recall · entity briefs · activity timeline  →  agents
Writes flow down; lineage links every derived tier back to its L0 evidence, which is what makes retraction and erasure a lineage walk rather than a search.
L0 — evidence log
Every write (a CDC event, a webhook payload, an agent observation, a document version) becomes an immutable episode. L0 powers audit, poison rollback, and crypto-shredding. It is never rewritten.
L1 — canonical records & chunks
Structured data becomes bi-temporal facts keyed by (source, entity_id, field); unstructured text becomes searchable chunks. An “opportunity updated” event is a deterministic keyed upsert that retires the old value — supersession is structural, not ranked.
L2 — extracted facts
An extraction worker turns episodes into (subject, relation, value) facts, superseded through the same L1 bi-temporal machinery. The extractor is deterministic in tests, with an Anthropic seam for the general case.
L3 — entity briefs
A materialized brief is the current state of one entity in a single call: newest memory + recent agent activity + staleness metadata. Briefs refresh lazily on read (debounced) and in batch; crucially, the items in a brief are always re-derived under the caller's scope, so a brief can never leak.

Bi-temporality

L1 facts carry valid_from and valid_to. When a value changes, the previous row is not deleted — its valid_to is closed and a new row opens. This gives you two things at once:

example In the launch demo, an opportunity amount moves from $50,000 to $84,000 via a CDC update. A read at ?as_of= 30 seconds ago still returns 50000, marked superseded — while the current read returns 84000. The Scoped Recall Benchmark measures 0 stale citations across 200 reads after supersession.

Entities & entity tags

An entity is the thing a memory is about — usually a customer account, a contact, a team, or a user, addressed as a namespaced string like account:acme-corp. Every chunk, fact, and action is stamped with the entities it concerns.

Verity is honest about which tags are guaranteed:

Deterministic tags guaranteed
Tags derived from provenance at write time — a chunk from a structured object, a transcript attached to the Acme opportunity, an observation written under an Acme-scoped handle. Plane-3 guarantees over these tags are architectural.
Probabilistic tags measured
Tags inferred from unstructured text by an NER/LLM pass. A missed tag would widen retrievability, so the tagger is tuned for recall over precision, is suggest-only by default (opt in with VERITY_AUTO_TAG=1), and low-confidence content from sensitive sources is quarantined rather than indexed.
deny-by-default intersection A chunk tagged with two entities (a call transcript mentioning customers A and B) is retrievable only in a scope covering all its tags, or in neither — never in the union. And zero-tag content is retrievable only in explicitly broad scopes, never in an entity-bound one: “untagged therefore almost nowhere,” the inverse of the usual failure mode.

Scopes & scope handles

A scope is the answer to “who is asking, and about what?” A session mints a server-side MemoryScope handle — an HMAC-signed credential (the Typesense pattern) that binds three things for the whole session:

How a scope handle is minted and enforced Identity resolves through SpiceDB into a principal set; open_scope signs those principals, the entity scope, and a confidentiality ceiling into an HMAC handle; every read verb verifies the handle and applies its filters as a mandatory in-index pre-filter. identity user sub + agent azp resolved via SpiceDB open_scope → mint HMAC-signs principals + entity_scope + ceiling scope_handle (opaque) the ONLY credential Verity issues; passed to every other verb verb verifies signature, then filters IN the index query tampered handle → 401 · filters cannot be widened by arguments results the caller is allowed to see — and nothing else
The handle is compiled ahead of time: the read path makes zero live authorization calls for the common classes. Correctness and speed come from the same design.

The permissions page covers this in depth — the crucial property is that a handle's filters cannot be widened by agent-supplied parameters. Cross-entity analytics requires opening a different, audited scope. Go to Permissions →

ACL provenance

Every fact and chunk carries exactly one ACL provenance tag recording how its visibility was derived. This is surfaced on every read, so trust in a filter is never buried in docs:

mirrored
Visibility came from a real source ACL API (Google Drive permissions.list). The highest-fidelity tier.
approximated
Visibility was derived from a proxy for the real ACL (team membership standing in for issue visibility). Honest about being a best-effort mapping.
admin-assigned
Visibility was set by an explicit policy at ingest time — a webhook's bound set, a CLI --visibility, a framework sink's visibility_policy.
quarantined
No usable visibility could be derived. The item is held for review, never indexed permissively. This is the fail-closed default for anything ambiguous.

The knowledge layer

Scoped memory answers “what happened with customer A.” Knowledge items answer “what have we learned across customers” — objection patterns, segment behaviors, playbooks. The learning is valuable precisely because it crosses scopes, and dangerous for exactly the same reason. Verity's answer: generalization is a privilege earned through provable de-identification, never a default of recall.

A knowledge item is an entity-free semantic memory whose subject is a category, never an entity — e.g. “Healthcare-segment customers consistently require DPA redlines before security review.” It is promoted through an async, sleep-time pipeline that never touches a hot path:

The knowledge promotion pipeline Agents propose hypotheses; the consolidation worker clusters them across entities; a deterministic de-identification gate screens for entity names, quotes, and identifying values; k-distinct-entity support and a category-size floor apply; a human review queue publishes. propose agents, n=1 consolidate cluster across entities de-id gate deterministic screen k ≥ 3 distinct entities publish human any gate failure → quarantined (auditable), never published
Agents are hypothesis generators, not generalizers — a scoped agent structurally cannot know a pattern holds across customers. The consolidation worker, running in the trusted server plane with no conversational output, is the actual generalizer.

The safety properties, all deterministic:

The consolidation-merge decision itself is measured, and it is tuned precision-first: a false merge would fabricate cross-customer support, so precision dominates recall by design. On a 206-pair eval set, the lowest threshold that holds precision ≥ 0.99 is 0.73, buying recall 0.1064 (~30% of true paraphrase merges) at a false-merge rate of 0 — recall is a capability disclosure, precision is the guarantee. An LLM judge in the merge cascade is designed to lift that recall, but is not yet measured. The full mental model — the three roles, every gate, the merge cascade, and worked lifecycles — is on the knowledge layer page.

the one exception Published knowledge is the single thing retrievable in an entity-bound scope that isn't tagged within that scope — the §7g carve-out. It is safe because a published item is positively verified entity-free, keyed on its status: published, not on the absence of tags. See the carve-out in Permissions, or the carve-out on the knowledge page.

Glossary

principal / principal token
A canonical identity (user, group, or agent) that a permission can name. Materialized to a small integer token per tenant for fast in-index filtering.
scope handle
The HMAC-signed session credential binding principals, entity scope, and confidentiality ceiling. The only credential Verity issues.
episode
One immutable L0 record of a write. Everything derives from episodes.
fact
A bi-temporal L1 record keyed by (source, entity_id, field).
chunk
A searchable unit of text with an embedding, a visibility set, entity tags, and a confidentiality class.
brief
A materialized L3 view of one entity's current state, always re-filtered to the caller's scope on read.
action record
An entry on the scoped activity timeline — what an agent did, when, with what outcome — so other agents can check before acting.
confidentiality class
One of public / internal / confidential / restricted. Pricing, quotes, and negotiation terms land in restricted.
knowledge item
An entity-free, category-level generalization published past the de-identification gate.
tenant
The top-level isolation boundary; the first-position filter on every query.