Assay is one store. Labelling is not always in scope.
ModeWhat Assay isLabelling
Corpus (mode: "corpus")Track a person or a business using AI to buildCore. assay labelling on.
Observability (mode: "observability")Meter + transcripts on an agent loopOptional. assay sweep on without labelling.
assay init writes mode: "corpus" and both switches off.

The two switches

SwitchCommandWhat it does
Captureassay sweep on / offFile-log ingest on a 30-minute timer
Labellingassay labelling on / offPlace unplaced sittings using their AI
labelling on does not require sweep on (an embedded or OTLP host already fills the store). Both off unloads the timer. on is the consent moment. It records the harness binary it found. It copies enough environment into the timer so the job sees the same AI you do. For Claude Code it also merges a Stop hook: assay labelling session-end. off reverses config, copied skill files, the timer, and that marked hook. Overlays already written stay.

Do not buy a second model

The runner uses the AI they already pay for:
  1. A coding-harness CLI on PATH with print mode, or
  2. labelling.api in the config (url, model, and the name of an env var for the key — never the secret itself).
No driver → on refuses and writes nothing. Assay owns: the tree, the type vocabulary, the write door, rank (declared > judge > heuristic), retrieve-by-write, the timer. The model returns JSON. Assay parses and writes through the same door as assay declare.

Reliability path

Clean exit: assay labelling session-end [--session <id>].
  1. Retrieve-only objective placement. No judge.
  2. If that sitting is still unplaced, run the labeler for that sitting only.
  3. No session id → retrieve only. Do not guess the newest sitting.
  4. Always exits 0 so the host sitting never fails.
Backup: the sweep timer (see Capture). The portable skill is still copied into detected harness dirs so a same-sitting declare can happen as a byproduct. It is not what makes on true. Session-end does not capture. Sweep still does.

What you do by hand

assay unplaced                 # sittings still missing an objective
assay labelling run            # batch of unplaced sittings
assay declare --type build:feature --session <id>
assay declare --objective <node> --session <id>
On the session page in the console, click the type value and type. Enter saves. Escape abandons. That write is source=user and outranks later guesses. A sitting that changed job needs episodes, not one label. A sitting that also touched another product needs a touch, not a split. See Framing. Proposed nodes from a judge wait for accept. Do not treat a proposal as an accepted root.

Observability

Labelling is optional. assay sweep on captures without it. A local --judge stays behind the sovereignty gate. Do not treat that pass as corpus quality.