# vet reviews a diff and an agent transcript against one goal, then exits 10

> An AGPL-3.0 Python tool, published to PyPI as verify-everything, that checks code changes for correctness and agent conversations for goal adherence using your own model provider. It installs as an agent skill, runs as a CLI, and ships as a reusable GitHub Action, and the exit codes are unusual enough to plan for.

**imbue-ai/vet** — Find issues worth your attention.

- Repository: https://github.com/imbue-ai/vet
- Stars: 518 · Forks: 19
- Language: Python
- License: AGPL-3.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/imbue-ai-vet

## The PyPI name is verify-everything, the command is vet

The naming is worth pinning down before you install anything. On GitHub the project is `vet`, the distribution on PyPI is `verify-everything`, the console script is `vet`, and the import package is `vet` with the entry point at `vet.cli.main:main`. There are three documented install routes and they differ only in isolation:

```bash
pip install verify-everything
```

```bash
pipx install verify-everything
```

```bash
uv tool install verify-everything
```

The project metadata puts the floor at Python 3.11 and classifies the package as Beta, with classifiers for 3.11 through 3.13 and a console-only environment aimed at developers. Two things about the packaging are unusual. The `vet` package ships a `py.typed` marker, so type checkers will use its inline annotations. And the dependency list is annotated by provenance, separating the original dependencies from two sets inherited from sibling internal packages, which is a hint that this tool was extracted from a larger codebase rather than designed standalone.

## Exit 10 means findings, exit 1 means the tool itself broke

The exit code contract is the part to design your CI around, because it is not the usual zero or nonzero split. Code `0` means no issues were found. Code `1` is an unexpected runtime error, meaning vet itself failed rather than passing judgement. Code `2` is an invalid usage or configuration error. Code `10` is the one that means issues were found. A pipeline that treats any nonzero status as a build failure will therefore report a clean run with findings exactly the same way it reports a crash, so the gate needs to branch on 10 specifically. Three output formats are available: `text`, `json` and `github`, with the last one shaped for a review comment that the GitHub Action can post. Underneath, the pipeline is short: vet snapshots the repo and the diff, optionally attaches a goal and an agent conversation, runs the LLM checks, then filters and deduplicates the findings into a final list.

## --history-loader runs a shell command as the current user

One security note is given its own section, and it deserves it. The `--history-loader` option executes the shell command you specify, as the current user, in order to load conversation history. That is the mechanism that lets vet read a Claude Code or Codex transcript without knowing anything about those tools' storage layouts, and it is also an arbitrary command execution path driven by configuration. The guidance is to review history loader commands and shared config presets before use, which matters most in CI where the config often comes from the repository rather than from you. The same caution extends to the named TOML profiles, since a profile is exactly the kind of file that gets copied between projects and then trusted. Nothing else in the tool is described as executing external commands, so the history loader and the profile files are the two places to read line by line.

## The GitHub Action wants pull-requests: write and a full clone

Vet reviews pull requests through a reusable action, and the workflow file it expects is given in full. The permissions block asks for `contents: read` and `pull-requests: write`, the trigger covers `opened`, `edited`, `synchronize` and `reopened`, and the job is skipped when the pull request is a draft. Checkout is pinned to the head SHA with `fetch-depth: 0`, which means a full history clone so the merge base can be computed. The step itself is one line, `uses: imbue-ai/vet@main`, with `agentic: false`, and the action handles Python setup, installing vet, computing the merge base and posting the review. `ANTHROPIC_API_KEY` has to be present as a repository secret when you use Anthropic models, which are the default. Two things to notice before copying it: referencing the action by `main` rather than a tag means your workflow follows the branch, and `fetch-depth: 0` on every pull request is not free. All available inputs are documented in `action.yml`.

## Model resolution runs user config, then builtins, then registry

Three sources feed the model list, in a stated priority order. User configuration wins, read from either `.vet/models.json` at the repository root or `$XDG_CONFIG_HOME/vet/models.json`, falling back to `~/.config/vet/models.json`. Below that sit the built-in models for Anthropic, OpenAI and Gemini. Below that sit registry models, which are community contributed and are not present until you fetch them:

```bash
vet --update-models
```

That command downloads definitions from a JSON file in the repository and caches the result at `~/.cache/vet/remote_models.json`, after which those models appear in `vet --list-models` and can be passed to `--model` like any other. This is the one part of vet that fetches and executes configuration shaped by other people, so the trust boundary is the registry rather than your provider. Definitions can be added to it through `registry/CONTRIBUTING.md`, and because the cache is local, upgrading vet is not what refreshes the list, the explicit update command is.

