assay  ·  getting started

Install

Two ways in, and one of them does the work for you. If you drive with Claude Code, add the Assay plugin and run one skill — assay:install — and it scaffolds the board, pins and hash-verifies statusgen, wires CI, and proves the install, stopping only where a human must decide. If you don't, the manual path below stands up the same thing by hand from the pinned release binary in the public medici-finance/assay repository. Same destination; the turnkey path just gets you there without transcription errors.


With Claude Code — the turnkey path recommended

Assay ships as a Claude Code plugin, and the plugin carries an installer skill. You add the marketplace, install the plugin, and invoke assay:install; the skill does the rest — it detects the repo, scaffolds the streams tree, acquires the version-pinned statusgen binary and checks its sha256, wires the CI workflow, and proves the result. It is the same runbook the manual path walks, executed instead of transcribed.

Prerequisites. Claude Code installed and running in the repo you want to adopt; the GitHub CLI (gh) installed and authenticated (the skill downloads the pinned release with it); and a macOS or Linux host. Windows is a named fast-follow — the binary-acquisition step is not implemented for it yet, and on a Windows host the skill says so and stops rather than guessing.

Three commands. Add the plugin marketplace from the public repository, install the assay plugin from it, then invoke the installer skill:

# in Claude Code, inside the repo you're adopting
/plugin marketplace add medici-finance/assay
/plugin install assay@assay
# then invoke the installer skill — or just ask: "install Assay here"
assay:install

What assay:install does, in order — and what it refuses:

  • Confirms the target before writing anything: it names the absolute repo path and the detected platform back to you, and will not scaffold a repo it only inferred.
  • Scaffolds with statusgen init rather than hand-rolling a second copy of the tree — the streams directory, the three registers, and a bootstrap-safe CI workflow.
  • Pins and verifies statusgen. It resolves the statusgen release paired with the plugin version (never latest, never “the newest release”), writes the channel-E line into .assay-versions, downloads the asset, and refuses on a hash mismatch. A pinned sha256 is the one thing a re-tagged release cannot silently swap.
  • Wires CI and the optional main-guard, confirming the two-half workflow is present and correct rather than authoring a competing copy.
  • Proves the install. It is not done until statusgen --root . --lint exits 0 and statusgen --version prints the pinned tag. If either fails, the skill says the install is not proven and stops — no fabricated success.
  • Idempotent, and it refuses to clobber. Re-invoking is safe: an already-adopted repo is reported and left untouched (a first-class outcome, not an error); a partially-installed one advances only the unmet steps.

The skill authors branches and opens draft PRs only. It never merges. By design it stops and hands you the exact values at every step that must stay a human decision — among them private-repo CI auth, creating and installing the reviewer GitHub App (the identity that posts approvals, which a worker session cannot stand in for), and any merge, push, tag, or first ready-flip on main. It hands you the values and waits; it does not fabricate the outcome.


Manual — without Claude Code

No Claude Code, or you want to run each step yourself? Everything below stands up the same install by hand. This is the ground the turnkey skill covers for you; it is also the authoritative reference for what that skill does. There is one supported acquisition channel — the pinned release binary — and it is described here.

Take the binary, not the source

statusgen is the single writer of your STATUS.md board — a repo-agnostic Go tool with no product knowledge. The obvious way to adopt a small self-contained tool is to copy its directory into your repository. That recommendation has been retired. A vendored copy is a fork, and forks rot in silence: a copied generator, frozen at the commit where it landed, still green and still gating another repository's pull requests weeks later while missing every check added upstream since. A gate that has quietly stopped checking what it is believed to check is worse than no gate.

So the supported path is a pinned release binary, verified by sha256. A one-line-per-platform pin file names the release tag and the expected hash; installation downloads the asset, checks its digest, and refuses on a mismatch; upgrading is a one-line change reviewed like any other. One binary, one pin, one place to bump — and drift becomes a diff instead of a silence.

Everything else is the standard adoption runbook; this page is the getting-started slice of it. The authority is docs/adopting-assay.md in the public repository, written as a step-by-step runbook a coding agent can execute.


Pin the release

Commit a .assay-versions file at your repository root with one line per platform you install on, in the form statusgen-<platform> <tag> <sha256>. The current release is v0.9.1. Its published assets and digests:

Table statusgen v0.9.1 · release assets
PlatformAsset namesha256
macOS Apple silicon statusgen-darwin-arm64 f2203ea531ac5ea26bf84cfe36c4ca2baaa26c16fb4cea8b0c163fbd17466fc7
macOS Intel statusgen-darwin-amd64 50e34b63b540ff107251cb28f8be1e4ccd697c615162550878935aad40a0e046
Linux x86-64 statusgen-linux-amd64 6d2e95f1d33203b7dc6016f7cc68e2fd4afeebac99eb9e95a35e73cc0d7659ac

