Guide 01 / Installation
Install & the repo-pinned shim
Pitot is not installed on machines. It is pinned by repositories. This guide walks through the two substrate files pitot init commits, what the shim does on first run, and why a fresh clone — human, CI runner, or cloud agent — needs zero setup.
01The model: the repository is the version authority
Most CLIs ask every machine to install the right version and hope they agree. Pitot inverts this. The repository commits exactly two things:
.pitot/version— one semver line. The only version authority..pitot/bin/pitotand.pitot/bin/pitot.ps1— committed shims that read the pin, hydrate exactly that release into a per-user cache, and exec it.
Everyone who clones the repository — teammates, CI, cloud coding agents — runs the same verified binary, because the version travels with the code it supervises.
02The front door: one line, once
You need the global CLI only for convenience — mostly to run pitot init in repositories that are not pinned yet. Install it from the distribution front door:
curl -fsSL https://get.operatorstack.systems/pitot | sh
Building from source works too: go install github.com/operatorstack/pitot/cmd/pitot@latest. Inside a pinned repository, neither matters — the committed shim always wins, and it runs the pinned version, not whatever is on PATH.
03pitot init: pin, shims, and a runnable start
In your repository, scaffold a Controller and the substrate in one step:
pitot init --template shell-policy --language go --dir agent-policy
templates: shell-policy · release-approval · blank-controller · blank-consumer — languages: python · typescript · go · rust
This writes the version pin, both shims, a runnable Controller project, and registers it as one tenant fragment under .pitot/conf.d/. It never overwrites existing files unless you pass --force. Commit everything it writes:
.pitot/ ├── version # e.g. 0.1.2 — one line ├── bin/pitot # committed shim (sh) ├── bin/pitot.ps1 # committed shim (PowerShell) └── conf.d/agent-policy.yaml agent-policy/ ├── go.mod └── main.go # your Controller — ordinary code
04Shim mechanics: hydrate once, cache forever
On its first invocation, the shim:
- reads the pinned version from
.pitot/version; - downloads that release into
~/.cache/pitot/<version>/; - verifies it against the published
checksums.txt(sha256) before anything executes; - execs the verified binary, passing your arguments through.
The cache is write-once and shared per user: switching branches or repos with the same pin costs nothing, and every later invocation is a cache hit.
05Fresh clones & CI: zero setup, by construction
Because the pin and the shim are committed, a fresh environment needs no install step at all:
git clone <your-repo> && cd <your-repo>
.pitot/bin/pitot version
first run hydrates the pinned release from production, sha256-verified, then runs it
CI jobs and cloud coding agents call .pitot/bin/pitot directly. There is no version matrix to maintain and no "works on my machine" drift — the repository decided the version when the pin was committed.
06Fail-closed rules
- No PATH fallback. The shim never silently falls back to whatever
pitotbinary happens to be installed. The pin is honored or the run fails. - Named errors. A missing release with no network fails closed with a named error — not a partial run on the wrong version.
PITOT_NO_HYDRATE=1is the kill switch: hydration becomes cache-only, so air-gapped or locked-down environments can pre-seed the cache and forbid downloads.
The shim sits in front of a tool that supervises coding agents. A supervision layer that silently runs the wrong version is worse than one that stops — so version resolution is fail-closed everywhere.
07Checking state at any time
pitot doctor
reports the effective local boundary, pin, shim, and cache state
pitot doctor --host kimi
additionally checks one host's hook wiring (Pitot never edits host configs for you)