1.0. System
In one glance
- You will: Install mise, trust this checkout’s task files by name, and run a clean clone all the way to a green offline suite.
- You need: Git, a Unix-like shell, and permission to install tools into your own user account. No model, no container engine, no cluster, no cloud project.
- Time: about 20 minutes, hands-on.
Why the toolchain is pinned, and what the doctor checks
Toolchain pinning means the repository fixes an exact version for every command-line tool it shells out to. That is the Go toolchain, the linters and formatters, the documentation builder, and the SQLite CLI, and the repository ships one command that compares those pins against your machine.
It exists because machines running different linters or compilers reach different verdicts on identical code, and no test catches that: the tests are what differ. Two machines whose golangci-lint versions are two minor releases apart disagree about an empty diff. The comparison also catches a tool nobody installed, which otherwise surfaces as a bare command not found four levels down a task chain.
This page installs mise, trusts this checkout’s five task files by name, and takes a clean clone to a green offline suite in four commands. Every later page starts there.
You will run that comparison two sections from now, once mise itself is on your machine:
mise run doctorHere is what it says before anything is installed: every line names a tool and its remedy, and the run exits non-zero. This is a real run with PATH stripped to the few shell utilities the script itself calls, so twenty tools come back missing; these are its first four lines:
missing: go remedy: mise run install
missing: hugo remedy: mise run install
missing: golangci-lint remedy: mise run install
missing: gotestsum remedy: mise run installTen more mise-managed tools follow with that same remedy. Then come six the repository does not own — git, curl, cc, install, make, and tar — and each of those points at a reviewed host package source instead, because no repository installer can conjure a C compiler. The run closes by telling you to re-run the doctor for the profile you asked about: the named tier of prerequisites it compares against your machine, base here.
Deeper: which hosts are exercised, and which are best-effort
The doctor reads your tools, not your operating system; host support is a matrix rather than a yes.
| Host | Status | What that means here |
|---|---|---|
| Linux x86_64 with cgroup v2 | Fully supported | Offline checks, containers, k3d, and host observability are exercised here. |
| Linux arm64 | Best-effort | Go builds are portable; pinned third-party images and tools may differ. |
| macOS | Best-effort | Offline Go and docs work; container networking follows the desktop runtime. |
| WSL2 | Best-effort | File permissions, cgroups, and host networking depend on the WSL setup. |
Everything on the required path — the offline checks, the local model, the agent itself — works on all four; only the first row exercises the heavier optional half: containers, the local cluster, and host observability. SUPPORT.md owns this matrix and its deprecation policy.
Install mise, then trust five task files by name
Get the source first — every command here resolves against a path inside the checkout, so there is nothing to trust until one exists:
git clone https://github.com/MLOps-Courses/agentops-open-course.git
cd agentops-open-courseInstall mise from its official instructions and activate it in your shell. Trusting a mise configuration file approves the task definitions inside it for execution, so do it one file at a time:
mise --version
mise trust mise.toml
mise trust agents/go/mise.toml
mise trust agents/data/mise.toml
mise trust evals/mise.toml
mise trust tools/mise.tomlTrusting everything at once — the --all form of that command — walks parent directories and unrelated nested configurations, so on a laptop with several checkouts under one directory it can quietly approve task files you have never read. Naming each file is slower to type and impossible to get wrong.
If mise --version prints a version but a later task still runs the wrong tool, mise is installed without being activated: restart the shell and check again.
Run four commands to take a clean clone to green
One of them builds SQLite from source, so the C toolchain the doctor named has to be there first. That build is deliberate: a moving version-manager plugin would compile bytes nobody reviewed, and a distribution’s own sqlite3 could not keep agents/data/incidents.db reproducible. Install the compiler from a reviewed host package source, the line that matches your system:
sudo apt install build-essential # Debian and Ubuntu
sudo dnf group install development-tools # Fedora
xcode-select --install # macOSThen run these in this order, from the repository root:
mise run install
mise run doctor
mise run check:core
mise run testinstall resolves the three Go modules, materializes the Hextra documentation theme, rebuilds the SQLite CLI from a checksum-verified upstream archive, and connects the Git hooks to the same tasks you just ran. doctor reports the base profile. The :core suffix marks the slice of a task that needs no model, container engine, cluster, or cloud project. Neither of the last two makes a model call, opens a network connection to a provider, or reads your .env.
Predict before you run them: how long should a repository that contains an AI agent, an evaluation harness, and a documentation site take to check itself?
check:core takes a couple of minutes, because it lints the shell scripts, parses every inline mise task body under its configured shell, and security-reviews the GitHub Actions workflows. These are its last three lines:
[check:shell] GKE model smoke context, payload, retrieval, and fail-closed checks passed
[check:shell] Finished in 147.17s
Finished in 147.91smise run test then runs all three module suites. The agent’s own suite ends with a per-package coverage report rather than one flattering total:
DONE 1815 tests, 1 skipped in 4.826s
[test] $ ../../scripts/check-coverage.sh coverage.out 80 agents/go
ok 84.2% agents/go/a2aserver
ok 91.7% agents/go/compose
ok 91.0% agents/go/config
ok 100.0% agents/go/model
ok 98.5% agents/go/tools
agents/go meets the 80% per-package coverage floorThat is one real run, trimmed: twenty packages are reported and five survive here, and the timing is a warm cache — a first run compiles everything and takes minutes rather than seconds. The 80% floor is per package rather than a module average, and it counts statements that ran, not statements anything asserted on.
The one skip is deliberate, not a broken machine. a2aserver’s TestPostgresSessionProbeAgainstARealServer needs a live PostgreSQL, so it skips whenever AGENT_TEST_SESSION_DSN is unset and prints the docker run command that would un-skip it. Everything the account-free path promises is in the 1,814 that ran.
You have just verified an agent’s composition, configuration, persistence, and policy plane on your own machine, offline, in about three minutes. Nothing in that run called a model, so it says nothing about answer quality: whether the agent picks the right tool, or whether its answer follows from what that tool returned. 0.2. Evidence owns that distinction and every later page links there rather than repeating it.
Formatting is a separate verb on purpose. mise run format:core rewrites files, so run it deliberately and read the diff; mise run build:docs renders the site into site/ and fails on any warning.
What each doctor profile checks, and what it never claims
There are five profiles, and the tool lists they compare against live in the script, not in this page:
readonly -a base_managed_tools=(go hugo golangci-lint gotestsum dprint sqlite3 jq lychee shfmt shellcheck actionlint zizmor rg trivy)
readonly -a base_host_tools=(git curl cc install make tar)
readonly -a model_host_tools=(ollama)
readonly -a gateway_managed_tools=(yq)
readonly -a gateway_host_tools=(docker openssl)
readonly -a platform_tools=(
k3d kubectl helm helmfile skaffold kubeconform kube-linter agentgateway promtool sops age-keygen
)
readonly -a gcp_platform_tools=(kubectl helm helmfile skaffold kubeconform tofu tflint)
readonly -a gcp_host_tools=(gcloud gke-gcloud-auth-plugin)The base doctor checks mise-managed actionlint, dprint, go, golangci-lint, gotestsum, hugo, jq, lychee, rg, shellcheck, shfmt, sqlite3, trivy, and zizmor, plus the six host prerequisites cc, curl, git, install, make, and tar. Each heavier profile adds its own tier on top:
- model adds
ollamaand the configured local model. - gateway adds mise-managed
yqplus hostdockerandopenssl, and checks the pinned host gateway wrapper. - platform checks
age-keygen,agentgateway,helm,helmfile,k3d,kube-linter,kubeconform,kubectl,promtool,skaffold,sops, plus the gateway tier. - gcp checks
gcloud,gke-gcloud-auth-plugin,helm,helmfile,kubeconform,kubectl,skaffold,tflint, andtofuplus the gateway tier.
Run only the profile the page in front of you names. mise run install:platform provides the platform tier; the repository deliberately installs no Google Cloud CLI components, so gcloud and gke-gcloud-auth-plugin come from the same reviewed Cloud SDK or host package source as the rest of your system, and mise run doctor:gcp then verifies the whole live path.
A doctor result says the prerequisites are present, and nothing else. It does not claim the application works, the model answers well, a deployment is healthy, or a release is fit to ship.
Your turn: separate the pinned tools from the host prerequisites
The doctor prints its failures, not the list it checks against. The --requirements flag prints that list, and reading it once shows which parts of your machine this course owns and which it merely requires.
Predict first: of the tools the base profile needs, how many can mise run install provide, and what is the C compiler for?
- Mode:
inspect— the flag only prints; it installs and checks nothing. - Goal: separate the tools this repository pins from the prerequisites your host owns, and explain why the split exists.
- Files to touch: none.
- Preflight:
mise run doctorexits zero. - Steps: from the repository root run
./scripts/doctor.sh --requirements base, then./scripts/doctor.sh --requirements platform, and compare the two lists. Each line is a tool and its remedy, separated by a tab. - Gate that proves completion: you can name the six tools whose remedy is a host package source rather than a repository task, and say which install step needs
cc,make, andtar. Readscripts/install-sqlite.shif the answer is not obvious — it downloads one upstream SQLite archive, verifies its SHA-256, compiles it, and asserts the resulting binary’s version. - Final state: no files changed, no tools installed.
What you can do now
mise run doctorreports the base profile ready, and you can read its failure output as a tool-and-remedy list rather than as noise.mise run check:coreandmise run testboth pass on your machine, with no model, no container engine, and no network.- You trusted five named task files instead of everything under your home directory.
- You can say which doctor profile a later page needs, and why a green one never implies the next.
This was an unfamiliar checkout when you opened it. It is now a machine where every tool that decides a verdict is pinned, and where the difference between “the code is wrong” and “your toolchain is different” is one command away.
Start the model download now, in a second terminal, and it arrives while you read: ollama pull qwen3:4b-instruct fetches about 2.5 GB, and 1.4. Providers is where you verify it.
Continue to 1.1. Go, which takes that green run apart and says what each check covers and what it leaves unproved. Or go straight to 1.4. Providers if you want the model answering first, and come back to 1.1. Go before you edit anything.