> ## 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.

# Publishing a project

> Log in once, derive one repository per brain, push them all, and declare the brains you must never republish.

## Publishing: log in once

```console theme={null}
vitruvio registry login docker.io --from-docker
vitruvio project show
```

```
project     coursework
publishes   docker.io/you  (from your registry login)

  optics             docker.io/you/coursework-optics
  acoustics-ii       docker.io/you/coursework-acoustics-ii
  dynamics           docker.io/you/coursework-dynamics
```

Each brain derives `<namespace>/<project>-<brain>`. Nobody writes a registry reference per subject, and adding a
subject is adding a directory.

The namespace comes from `[registry].namespace` when set, and otherwise from whichever account you are logged in as.
That fallback is the whole point of `--from-docker`.

The **project prefix is load-bearing**: without it, two projects that each hold a brain called `notes` would publish
to one repository and overwrite each other — and the second one would find out when a pull returned the wrong
subject.

## Publishing the whole project

```console theme={null}
vitruvio dist push --all --tag v1
```

```
ok    optics             docker.io/you/coursework-optics:v1
ok    acoustics-ii       docker.io/you/coursework-acoustics-ii:v1
skip  dynamics           nothing committed yet
```

An empty brain is **skipped, not failed**: a subject you have not started yet is the ordinary state of a project. A
brain that fails for a real reason does not stop the others, and the command exits non-zero at the end — carrying
the per-brain results with it, so `--json` on a half-published project still tells you which ones went.

Run `vitruvio registry check <repository>` once before the first push to a new host. Docker Hub is verified to accept
the protocol's manifest shape; the next registry is the one that refuses.

## Overriding one brain

```toml theme={null}
[brains.thesis]
path = "./brains/thesis"
reference = "ghcr.io/you/thesis"     # this one goes somewhere else entirely
```

## A brain you did not author

Pulling a brain gives you a local working copy that is writable like any other — nothing in the protocol
distinguishes "a brain I authored" from "a brain I installed". So a stray `dist push` publishes a *fork* of a shared
brain under whichever repository this project derives, and the two lineages diverge with nobody informed.

Declare it instead of remembering it:

```toml theme={null}
[brains.common]
path = "./brains/common"
reference = "ghcr.io/acme/acme-brain"   # where it really lives
publish = false                         # `dist push` refuses this brain
```

```console theme={null}
vitruvio project add common --no-publish --reference ghcr.io/acme/acme-brain
vitruvio --brain common dist push          # exit 6, before anything is packed
vitruvio dist push --all                   # skips it, and says so
```

`project show` prints `(publish = false)` beside it, because a prohibition nobody can see is one somebody works
around by accident — the repository column otherwise reads as a statement that a push goes there.

Two things it deliberately is not. It is **not a permission**: anyone who can edit `vitruvio.toml` can flip it, which
is the right amount of friction for a declaration whose only job is to make a deliberate act look deliberate. And it
is **not read-only**: `source pull`, `ingest run` and `index build` all still work on that brain. What is forbidden
is republishing it, not updating your copy.


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