> ## Documentation Index
> Fetch the complete documentation index at: https://vitruvio.sh/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# How vitruvio runs a brain

> The lifecycle of a brain in commands, the one output contract every command honours, the exit codes, and why every write names an actor.

[The protocol](/docs/concepts/what-is-a-boltzmann-brain) says what a brain is. Vitruvio is what you run against one.
This page is the shape of that: the handful of verbs, the one output contract, and the two rules that every
command obeys.

## The lifecycle, in commands

| step | command | what happens | read more |
| - | - | - | - |
| register | `vitruvio source register notes.md` | the evidence enters canonical memory, byte for byte | [Registering evidence](/docs/sources/registering-evidence) |
| index | `vitruvio index build` | the six index kinds the planner chooses from are derived | [Indices](/docs/under-the-hood/indices) |
| search | `vitruvio search "what notes.md is about"` | an evidence bundle comes back: blocks, ids, provenance | [Searching](/docs/brain/searching) |
| ingest | `vitruvio ingest run notes.md` | a model proposes knowledge; the gate validates before anything is committed | [Ingest](/docs/brain/ingest) |
| remove | `vitruvio retain supersede BLOCK --supersedes OLD --memory-type semantic` | one of five mechanisms; blocks are never mutated | [Retention](/docs/brain/retention) |
| publish | `vitruvio dist push --tag v1` | the brain leaves as an OCI artifact, to any registry | [Publishing](/docs/brain/publishing) |
| reconcile | `vitruvio dist fetch`, then `vitruvio reconcile merge THEIRS --reason "..."` | a history somebody else advanced joins yours | [Reconciliation](/docs/reconciliation/behind-ahead-diverged) |

Everything vitruvio derives — indices, statistics, the embedding cache — lives under `.vitruvio/` beside the
layout. Deleting it costs time, never knowledge: the blocks are the brain, and everything else is rebuilt from them.

Every command needs to know **which brain** it means. Inside a project that is a name, `--brain optics`; alone it
is the nearest `vitruvio.toml`. The full resolution order is on [Selecting a brain](/docs/projects/selecting-a-brain).

## One output contract

Every command that returns data takes `--json` and emits exactly one envelope on stdout. Notes, progress and
warnings go to stderr, so `vitruvio search q --json | jq` works unconditionally.

```json theme={null}
{
  "vitruvio": "0.10.0",
  "command": "query.search",
  "ok": true,
  "data": {},
  "warnings": [],
  "error": null
}
```

Branch on `ok`, then on `error.code`. Read `warnings` **even when `ok` is true**: "the vector index will not be
published", "stats are stale", "the recall floor was lowered" all arrive there, and a degraded result that looks
identical to a clean one is the failure this design exists to prevent. On a failure, `error.retryable` says whether
the same request could succeed if repeated unchanged; `command` names the operation that failed, whether or not it
got far enough to run.

`browse` is the one exception. It is an interface for a person, has no envelope, and refuses `--json` rather than
printing something a caller cannot read.

## Exit codes

The point of these is "may I retry, and with what changed".

| code | meaning | what to do |
| - | - | - |
| 0 | success | — |
| 1 | a bug in vitruvio | report it; do not retry |
| 2 | usage error | rephrase the command |
| 3 | no brain selected, or config invalid | fix the config, or pass `--brain` |
| 4 | not found | do not retry |
| 5 | protocol violation: verification, membership, integrity | **do not retry**; this is corruption or a broken claim |
| 6 | refused by retention policy, or by `publish = false` | **do not retry**; the declaration says no |
| 7 | candidates rejected by validation | repair the payloads and retry |
| 8 | push is not a fast-forward | `dist fetch`, reconcile, push again — never `--force`, never `pull` |
| 9 | registry unreachable or refused | retryable |
| 10 | the cascade needs human review | stop and ask a person |
| 11 | a declared source was unreachable or refused | retryable |
| 12 | a reconciliation is open on this brain | `reconcile status`, then `continue` or `abort` |
| 13 | another caller is writing to this brain, or moved it under a read | retryable |

The distinction that matters most: **2** means you asked wrong, **5** and **6** mean the protocol refused and
retrying is pointless, **7** means your input was wrong and is fixable.

## Every write names an actor

```
error: no actor identity is configured, and every write is attributed in provenance
```

This is a refusal, not an inconvenience. An unattributed write is a provenance record that lies, and the whole value
of the provenance module is that it does not.

Reads never need one: inspecting someone else's brain is legitimate and attributes nothing.

The declaration in `vitruvio.toml` is authoritative. Once `[actor] id` is set, every write into the project is
attributed to it: a `--actor` or `VITRUVIO_ACTOR_ID` naming the same id is a harmless repetition, and one naming a
different id is refused with `ACTOR_OVERRIDE_REFUSED` (exit 3) rather than obeyed, because provenance must not
depend on which shell ran the command. Only the commands that create the declaration — `brain init`, `project init`,
`brain migrate` — may name any actor.

A brain kept by a different person inside a shared project declares its own actor, and that declaration is
authoritative for writes into that brain in the same way:

```toml theme={null}
[brains.optics.actor]
id = "colleague@example.com"
```

`project add optics --actor colleague@example.com` writes it when the id differs from the project's; a brain that
declares none is written to by the project's actor.

New writes accept exactly two stable actor-id forms: a lowercase address (`you@example.com`) or a lowercase
namespaced name (`openai/codex`). Vitruvio refuses uppercase, whitespace and free-form display names rather than
normalizing them, because the bytes enter provenance block identities. `name` remains the display label.

When another agent helped the primary actor, record it instead of replacing the author. Each brain declares who
may assist writes into it, and a brain that declares nobody inherits the project's list:

```toml theme={null}
[[assisted_by]]                       # the project's default
id = "openai/codex"
kind = "agent"
name = "Codex"
model = "openai/gpt-5"

[[brains.optics.assisted_by]]         # this brain's own agents, replacing the default for writes into it
id = "anthropic/claude-code"
kind = "agent"
```

With nothing else said, every declared party is recorded on every write. The global `--assisted-by` flags, or a
JSON array in `VITRUVIO_ASSISTED_BY`, *select* among the declared parties — keeping their declared `kind`, `name`
and `model` — and a party the brain has not declared is refused with `COLLABORATOR_NOT_DECLARED` (exit 3), because
a collaborator that appears in provenance without appearing in the committed file is the attribution nobody
reviewed. `--empty-assisted-by` records no assistance for one invocation. `brain init --assisted-by` and
`project add --assisted-by` write the declaration; `config show` and `inspect doctor` (`config.collaborators`) show
it. Assistance is written into provenance v2 on every new operation.

Ingest is stricter, because it is where a model writes. `ingest run` and `task commit` take the actor from the
declaration and from nowhere else — `--actor` or `VITRUVIO_ACTOR_ID` naming anyone the file does not declare for
that brain is refused with `ACTOR_NOT_DECLARED` — and they refuse to run until the invocation says who assisted:
`--assisted-by ID` for each assisting agent, chosen among the declared parties, or `--empty-assisted-by` when nobody
did (`COLLABORATOR_REQUIRED` otherwise). "Every declared party" is a default, and a default is not a statement.

## Integrity is not authenticity

`brain verify` proves that the blocks match their hashes and module roots. `auth status` additionally asks whether
valid, authorized SSH signatures support the claimed head. A brain can be intact and still be unsigned, unpinned,
or signed by a key outside its trust root — which is why the two are always reported separately, and why
[governed or ungoverned](/docs/onboarding/governed-or-ungoverned) is the first decision when creating one.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.