The pin file, carrying only the platforms you actually run on:

# .assay-versions
statusgen-darwin-arm64 v0.9.1 f2203ea531ac5ea26bf84cfe36c4ca2baaa26c16fb4cea8b0c163fbd17466fc7
statusgen-darwin-amd64 v0.9.1 50e34b63b540ff107251cb28f8be1e4ccd697c615162550878935aad40a0e046
statusgen-linux-amd64  v0.9.1 6d2e95f1d33203b7dc6016f7cc68e2fd4afeebac99eb9e95a35e73cc0d7659ac

Four rules carry their weight, and each has burned someone who skipped it: pin the full platform — operating system and architecture, never the family, or a darwin-amd64-only file quietly passes on an Apple-silicon host; refuse rather than guess when the line for the detected platform is absent; re-pin, never edit in place on an upgrade, so the bump shows up in a diff and gets reviewed; and keep each pinned asset name distinct from any CI job name.


Install and verify

Detect the platform, read the pinned line, download the asset, and compare the digest before installing. Refuse on a missing line and refuse on a hash mismatch — the check is the point, not decoration.

$ plat="$(uname -s | tr A-Z a-z)-$(uname -m | sed 's/^x86_64$/amd64/; s/^aarch64$/arm64/')"
$ grep "^statusgen-$plat " .assay-versions   # refuse if absent
statusgen-darwin-arm64 v0.9.1 f2203ea531ac5ea26bf84cfe36c4ca2baaa26c16fb4cea8b0c163fbd17466fc7

$ read -r _ tag want < <(grep "^statusgen-$plat " .assay-versions)
$ gh release download "$tag" --repo medici-finance/assay --pattern "statusgen-$plat"
$ got="$(shasum -a 256 "statusgen-$plat" | cut -d' ' -f1)"
$ [ "$got" = "$want" ] || { echo "sha256 mismatch — refusing"; exit 1; }
sha256 verified — statusgen-darwin-arm64
$ install -m 0755 "statusgen-$plat" /usr/local/bin/statusgen

Then prove the install is what the pin claims, and prove the hash check is live rather than ceremonial:

$ statusgen --version
statusgen v0.9.1
$ # re-run the install against a deliberately corrupted digest
sha256 mismatch — refusing

Stand up the board

With the binary on PATH, the rest of the day-one install is scaffolding the sources statusgen reads. The adopter scaffold in the public repository is a populated, read-only worked example — copy its shape, do not vendor it:

  • Streams. Create docs/streams/<stream>/README.md with the required frontmatter and brief table, and author the first brief by copying docs/brief-template.md. Fill every frontmatter field — an empty sources: or a missing risk: answer is a gap, not a shortcut. The review gate is derived (any risk: yes makes it human), never chosen.
  • Registers. Create the three append-only logs docs/streams/FINDINGS.md, INTAKE.md, and RETRO.md (formats in docs/registers.md). Numbering is gap-free; withdraw an entry with a tombstone, never by deleting a heading.
  • CI. Author a two-half workflow at .github/workflows/statusgen.yml — this is house-specific and is not shipped in the bundle. The pull-request half runs statusgen --lint only and blocks any diff that touches STATUS.md; the push-to-main half regenerates and commits the board. Only that one job ever writes the file.

The first board is the proof that the sources are well-formed:

$ statusgen --root . --lint
LINT: OK — 1 stream, 1 brief, 3 registers, no problems
$ statusgen --root .   # writes STATUS.md locally; the main-side CI job commits it

--lint is what pull-request CI runs — it builds the view internally but never reads or writes STATUS.md, so the board has exactly one writer and drift between sources and status stays visible. See statusgen for the full behaviour and the lifecycle for what the status cells mean.


Create the desk identities

Each desk role posts under its own GitHub App — eight Apps in all, so that a review or a verification is attributed to an identity the author cannot post as. GitHub has no API for creating an App, but it accepts a pre-filled manifest, and the GitHub Apps page carries one per role: a click on each, your review on GitHub's page, and the key comes back to your own terminal. The manual permission table is on the same page for anyone who wants every toggle in view.


The reading order

The golden path for someone standing this up for real, each document in the public repository:

  1. README — what Assay is and the component inventory, in one screen.
  2. docs/adopting-assay.md — the install runbook. It defines the named primitives once and composes them across three scenarios: green-field, an existing suite, and carving a unit out of a larger project.
  3. docs/brief-template.md and docs/brief-rules.md — the unit of work: scope, typed dependencies, the risk-derived gate, and a Verify table that can actually run. See also Briefs.
  4. docs/lifecycle.md — the states a brief moves through, and why verified is a distinct step a non-implementer runs.
  5. docs/registers.md — the append-only logs and their contiguity and tombstone rules.
  6. examples/adopter-scaffold — the worked shape to copy from.