-
Notifications
You must be signed in to change notification settings - Fork 1
agentm opinion registry
title: opinion registry — design status: launched kind: design scope: feature area: agentm/opinion-registry governs: [] parent: agentm-hld.md seeded: 2026-06-26 approved: 2026-06-26
The opinion registry is the thin resolver that makes agentm's opinions addressable by name: a tool or persona asks for
goodordone, and the registry folds the coded base with the learned supplement and serves one composite over the seams agentm already has. Implements the compose-and-serve[PENDING-IMPL]in opinions; parent agentm HLD.
An opinion is a standard agentm holds for how to work — what done, good, recoverable, or ready mean. The opinions design says a tool should be able to ask for one by name and get back the coded base folded with everything the agent has learned since. That request-by-name path is the one piece the opinions design leaves as [PENDING-IMPL]. This design specifies it.
Today each opinion is hardwired into its tool — code-review carries its own copy of good, the check battery carries done — so no tool can ask agentm for the standard; it carries a private copy. The registry closes that gap. It is the resolver that scans the opinion entries, resolves a name to its composed standard, and serves it, so the standard is defined once and every caller asks for it. It is a dependency leader: the per-capability opinion wirings and the persona roster's "Leans on" column both resolve through it.
The registry adds one resolver. Opinions live in two layers agentm already has — a coded base checked into the repo and a learned supplement in the memory backend — and the resolver folds them on request, the same base⊕overlay fold the style system already uses. The build roadmap names this the registry; what it adds is the resolve-by-name path over those existing seams (the opinions design's reuse-the-seams intent, made concrete).
A consumer asks by name; the resolver folds the coded base (in-repo) with the learned supplement (memory backend) and serves one composite. It rides the one-way capability bridge: crickets depends on agentm in a single direction.
The registry is a resolver in agentm, built to mirror the two that already do this job for other markdown data: capability_resolver.py (the one-way capability bridge) and governs_resolver.py (resolve a target to its governing design by scanning wiki/designs/ frontmatter as data). The opinion resolver copies that template closely — it reads markdown as data, never imports it, and never raises.
The resolver exposes two functions, with a thin CLI shim over them:
opinion_resolve(name, *, root=None) -> dict # rich form → {served, name, base_present, supplement_present, reason}
opinion_available(name) -> bool # boolean surface (mirrors capability_available)scripts/agentm-opinion.sh wraps opinion_resolver.py (exit 0 served · 1 unavailable · 2 usage), mirroring agentm-capability.sh and agentm-governs.sh.
Crickets reaches the resolver through a thin bridge that mirrors the crickets-side find_capability.py (in developer-workflows) — path-fallback discovery, graceful-skip when agentm is absent. The direction is one-way: crickets depends on agentm in a single direction.
No opinion schema exists today, so this design defines the first one. Each opinion is a markdown file with YAML frontmatter, read as data exactly as governs_resolver reads a design's frontmatter:
---
name: good # the canonical request-by-name key
kind: opinion # the primitive kind (mirrors kind: design / kind: persona)
question: "does it survive a hostile read?" # the one-line standard the surface answers
serves: [code-review, "/review"] # consumers, advisory — for discovery, not resolution
implements: crickets/code-review # pointer to the built artifact carrying the standard today
composes: [] # optional — sub-providers folded into the served composite
---
The standard prose — the coded base of the opinion.The served composite is the base body ⊕ the learned supplement, folded by the same mechanism crickets' style_resolver.py (in wiki-maintenance's diataxis-author) already uses for the prose-style base⊕overlay. Two storage layers:
-
The coded base ships as
opinions/<name>.mdin the agentm repo — the durable seed, the same for every install, changed only by a check-in. -
The learned supplement lives in the memory backend through the storage seam — an
opinions/area beside the always-load conventions, written by Experience over time. The resolver reads it; it never writes it.
Opinion content does not live in the kernel config. The resolver reads markdown-as-data, the way governs_resolver does; the config plane stays out of the content path.
The names the resolver serves — the catalog the opinions pillar owns. The set is open; voice stays in the style_resolver sibling (a prose-style overlay).
| Opinion | is it…? | where the standard lives today |
|---|---|---|
| done | finished? | the check battery + the written conventions |
| good | survives a hostile read? | the adversarial-review contract (code-review) |
| efficient | as cheap as the job allows, above the good floor? | opusplan + heat_policy.py + the model×effort tier scale |
| how-we-engineer | the way we work? | the phase discipline + the bugfix track + the sizing ladder |
| recoverable | able to be undone? | the recoverability doctrine (developer-safety) |
| private | safe to commit / share? | the deterministic leak-floor (privacy) |
| ready | ready to ship to real users? | the launch-readiness gate (/launch) |
| simple | the simplest thing that works? | Chesterton's Fence + the Rule of 500 (/simplify) |
| worth-knowing | worth remembering / surfacing? | the relevance bar (research + Experience) |
recoverable, private, ready, and simple have a standard a capability already holds; worth-knowing is the relevance bar the Researcher persona leans on. Each is addressable by name once it has an entry.
build_index(root) scans opinions/*.md frontmatter into a name → OpinionEntry map (at most one base entry per name), reading and never importing. opinion_resolve(name) returns the composite plus a reason, fail-safe and never raising, in the resolver style (the governs_resolver pattern):
| Reason | Meaning |
|---|---|
served |
base present; supplement folded in if any |
base-only |
base present, no supplement yet (a bare install) |
no-opinion |
unknown name |
error |
the scan collapsed; degrade, don't crash |
Three invariants hold at the resolver boundary (the operator's ruling on the opinion-system invariants):
- The coded base is always recoverable and the supplement is fully discardable — the supplement extends the base, it never overwrites it, and the agent never rewrites the coded base.
- Opinion changes are revertable, unified with the revert-log the memory system already needs for its curated tier.
- The resolver surfaces served-with-supplement vs base-only, so a caller can tell a seasoned standard from a bare one.
Versioning is always-latest, no pin. A caller gets the current standard; reproducibility comes from recording the supplement revision in /review output. A missing name returns no-opinion and never raises — a soft consumer degrades to quiet absence; a hard consumer's gate is the layer that decides whether absence is fatal (below).
Opinions bind through the axes that already exist:
-
A persona declares the surfaces it leans on in its manifest
opinions:field — the rendered form is the roster's "Leans on" column. The registry is what that field resolves through; the binding resolves at persona-adoption time, riding the persona activation plumbing — which personas calls its unbuilt core, so this binding is co-blocked with that plumbing rather than riding an existing seam. This mirrors thetier:axis (itself designed-not-built): the persona declares the binding, the opinions pillar owns the surface, one-way. The registry is addressable by name through its CLI and the composition edges before persona-adoption resolution exists. -
A capability or a single skill binds through the composition
requires:/enhances:edges reaching up to an opinion.requires: opinionis hard — a gate needs the standard to run at all (e.g./review's gate needs what good looks like); the resolver returningbase-only/no-opinionis what that gate raises on.enhances: opinionis soft — the tool works without it and does more when it's present; absence is a quiet graceful-degrade.
The resolver supports sub-capability granularity: the caller can be a whole capability or a single primitive. privacy is the worked case — the capability provides the private standard (its deterministic leak-floor), while its privacy-review skill is the named sub-caller that consumes good.
A representative slice of the consumer set (the full map is the composition design + the persona roster):
| Caller | Asks for | Strength |
|---|---|---|
code-review / /review
|
good | requires (the gate needs it) |
development-lifecycle (/work, /release) |
done · recoverable | requires |
development-lifecycle (/plan, /bugfix) |
how-we-engineer | enhances |
development-lifecycle finalize · CI |
private | requires |
/launch |
ready | requires |
/simplify |
simple | requires |
design |
how-we-engineer · good | enhances |
research · Researcher persona |
worth-knowing | enhances |
token-audit |
efficient | enhances |
| Persona — Tech-Lead | done · good | adoption-time |
| Persona — Engineer | done · efficient | adoption-time |
| Persona — Reviewer | good | adoption-time |
efficient is compound — the resolver assembles it from sub-providers via the entry's composes: field. It returns a cost budget with a quality floor: its model-routing lever is the model + effort routing tier scale and the measurement half comes from token-audit, so efficient composes: those two sub-payloads into the served composite.
Some opinions are provided by a capability that holds the standard. recoverable's standard lives in developer-safety's recoverability doctrine; private's deterministic leak-floor lives in privacy; ready's readiness gate lives in /launch; simple's lives in /simplify. The capability is the opinion's implements: artifact; the opinion makes that standard addressable by name to every other caller.
Surfaces that consume no opinion, each for its own reason (the honesty lint expects no binding from them): reporting (reports, doesn't judge — it follows the voice convention), github-projects (mirrors state), obsidian-vault (infrastructure below the substrate), conventions (the inverse — opinions cite it). developer-safety and privacy are providers of recoverable/private, not consumers.
The registry is kept honest by three gates that copy the capability-resolver pattern, plus a dedicated resolver test:
-
check-opinion-resolver-one-way.py(wired intocheck-all.sh) — an AST gate that fails ifopinion_resolver.pyusesimport_module/__import__/exec/evalor imports non-stdlib outside a reviewed sibling allowlist. The resolver discovers opinions; it never runs them. -
Update
check-capability-naming.py— its reservedOPINION_NAMESset is drifted (it reserves{efficiency, quality, good, done}while the canonical surfaces are the nine-opinion catalog). Reconcile it to the catalog names so no capability can shadow an opinion and the one-way capability→opinion rule stays whole. -
An honesty lint — every consumer-declared opinion name (a persona
opinions:entry, a capabilityrequires:/enhances:opinion target) must resolve to a realopinions/entry. No orphan opinion references.
Plus test_opinion_resolver.py, copying test_governs_resolver.py (served / base-only / no-opinion / error, never-raise).
-
vs the capability resolver — that resolves a capability to its provider (one provider, a hard
CapabilityMismatchErroron the consumer side). The opinion resolver resolves a name to a composed standard (base⊕supplement fold, soft never-raise). It rides the capability bridge but is its own resolver, the waygoverns_resolveris. -
vs the persona tier — the
tier:axis is the structural precedent (manifest-declared, policy-owned, adoption-applied, one-way); opinions reuse the same manifest + validator + adoption pattern, bound to standards instead of model-effort. -
vs model + effort routing — that is a sub-provider folded into
efficient's composite. - vs the gate model — the registry serves the standard; enforcement stays with done's deterministic check battery and good's adversarial pass. The registry makes those addressable by name. Opinions carry no advisory/enforced state machine — that knob belongs to the experience design.
-
rides the one-way capability bridge — crickets'
find_capability.py→ agentm'scapability_resolver.py; the opinion lookup rides the same path crickets already uses to reach agentm. -
rides the style base⊕overlay fold — crickets'
style_resolver.py(wiki-maintenance) is the compose precedent for base ⊕ supplement. -
rides the memory engine — the learned supplement is a memory entry in the
opinions/area, through the storage seam (memory system). -
binds through the persona
opinions:manifest axis (personas) and the compositionrequires:/enhances:edges (composition). -
efficientcomposes model + effort routing (the tier scale — itself[PENDING-IMPL]) andtoken-audit(the measurement). -
implements the
[PENDING-IMPL]in the opinions pillar; points up at the agentm HLD §Opinions.
-
Addressable before fully-extracted. Ship
opinions/<name>.mdas thin stubs first — frontmatter + animplements:pointer to the artifact that carries the standard today (done→check-all.sh+CI-Gates.md,good→code-review) + a short body — then deepen the bodies. This makes opinions addressable-by-name immediately, unblocking the per-capability wirings, without a risky one-shot extraction of every hardwired standard. -
The wirings flip as they consume. Each consumer moves from a private hardwired copy to
opinion_resolve(name)when its slice builds (the launched consumer designs call thisopinion_request— the same operation); the present-tense "compose with opinions" prose in the consumer designs is reconciled to as-built at the same time. -
At lift (docs): expand the opinions pillar's "opinions today" table to the nine-opinion catalog (its canonical home); add the
agentm/opinion-registryarea to the area taxonomy; repoint the pillar's "that code is what this design will govern once built" line to name this design as the governor ofopinion_resolver.py(the pillar stays discipline/area-only, the registry governs the code). -
At build: fix the drifted
OPINION_NAMESguard (a crickets code change), reserving all nine names; then buildopinion_resolver.py+agentm-opinion.sh+ the gates + the stub entries.
- Buildability illusion. The registry sits under the github-projects ≥4-deep dependency stack (board-depth → Planner → persona activation → this registry); dependents read "designed" while leaning on it. As it builds, downgrade dependents' status language from "designed" to "blocked on the registry" until it exists.
-
Compound
efficientis partly blocked. Its full composite needs the model-effort-routing tier scale, which is itself[PENDING-IMPL]. Until that ships,efficientserves base + thetoken-auditmeasurement only; the routing lever folds in when its peer leader lands. - Schema-first risk. This is the first opinion schema; getting a field wrong forces a migration across every wiring later. The stub-first migration limits the blast radius.
-
The consumer syntax co-evolves. The persona-side
opinions:manifest field is itself[PENDING-IMPL], so the declaration grammar the resolver reads is not fully locked — co-design the manifest field and the resolver together. -
Re-audit triggers: flip the parent opinions design's request-by-name
[PENDING-IMPL]to as-built when this ships; fold the model-routing lever intoefficientwhen the tier scale lands; revisit the name-space when a new surface is authored (the catalog stands at nine).
-
Soft resolver, hard at the gate.
opinion_resolvealways returns a reason and never raises (thegoverns_resolverstyle). Fail-loud is pushed up to the hardrequires:consumer's gate, which raises if its required opinion came back base-absent. A bare install and a seasoned one are served the same way. -
Always-latest, no pin. Reproducibility comes from recording the supplement revision in
/reviewoutput (operator ruling). - Invariants committed at the boundary now, even though both the supplement writer (the Experience loop) and the revert-log primitive it unifies with are unbuilt: base always recoverable, supplement fully discardable, opinion changes revertable (operator ruling). The registry only reads the supplement, so it is unaffected; the revertability invariant becomes enforceable when the memory-system revert-log lands.
- The registry serves; gates enforce. No advisory/enforced state machine for opinions.
- The sharpening loop is out of scope — it is the Experience → Opinions loop (operator ruling); this design only specifies that the supplement is a memory entry the resolver folds, not how it gets written.
-
The coded base ships as thin stubs first (operator ruling) — each
opinions/<name>.mdstarts as frontmatter + animplements:pointer + a short body, deepened later, so opinions are addressable by name without a one-shot extraction. -
The name-space is the nine-opinion catalog (operator ruling, 2026-06-26) — the original four plus recoverable, private, ready, simple, and worth-knowing (see the catalog table). voice stays in the built
style_resolversibling (a prose-style overlay, not a behavioral opinion). The set stays open — a new surface needs an authored entry. -
worth-knowingis a first-class opinion (operator ruling, 2026-06-26) — the relevance bar the Researcher persona leans on, lifted from a roster-only surface into the catalog (this reverses the earlier "normalize as drift" call).recoverableandprivateare likewise promoted from folded sub-standards into peer opinions; their standards stay provided bydeveloper-safety/privacy.
-
The resolver precedents to copy: agentm
scripts/governs_resolver.py+test_governs_resolver.py(markdown-data resolve-by-name, never-raise) · agentmscripts/capability_resolver.pywith crickets'find_capability.py(the one-way bridge) · cricketsstyle_resolver.py(wiki-maintenance / diataxis-author — the base⊕overlay fold) · agentmscripts/capability_version_match.py(graceful-degrade matching) -
The guard to reconcile: crickets
scripts/check-capability-naming.py(the reservedOPINION_NAMESset) -
The coded bases today:
AGENTS.md+harness/principles.md·scripts/check-all.sh+wiki/reference/CI-Gates.md(done) · cricketscode-review(good) ·harness/skills/memory/scripts/heat_policy.py+ opusplan (efficient levers) ·development-lifecycle(how we engineer) -
Up: opinions pillar (the
[PENDING-IMPL]this implements) · agentm HLD §Opinions - Consumers: composition (the capability wiring) · personas (the "Leans on" column)
- design-doc Forward plan — the Opinion slice (Phase 3 → 4), the migration this realizes
Newest first. Collapses to one ≤2-paragraph entry at finalization; git holds the granular history.
-
2026-06-26 — authored, reviewed, and finalized. The Bucket-A substrate sub-design specifying the request-by-name registry the opinions pillar leaves as
[PENDING-IMPL]— a dependency-leader that gates the per-capability opinion wirings and the persona roster's "Leans on" column. The registry is a resolver in agentm (opinion_resolver.py+agentm-opinion.sh) built to mirror the existinggoverns_resolver.py: it scansopinions/<name>.mdentries as data, resolves a name to the base ⊕ learned-supplement composite (via thestyle_resolverfold), reasonsserved/base-only/no-opinion/error, and never raises; crickets reaches it one-way through the capability bridge. It defines the first opinion-entry schema and binds through the existing personaopinions:axis + compositionrequires:/enhances:edges, kept honest by an AST one-way gate + the reconciled naming guard + an orphan-reference lint.Operator calls: soft resolver / hard at the gate; always-latest no-pin; invariants at the boundary; registry serves, gates enforce; sharpening loop out of scope; coded base ships thin-stubs-first. The catalog expands to nine — done · good · efficient · how-we-engineer · recoverable · private · ready · simple · worth-knowing — with
recoverable/privatepromoted from folded sub-standards to peer opinions provided bydeveloper-safety/privacy, andvoicekept in thestyle_resolversibling. Re-audit: flip the parent[PENDING-IMPL]at ship; fold the routing lever intoefficientwhen the tier scale lands; revisit the name-space when a new surface is authored.