Share reviews across a team
A review is a line in a file in your repository. So the question “how does my teammate see my review?” has the same answer as “how does my teammate see my code?” You commit it and they pull.
There is a second, optional path through the hosted portal. It is worth understanding what it does and does not do, because the names mislead.
The default: commit .vidi/
vidi init creates the ledger files and tells you to commit them:
$ vidi init
initialized: this repo can now track reviews in .vidi/
created .vidi/: commit these files so reviews travel with the repo
updated .gitattributes + .gitignore: combine review records across branches; keep the scan cache out of git
stage git add .vidi/ .gitattributes .gitignore
That is the entire sharing mechanism. Vouch, commit, push:
$ vidi vouch "crates/vidi-core/src/crypto/keyid.rs::impl:KeyId::fn:of_public_key"
vouched crates/vidi-core/src/crypto/keyid.rs::impl:KeyId::fn:of_public_key as you@example.com (maintainer)
content_id 8384bb1382675eb3dd0b7d3e9d858c5f · appended to .vidi/ (bare line, diff-visible)
$ git add .vidi/reviews.jsonl && git commit -m "review: vouch KeyId::of_public_key"
Your teammate pulls the branch and runs vidi status. Your review is theirs
now, and it counts toward coverage on their machine exactly as it did on yours.
No account, no server, no token. This is the free tier, and it is the recommended path.
Why two people’s reviews never collide
Review files are append-only JSONL — one claim per line, and nothing is ever
rewritten in place. vidi init adds one line to .gitattributes:
.vidi/*.jsonl merge=union
That tells git to resolve these files by keeping every line from both sides rather than asking you to pick. Two people reviewing different units on different branches produce two sets of lines, and the merge is their union.
Order does not matter either, because the merge algebra is monotone: union,
dedupe by content_id, and revoke-wins. Everyone who merges the same set of
records computes the same coverage, whatever sequence the merges happened in.
Commit that .gitattributes line along with .vidi/, the guarantee only holds
if everyone has the rule. See
Why review files never conflict.
Reviews travel with the branch
Because they are ordinary tracked files, review records follow the same rules as code:
- they arrive with
git pulland move withgit push - they are visible in a pull request diff, one added line per review
- a branch that is behind on reviews is behind in the ordinary git sense
- rebasing replays review commits like any other commit
If your team rebases rather than merges, set it once per repo:
$ git config pull.rebase true
Nothing about the ledger objects to being rebased. The merge=union rule exists
for the case where two histories genuinely diverge, which rebasing avoids by
construction.
What the hosted lane actually is
The paid portal adds two commands. They sound like a matched pair and are not:
vidi pull | vidi push | |
|---|---|---|
| Direction | portal → your machine | your machine → portal |
| What moves | review and revocation records | a coverage snapshot |
| Effect | union-merges into your local .vidi/ | stored server-side for re-rendering |
| Gates anything? | the records it adds do | never |
vidi push does not share your reviews. It uploads an already-computed
coverage snapshot, the numbers behind vidi json, so the portal can render a
dashboard. The server stores it verbatim and it never gates anything. The half
of push that would upload an authoritative review store is not built.
Pushing reviews outward stays git’s job. The portal is a read-and-display surface over a git-native ledger, plus the hydrate path below.
Logging in
Two logins, and they are for different things:
$ vidi login --local # offline identity, no account, free tier
$ vidi login # vidivouch.com device flow, the paid lane
--local records a self-asserted identity enough to authorize writes, which
is all the free tier needs. The hosted form runs a device flow and stores a
revocable bearer token, never a signing key, at ~/.vidi/token.
The two record different identity strings, which is the one thing here that will silently cost a team coverage:
| Login | attesterIdentity.id recorded |
|---|---|
vidi login --local | your git email, e.g. you@example.com |
vidi login | a person GUID, vidi:p:<uuid> |
Your policy’s [reviewers] keys are matched literally against that string. If
your team switches from local to hosted logins, list both forms for each
person, or the reviews made under the other one stop counting silently. See
policy.toml.
What vidi pull fetches
vidi pull fetches the tenant’s stored review and revocation lines and splits them
by kind. Revocations into .vidi/revocations.jsonl, everything else into
.vidi/reviews.jsonl, then union-merges each into the local file.
$ vidi pull
pulled github.com/graze-ai/vidi → 0 review + 0 revocation line(s) fetched · 0 new review + 0 new revocation merged · 0 already present
The three counts are worth reading separately: what the server served, what was new to you, and what you already had. A healthy repeat pull shows lines fetched and nothing new, which means you are in sync rather than that nothing happened.
The pull above returned nothing on a repository whose local ledger holds several
reviews, which is the push/pull asymmetry made concrete. Those reviews live in
git and have never been in the portal’s review store, because no command
uploads them there. vidi push uploads coverage, not reviews.
What comes back depends on which bearer you hold:
| Token | Repo selector | Scope of the result |
|---|---|---|
person (vida_ / vidc_, from vidi login) | required — sent as ?repo=host/owner/name | that repository |
| tenant API token | none; the bearer is already tenant-scoped | the whole tenant |
A person token can belong to several tenants, which is why it must name the repo; a tenant token already implies one, so a tenant-wide pull works even where no git remote resolves.
The merge is the same algebra as the git path, plus two rules: a review that
arrives notary-signed where you held only a self-asserted copy is reported as an
upgrade, and an undecodable remote line is refused rather than appended. A
refusal means something is wrong in transport, so pull exits non-zero if any
line was refused, even though the lines that did decode merged normally.
Configuring the remote
Both commands resolve a URL and a bearer, each by its own ladder:
| Order | |
|---|---|
| URL | --url > $VIDI_REMOTE_URL > $VIDI_NOTARY_URL > the production host |
| Token | --token > $VIDI_REMOTE_TOKEN > the stored vidi login token |
URL resolution never fails, a missing URL falls back to production rather than
erroring. The repo slug resolves as --repo > $GITHUB_REPOSITORY > the
origin remote, taking the host from $GITHUB_SERVER_URL so GitHub Enterprise
works without assuming github.com.
$VIDI_REMOTE_TOKEN is the CI path: it passes through untouched with no refresh
half, so a build authenticates without an interactive login. Keep it in your CI
secret store, not in the repository.
Pointing at a self-hosted portal, vidi will not send a bearer over plain
HTTP to a non-loopback host: use https://, or loopback for local testing.
Which path to use
Commit .vidi/ regardless, it is the source of truth and it costs nothing.
Add the portal when you want coverage dashboards across repos, or when you want fresh clones and CI to hydrate reviews without a full checkout of every branch that produced them.