Skip to content
1.5. Workspace

1.5. Workspace

In one glance

  • You will: Break the documentation checker on purpose, restore it, and learn which of the repository’s checks runs at which moment.
  • You need: The base installation from 1.0. System and a checkout with no changes you care about losing.
  • Time: about 20 minutes, hands-on.

Why the course pages are checked against the repository

This repository treats documentation as checked source. tools/bin/conventions docs reads every page against the actual tree and fails when the two disagree: paths named in prose must exist, mise run tasks must be declared in a manifest, quoted tool versions must equal the pins, included source regions must have one start and one end marker, and every Mermaid diagram must carry a prose alternative beside it.

The checker exists because prose drift is silent. A page pointing at a Go file renamed eleven months ago breaks no build and no test; the cost lands months later, on a reader, and in a teaching repository the pages are the product. You will watch the checker catch a missing path, then sort authority from disposable output and match each check to its moment. The offending sentence was appended to this very page, and the checker was run from the repository root:

tools/bin/conventions docs
content/1. Setup/1.5. Workspace.md: line 105: literal repository path does not exist: agents/go/nope.go

Line 105 is two past the last line of this page as it ships, which is where an appended sentence lands. Delete it, run the same command, and the checker goes quiet and exits zero.

That binary is part of the toolchain you already installed: mise run install builds it into tools/bin, and mise run check:docs runs this exact command before building the site, so the hook, CI, and your terminal all decide the same way. Rename a task and the page that documented it fails before the rename is committed.

You have just watched documentation treated as something that can be wrong, not merely old.

Which files are authority, and which are disposable output

One rule sits underneath all the others: a small set of files decide what is true. Everything a command produces records one moment rather than a fact about the project.

Authority lives in mise.toml for task names and pinned tools; in agents/go/go.mod, evals/go.mod, and tools/go.mod for declared dependencies, with their go.sum files owning exact resolution; in AGENTS.md for repository invariants and operating limits; and in dprint.json plus the three .golangci.yml files for mechanical style. Use whatever editor you like, as long as it runs gopls and mise run format gets the last word on style, not your editor’s plugin.

Everything below is generated, ignored by Git, safe to delete, and never a source of truth:

  • agents/go/.state/ holds the writable runtime databases and crash-recovery journals.
  • site/ holds the rendered documentation site.
  • coverage.out and its reports are local measurements.
  • results.json and any artifact named by an --output flag record one run and nothing more.
  • .env and local credentials are private configuration.

One exception hides inside the first bullet. A state restore copies a snapshot of those databases back over the live ones, and a dot-prefixed .restore-* file in the state directory is the journal a half-finished restore left behind, recording which copy of the data was real. It is evidence, not litter to sweep up because a status command looks noisy: read one before you remove it. 2.4. Sessions has you plant one, watch startup refuse to guess at it, then delete it deliberately.

The three Go modules are separated for the reason 1.1. Go argues: the black-box evaluation harness must stay unable to import agent internals. And when you change a fact, change its owning source, its test, and its public contract together — never copy a dependency version into prose when the lock owns it.

Lefthook runs the same mise tasks, scoped to what changed

Local hooks are a second implementation of CI in most repositories, which is why they drift and then get bypassed. Here they are thin: lefthook only calls mise run tasks, so a hook and a workflow cannot disagree about what “checked” means.

This page’s Markdown source carries both hook task lists in a comment that check:docs rebuilds from lefthook.yml, so the two cannot drift. pre-commit formats staged Markdown, configuration, and Go, runs one check:* task per kind of file you staged, then scans that diff for secrets; each check is globbed to the paths it owns, so a one-word README fix does not pay for the Go linters. pre-push drops the globs and runs the model-, container-, cluster-, and cloud-free check:core plus the full test suite, so nothing reaches a remote unchecked, and bypassing a hook only moves the failure later. Hosted CI prepares the same deterministic surface with mise run install:validation, which installs every account-free dependency — the base tier plus the platform tier the full mise run check needs — and starts no model or platform service.

Choose the smallest check that honestly settles what you changed:

MomentCommandWhat it decides
While editing Gomodule-local mise run check and mise run testFormatting, lint, race-tested behavior, measured coverage
While editing docsmise run check:docs and mise run check:linksPage contracts, the rendered site, and local links
Before pushingmise run check:core and mise run testThe whole deterministic repository
Maintainer validationmise run install:platform, then mise run checkCore plus the infrastructure, licence, and security profiles, which need the platform tier
Release candidateconfigured eval:* and platform smoke tasksModel and runtime behavior tied to one source commit

Report a measured percentage next to the floor it cleared, and remember that neither number says the tested behavior is right — 0.2. Evidence owns that distinction.

Run git status --short before you start and after you finish. A dirty worktree you did not create is someone else’s work, and a repository-wide mise run format or git restore will overwrite it — scope both to what you own.

Your turn: break the ordered-list rule and read the failure

The ordered-list rule below is subtler than a missing path, and enforced just as literally.

Predict first: this course’s Markdown style requires every ordered-list item to be written 1., so the numbering stays dynamic when the list is edited. If you write 2. instead, does the checker ignore it, reformat it, or refuse?

  • Mode: temporary experiment.
  • Goal: watch the checker name a file, a line, and the exact rule, then restore the page and watch it go quiet.
  • Files to touch: only this page. The Go modules, the seed data, and your .env are untouched.
  • Preflight: confirm the page is unmodified with git diff --quiet -- "content/1. Setup/1.5. Workspace.md", which is silent and exits zero when it is clean.
  • Steps: from the repository root, append a bogus list item with printf '\n2. A renumbered list item.\n' >> "content/1. Setup/1.5. Workspace.md", then run tools/bin/conventions docs and read the failure.
  • Gate that proves completion: the checker exits non-zero and names the file, the line, and the rule:
content/1. Setup/1.5. Workspace.md: line 105: ordered Markdown items must use `1.`, not `2.`
  • Final state: restore the page with git restore -- "content/1. Setup/1.5. Workspace.md", then run tools/bin/conventions docs again and confirm it prints nothing and exits zero.

The rule is minor. Where it lives is not: it is a Go test in tools/internal/conventions, so a documentation contract fails the build the way a compiler error does. When Chapter 4 asks you to add a rule of your own, that is the seam you will extend.

What you can do now

  • You can say why a 2. list item fails tools/bin/conventions docs, and read the file, line, and rule from one message.
  • You can say which files are authority, which are disposable records, and why a .restore-* journal is neither.
  • You can pick the smallest check that honestly settles the change in front of you, and name what each one leaves open.
  • git status --short shows only changes you meant to make.

“The repository is clean” is now a checkable claim rather than a feeling: a checker that reads your prose against the code, a hook that runs the tasks you run, and a coverage floor reported per package rather than behind a total.

Continue to 2. Agents, where you assemble and run the one agent object every later chapter extends, on a model running on your own hardware.