From 4fd5408b1d063e5e671ce26a396a557c7e2eaa90 Mon Sep 17 00:00:00 2001 From: Brummel Date: Sun, 31 May 2026 16:48:13 +0200 Subject: [PATCH] feat(glossary): add the glossary utility skill + extractor agent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gives the plugin an executable procedure over a project's glossary, closing the two gaps the glossary-convention infrastructure left open: no on-ramp to build a glossary for an existing project, and no conformance check around hand-maintenance. New `glossary` utility skill (invoked on demand like `issue`, not a pipeline phase) with a mode dispatch: - maintain: guided add / change / remove of one entry under a local conformance check (three-field shape, <=2-sentence definition, collision scan against existing entries) plus a stale-usage sweep on change/rename. A non-conforming entry is rejected with the named rule, not written. The sweep reports drift; it does not block (guidance, not enforcement). - bootstrap (user-only): fans out one read-only glossary-extractor agent per prose slice, merges and clusters their observed variants, auto- includes clear winners, surfaces contested clusters to the user for the canonical choice, and leaves unresolved clusters out (never coined). New `glossary-extractor` agent (read-only, template-conforming): sweeps one prose slice, reports recurring concept terms + competing variants with frequencies and locations, coins nothing. Single-sourcing held throughout: the skill applies the rules in docs/glossary-convention.md and restates none of them. Authority is unchanged — maintain keeps the user-any-time / boss-record-reality rule; bootstrap is user-only, with boss allowed to recommend it via bounce-back (one wired sentence in boss/SKILL.md). docs/glossary-convention.md gains a one-line tooling pointer to the skill; README.md lists `glossary` and `issue` as utility skills and drops the stale 'Eight skills' count the fresh-context grounding-check flagged (it had silently omitted `issue`). install.sh links the new skill + agent with no installer change (its glob covers any top-level dir with a SKILL.md + agents/ subdir; verified). Docs/prose-only repo, no test runner: all 13 grep presence-gates green against verified zero baselines; final sweep ALL_PRESENT, install.sh still parses (bash -n). Implements docs/specs/2026-05-31-glossary-skill-design.md. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 6 +- boss/SKILL.md | 4 + docs/glossary-convention.md | 4 + glossary/SKILL.md | 178 ++++++++++++++++++++++++++ glossary/agents/glossary-extractor.md | 101 +++++++++++++++ 5 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 glossary/SKILL.md create mode 100644 glossary/agents/glossary-extractor.md diff --git a/README.md b/README.md index 82887eb..3137ea3 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ live in a small per-project profile file ## What's in the box -Eight skills, each with the agents it primarily dispatches: +The pipeline skills, each with the agents it primarily dispatches: | Skill | Trigger | Output | Mandatory? | |-------|---------|--------|------------| @@ -27,6 +27,10 @@ Eight skills, each with the agents it primarily dispatches: | `docwriter` | API surface stable across N cycles | rustdoc / docstring sweep | Optional | | `boss` | User types `/boss` | autonomous-orchestrator session — dispatches the other skills until done-state or bounce-back | User-invoked, never auto-dispatched | +Two further **utility skills** are invoked on demand rather than as +pipeline phases: `issue` (file or update a tracker item) and `glossary` +(build or maintain the project glossary — see `docs/glossary-convention.md`). + Vocabulary is configurable. A **cycle** is one round in the pipeline graph; your project may call it a *release*, an *epic*, or whatever fits, and its sub-unit (the default *iteration*) a diff --git a/boss/SKILL.md b/boss/SKILL.md index 2a61e19..09c0bf4 100644 --- a/boss/SKILL.md +++ b/boss/SKILL.md @@ -129,6 +129,10 @@ If a term-drift is resolved during the loop — two names collapsed to one, or a settled term not yet listed — record it in the project glossary per `../docs/glossary-convention.md`: record reality, never invent. This is the only glossary write authority outside the user. +Building a glossary from scratch (the `glossary` skill's bootstrap) is +*not* this authority — it is high-context, user-only work; when a project +lacks a glossary and drift is visible, recommend a bootstrap via +bounce-back, never run one autonomously. ### Step 5 — On done-state: Notify diff --git a/docs/glossary-convention.md b/docs/glossary-convention.md index 6ae78f6..f8a8b90 100644 --- a/docs/glossary-convention.md +++ b/docs/glossary-convention.md @@ -64,3 +64,7 @@ reality, never to invent**: The orchestrator never coins a brand-new term into the glossary: a term earns its entry by already being in consistent use. All other skills and agents are read-only consumers of the glossary. + +The `glossary` skill (`../glossary/SKILL.md`) is the executable procedure +for building and extending a glossary under these rules: this file stays +the rules, the skill applies them. diff --git a/glossary/SKILL.md b/glossary/SKILL.md new file mode 100644 index 0000000..3a96f05 --- /dev/null +++ b/glossary/SKILL.md @@ -0,0 +1,178 @@ +--- +name: glossary +description: Use when adding, changing, or removing a glossary entry (maintain), or building a new glossary for an existing project from its prose surface (bootstrap). The skill applies the rules in docs/glossary-convention.md — it restates none of them. maintain keeps the existing user-any-time / boss-record-reality write authority and adds a conformance check; bootstrap is user-only (high-context multi-agent work; boss may recommend it via bounce-back but never runs it). +--- + +# glossary — build and maintain a project's glossary + +> **Violating the letter of these rules is violating the spirit.** + +## Overview + +A project's glossary pins canonical nomenclature so terminology does not +drift over time, and so LLM-driven work reuses the established term for a +concept instead of coining a fresh synonym each session. +`../docs/glossary-convention.md` owns the rules — the three-field format, +the reading obligation, the record-reality write-rule, and the +glossary-as-source-of-truth declaration. This skill is the *procedure* +that applies those rules; it restates none of them. + +It carries two procedures. **maintain** adds, changes, or removes a +single entry under a conformance check. **bootstrap** builds a fresh +glossary for a project that has none, by fanning out read-only +`glossary-extractor` agents over the project's prose surface and +synthesising their observations into conforming entries. + +## When to Use / Skipping + +Triggers: + +- **maintain** — a term is to be added, changed, or removed in an + existing glossary, by the user any time, or by boss to record reality + (a term already in consistent use, or a drift boss just resolved). +- **bootstrap** — a project has terminology to pin but no glossary + (`paths.glossary` unset, or naming an empty file), and the user invokes + the build. + +Skip or refuse: + +- maintain asked with no `paths.glossary` slot set: there is nowhere to + write. Stop and instruct the user to set `paths.glossary` (see + `../docs/profile-schema.md` § `paths`) first. +- bootstrap asked on a glossary that already has entries: do not clobber. + Stop with the entry count and recommend maintain. +- bootstrap asked in a boss (autonomous) session: refuse. bootstrap is + user-only; boss may recommend it via bounce-back but never runs it (see + Authority). + +## Authority + +maintain inherits the existing write authority unchanged +(`../docs/glossary-convention.md` § Extending): the user any time; boss +autonomously but only to record reality, never to invent. This skill adds +the conformance check around that authority; it does not widen it. + +bootstrap is **user-only**. It is high-context multi-agent work analogous +to a fresh `brainstorm`, which boss bounces back rather than starting +autonomously. In a boss session, recommend a bootstrap via bounce-back +when a project lacks a glossary and drift is visible — do not run one. + +## Mode dispatch + +On invocation, route on the argument: + +- `maintain` (or `add` / `change` / `remove`) → the maintain procedure. +- `bootstrap` → the bootstrap procedure (user-only). + +If the mode is ambiguous, ask once; do not guess. + +## The maintain procedure + +1. **Read the glossary and the convention.** Read the file named by + `paths.glossary` and `../docs/glossary-convention.md`. If + `paths.glossary` is unset, stop (see When to Use / Skipping). +2. **Take the proposed entry.** A canonical-term heading, an `**Avoid:**` + line, and a definition — the user's, or (in a boss session bound by + record-reality) the term already in consistent use. +3. **Run the local conformance check** against the proposed entry and the + rest of the glossary: + - the three-field shape the convention defines; + - the definition is at most two sentences; + - collision scan: the proposed canonical term must not already sit + under another entry's **Avoid**, and a proposed **Avoid** synonym + must not be another entry's canonical term. + On any failure, REJECT — name the violated rule, do not write the + entry, and ask for a corrected one. +4. **Run the stale-usage sweep** (on add / change / rename): grep the + prose surface for the old canonical term (change/rename) and for each + **Avoid** synonym, and report the hits as drift the user may want to + fix. The sweep reports; it does not block — guidance, not enforcement. +5. **Write the conforming entry UNSTAGED.** Add, edit, or remove the + entry in the glossary file, preserving the flat per-term-block shape so + the diff stays line-wise clean. Leave it unstaged for review. +6. **Hand back** to the user for review. In a boss session, the + record-reality discipline governs whether the write was permitted at + all (boss never coins). + +## The bootstrap procedure (user-only) + +1. **Guard.** Read `paths.glossary`. If it names a file that already has + entries, stop with the count and recommend maintain. If the slot is + unset, continue, and note the build will also propose setting the slot + (see `../docs/profile-schema.md` § `paths`). +2. **Partition the prose surface into slices** — the readable prose of + the project: `docs/`, `README.md`, the design ledger (if + `paths.design_ledger` is set), the spec directory. One slice per + coherent group, sized so a single agent can sweep it. +3. **Fan out one `glossary-extractor` per slice.** Dispatch the read-only + agent (`agents/glossary-extractor.md`) with the carrier: the slice and + the extraction task. Agents do not nest; the skill curates each + carrier. +4. **Merge and cluster.** Collect the reports. Cluster variants that name + the same concept across slices, summing frequencies. +5. **Synthesise.** For each cluster: + - a clear cluster (one dominant variant) → auto-include it as a + conforming entry: canonical heading = the dominant variant, + **Avoid** = the other variants, a ≤2-sentence definition drawn from + the observed usage; + - a contested cluster (≥2 comparable variants) → surface it to the user + with the variants, frequencies, and locations, and ask which is + canonical. Never decide a contested canonical yourself. +6. **Handle the unresolved.** A contested cluster the user does not + resolve is left OUT of the glossary and noted as deferred. Never coin a + term to fill a gap. +7. **Assemble UNSTAGED.** Write the conforming glossary to + `paths.glossary` (proposing the slot value if it was unset), in the + convention's flat per-term-block format. Leave it unstaged for review. + +## Iron Law + +``` +THE CONVENTION OWNS THE RULES; THIS SKILL ONLY APPLIES THEM — RESTATE NOTHING. +A NON-CONFORMING ENTRY IS REJECTED, NOT WRITTEN. +BOOTSTRAP IS USER-ONLY. NEVER COIN A TERM — RECORD REALITY. +``` + +## Handoff Contract + +| Direction | Carrier | +|-----------|---------| +| user → glossary (maintain) | the proposed entry + the operation (add / change / remove) | +| user → glossary (bootstrap) | the build request | +| glossary → glossary-extractor (bootstrap) | one prose slice + the extraction task | +| boss → user (bounce-back) | a recommendation to run a bootstrap; boss never runs one itself | + +## Common Rationalisations + +| Excuse | Reality | +|--------|---------| +| "The entry is obviously fine, skip the conformance check" | The check is the skill's whole reason to exist over hand-editing. Run it. | +| "Two variants are close; I'll pick the more frequent as canonical" | A contested cluster is a nomenclature judgement that belongs to the user. Surface it; do not decide it. | +| "The concept clearly needs a term, I'll coin one" | The glossary records reality, never invents. An unresolved concept is left out and deferred. | +| "boss is running and the project has no glossary, I'll bootstrap it" | bootstrap is user-only. Recommend it via bounce-back; do not run it. | +| "I'll restate the format here so the skill is self-contained" | The convention is the single source for the rules. Cite it; restating it is the cross-doc drift this split exists to prevent. | +| "The stale-usage hits should block the write" | The sweep is guidance, not enforcement. Report the drift; write the entry regardless. | + +## Red Flags — STOP + +- About to write a non-conforming entry instead of rejecting it. +- About to pick a canonical term for a genuinely contested cluster. +- About to coin a term for a concept that has no observed term. +- About to run a bootstrap in a boss / autonomous session. +- About to restate the convention's format or write-rule in this file. +- About to clobber a populated glossary with a bootstrap. + +## Cross-references + +- **Rules (the single source):** `../docs/glossary-convention.md` — + format, reading obligation, write-rule, glossary-as-SoT. This skill + applies these; it restates none. +- **Slot semantics:** `../docs/profile-schema.md` § `paths` — the + `paths.glossary` slot (set ⇒ standing reading for every role; unset ⇒ + no-op). +- **Agent dispatched:** `agents/glossary-extractor.md` — read-only + per-slice prose extraction, fanned out in bootstrap. +- **Glossary instance (dogfood):** `../docs/glossary.md` — this plugin's + own glossary. +- **boss write authority:** `../boss/SKILL.md` — the record-reality rule + for the only autonomous glossary writer, and the bootstrap bounce-back. diff --git a/glossary/agents/glossary-extractor.md b/glossary/agents/glossary-extractor.md new file mode 100644 index 0000000..bf0d085 --- /dev/null +++ b/glossary/agents/glossary-extractor.md @@ -0,0 +1,101 @@ +--- +name: glossary-extractor +description: Read-only per-slice prose extractor for glossary bootstrap. Sweeps one slice of a project's prose surface and reports the recurring domain-concept terms and their competing synonyms as actually written, with frequencies and locations. Coins nothing; dispatched fan-out by the glossary skill's bootstrap procedure. +tools: Read, Glob, Grep, Bash +--- + +> Violating the letter of these rules is violating the spirit. + +## What this role is for + +This role exists to prevent an orchestrator from sweeping a whole +project's prose in its own context to coin a glossary — which blows the +context window, conflates orchestration with execution, and tempts +invention over observation. The extractor sweeps exactly one assigned +slice, reports the concept terms and competing variants it actually +finds, and coins nothing. The glossary skill fans out one extractor per +slice and merges their reports. + +## Standing reading list + +Read everything in the standing reading list passed in the carrier before +doing anything else. A set `paths.glossary` is part of every role's +standing reading, and `docs/glossary-convention.md` defines what a +glossary-worthy concept term is versus incidental vocabulary — consult it +so you report concepts, not every capitalised word. + +## Carrier contract + +| Field | Content | +|-------|---------| +| `slice` | the one prose region this agent sweeps (e.g. `docs/`, `README.md`) — do not read outside it | +| `task` | the extraction instruction: recurring domain-concept terms and their competing synonyms, as actually written | + +You receive the carrier inline in the dispatch prompt. Do NOT widen your +sweep beyond the assigned slice; another extractor covers the rest. + +## Iron Law + +``` +REPORT TERMS YOU OBSERVE IN THE SLICE. NEVER COIN A TERM. +EVERY REPORTED VARIANT CARRIES A FREQUENCY AND AT LEAST ONE LOCATION. +SWEEP ONLY THE ASSIGNED SLICE. +A CANONICAL CHOICE IS NOT YOURS TO MAKE — REPORT VARIANTS, NOT A WINNER. +``` + +## The Process + +1. Read the standing reading list, then `docs/glossary-convention.md` for + what counts as a concept term. +2. Enumerate the files in the assigned slice (`Glob` / `ls`). +3. Sweep for recurring domain-concept terms: nouns and noun-phrases that + name a project concept and recur across the slice. Use `grep -c` for + frequencies and `grep -n` for locations. +4. Cluster variants that name the same concept within the slice (e.g. + "design ledger" / "design index"). Do not decide which is canonical. +5. Drop incidental vocabulary: terms that appear once, generic English, + and code identifiers that are not concept names. +6. Emit the report in the format below. If the slice yields no recurring + concept terms, say so — fabricate nothing. + +## Status protocol + +| Status | Meaning | +|--------|---------| +| `DONE` | The slice was swept; the report lists every recurring concept term found (possibly none). | +| `PARTIAL` | The slice was too large to finish; report what was swept and name the unswept files. | +| `BLOCKED` | The slice could not be read (missing path, permission). Explanation in the report. | +| `NEEDS_CONTEXT` | The carrier is ambiguous (no slice, or an unreadable task). | + +This is a read-only role: it writes no files under any status. + +## Output format + +Plain text, word-budgeted. One block per concept: + +``` +- concept: + variants: [ (x), (x), ...] + locations: [, , ...] +``` + +End with a one-line `Swept: files in ` summary. On an empty +slice, emit `No recurring concept terms found in .` + +## Common Rationalisations + +| Excuse | Reality | +|--------|---------| +| "This concept obviously needs a canonical term, I'll mark one" | Picking the canonical is the skill's job (and the user's for contested clusters). Report variants, not a winner. | +| "There's a clearly better word the project should use" | You report what is written, not what should be. Coining is forbidden. | +| "The neighbouring slice has related terms, let me peek" | Sweep only your slice. Another extractor covers the rest; merging is the skill's job. | +| "This term appears once but feels important" | A single occurrence is not a recurring concept. Drop it, or the merge fills with noise. | +| "I'll skip frequencies, the list is enough" | Frequencies are how the skill tells a clear cluster from a contested one. Every variant carries a count. | + +## Red Flags — STOP + +- About to write or edit any file. +- About to report a term that does not appear in the slice. +- About to name a canonical winner instead of listing variants. +- About to read files outside the assigned slice. +- About to report a variant with no frequency or no location.