## A models.json entry carries a context window and an output cap

Custom definitions speak the OpenAI-compatible endpoint shape, and the example makes the required fields explicit. A provider entry needs a display `name`, an `api_type` of `openai_compatible`, a `base_url`, and an `api_key_env` naming the environment variable that holds the key rather than the key itself. Each model inside it declares a `model_id`, which is the provider-side identifier, plus a `context_window`, a `max_output_tokens` and a `supports_temperature` flag. The sample registers OpenRouter at `https://openrouter.ai/api/v1` reading `OPENROUTER_API_KEY`, with `gpt-5.2` mapped to `openai/gpt-5.2` at a context window of 400000 and 128000 output tokens, and `kimi-k2` mapped to `moonshotai/kimi-k2` at 131072 and 32768. Once defined, selecting one is just:

```bash
vet "Harden error handling" --model gpt-5.2
```

Those four numbers are what let a tool decide what to send and what to expect back, so a definition that guesses them wrong will fail quietly rather than loudly.

## Three model SDKs and a skill installed into four agent directories

The dependency list explains the built-in model coverage: `anthropic`, `openai` and `google-genai` are all required, matching the three builtin provider families exactly, alongside `tiktoken` for counting. The rest of the stack is infrastructure for reading a repository and running agents around it, with `pygit2` for git access, `libcst` for concrete syntax tree work, `diskcache` and `cachetools` for caching, `httpx`, `pydantic` and `cattrs` for request and schema handling, and `jinja2` for the prompt templates that define each check. The agent skill is a separate installation path from the CLI, and this one is worth understanding before you run it:

```bash
curl -fsSL https://raw.githubusercontent.com/imbue-ai/vet/main/install-skill.sh | bash
```

It prompts between project level, writing into `.agents/skills/vet/`, `.opencode/skills/vet/`, `.claude/skills/vet/` and `.codex/skills/vet/` at the repo root, and user level, writing into the matching directories under your home directory so every agent discovers it. Four directories is not an accident, it is the four agent tools the project names. The repository also carries a `.pre-commit-config.yaml`, so the same check can run before a commit rather than after a push.

## Conclusion

vet suits teams that already review agent output by hand and want the review to run automatically after every change, since pairing a diff with a transcript and a stated intent is a check linters cannot perform. It is pointless as a replacement for tests and static analysis, and its value collapses if your agent harness cannot export a conversation, since half the tool disappears without that transcript. Before wiring it into CI, read the exit code table rather than assuming nonzero means failure, because 10 is the success-with-findings code and 1 is the broken-run code, decide whether `pull-requests: write` and full-history checkout are acceptable in your workflow, and audit any shared TOML profile or `--history-loader` command before adopting it, since the tool documents both as places where a shell command runs as your user.

## FAQ

### How do I install and run vet?

The PyPI distribution is named verify-everything while the command is vet. Install it with pip install verify-everything, pipx install verify-everything, or uv tool install verify-everything, then run it in a repository as vet "Implement X without breaking Y". Python 3.11 or newer is required.

### What exit codes does vet use?

Zero means no issues found, 1 means an unexpected runtime error, 2 means an invalid usage or configuration error, and 10 means issues were found. Output formats are text, json and github, so a CI gate has to branch on 10 to tell findings from a crash.

### Can vet review my Claude Code or Codex session?

Yes, in agentic mode. Pass --agentic with --agent-harness set to claude, codex or opencode, so vet can use your existing subscription instead of an LLM API. The transcript is loaded through the --history-loader option, which executes the shell command you give it as the current user.

### How do I register a model that vet does not know about?

Add an OpenAI-compatible provider to a models.json file at .vet/models.json in your repo or at ~/.config/vet/models.json, naming the base URL and the environment variable holding the key. Community models can also be fetched from the registry with vet --update-models, which caches them at ~/.cache/vet/remote_models.json.

## Sources

- [imbue-ai/vet on GitHub](https://github.com/imbue-ai/vet)
- [Issues](https://github.com/imbue-ai/vet/issues)
- [License: AGPL-3.0](https://github.com/imbue-ai/vet/blob/main/LICENSE)
- [README](https://github.com/imbue-ai/vet/blob/main/README.md)
- [Releases](https://github.com/imbue-ai/vet/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/imbue-ai-vet
