ss-bs-discovering-glossary — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited ss-bs-discovering-glossary (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
You are loaded inline by ss-bs-bootstrapping-project (NOT dispatched as a subagent). A glossary captures the project's canonical vocabulary — domain words that recur across the codebase and have a project-flavored meaning. The code reveals which terms exist and where they appear, but only the user can confirm which ones are load-bearing for a newcomer, whether two names refer to the same thing, and whether a definition lifted from inline comments matches current intent. A subagent could surface candidates from one read pass but couldn't have the back-and-forth needed to settle the cut list. So this skill stays in the coordinator's context.
Core principle: The bar for inclusion is — would someone new to the project misuse this term without a definition? Generic programming terms (function, variable, class) belong in textbooks, not here.
Announce at start: "I'm using the ss-bs-discovering-glossary skill to build docs/GLOSSARY.md with you."
You're invoked when the user picked Create / Extend / Replace for glossary. The coordinator passes you:
REPO_ROOT — absolute path to the repo rootMODE — create, extend, replace, or audit. Audit invokes the drift-check path (Step 1.6) and the drift-resolution Q0 in Step 3.EXISTING_CONTENT — verbatim current docs/GLOSSARY.md content (only for extend / replace; empty otherwise)FILE_PATH — target write path (typically docs/GLOSSARY.md; honors context.glossary_path config override if non-default)on or off. When on, run Step 1.5 (silent diagnose) and surface Q1.5 in Step 3. When off, skip both — identical to pre-suggestion-pass behaviour. Defaulted by the coordinator from suggest.default in config and the opt-in question at bootstrap start. Always on in audit mode.extend mode. Extend merges; only replace overwrites.on (regardless of input). This is documented in the Inputs section.┌─────────────────────────────────────────────────────┐
│ MODE = create or replace │
│ → Step 1: silent code scan (READMEs, identifiers, │
│ schemas, routes, comments) │
│ → Step 1.5: silent diagnose (if SUGGEST=on) │
│ → Step 2: announce findings (+ diagnoses) │
│ → Step 3: targeted questions (Q1, Q1.5 if SUGGEST,│
│ then Q2-Q3) │
│ → Step 4: synthesize draft → show to user │
│ → Step 5: refine via tweak loop (cap 3) │
│ → Step 6: atomic write │
├─────────────────────────────────────────────────────┤
│ MODE = extend │
│ → Step 1: silent code scan + read EXISTING_CONTENT│
│ → Step 1.5: silent diagnose (if SUGGEST=on) │
│ → Step 2: announce findings + gaps + diagnoses │
│ → Step 3: targeted questions on gaps + Q1.5 │
│ → Step 4: synthesize additions → show diff │
│ → Step 5: refine via tweak loop (cap 3) │
│ → Step 6: atomic write of merged content │
├─────────────────────────────────────────────────────┤
│ MODE = audit │
│ → Step 1: silent code scan │
│ → Step 1.5: silent diagnose (always on for audit) │
│ → Step 1.6: drift check vs EXISTING_CONTENT │
│ → Step 2: announce findings + drift + diagnoses │
│ → Step 3: Q0 (drift resolution) → Q1 → Q1.5 → ...│
│ → Step 4-6: as usual │
└─────────────────────────────────────────────────────┘Read all of the following that exist. Don't narrate progress to the user — this happens silently, then you announce findings once in Step 2.
Read these if they exist:
README.md — the project introduces its vocabulary here, usually with capitalization signals (PascalCase or backticked terms)CONTRIBUTING.mddocs/ — skim the table of contents or README; note any "Concepts" or "Terminology" sectionsNote every term that:
You don't need every file. Sample widely:
Class / type / interface names (depending on language):
Database / model names:
migrations/, db/migrations/, prisma/schema.prisma)models/, entities/, ORM-specific)Route paths:
/api/orders, /api/customers, /api/sku/:id)Configuration / env vars:
MAX_LOCKED_ORDERS, STALE_QUOTE_TTL)For each candidate term, note:
Search the codebase for comments that explain terms. Patterns:
// A <Foo> represents .../** <Foo>: <description> */# <Foo> means ...These are gold — the author has already done the work of defining the term. You can lift the definition (rephrased to fit the glossary format).
A term that appears across multiple layers is a strong glossary candidate:
For each candidate, score informally: how many distinct layers (DB / model / source / route / docs / config / README) does this term appear in?
EXISTING_CONTENT (it's empty). Build candidate list from scratch.EXISTING_CONTENT carefully. Note which terms are already defined. Candidate additions focus on net-new terms; also flag definitions in EXISTING_CONTENT that contradict current code behavior.EXISTING_CONTENT. Build candidates fresh.You'll likely have 50+ raw candidates after Steps 1a–1d. Pre-filter to ≤40 before showing to the user:
UserCreatedEvent doesn't need a glossary entry; "Event" might)For each surviving candidate, hold:
SUGGEST=on)If SUGGEST=off, skip this step entirely and proceed to Step 2.
Diagnose looks for vocabulary inconsistencies and missing-but-typically-valuable term definitions. Every diagnose finding must be evidence-cited with specific file paths or concrete counts. Abstract "you should do X" findings are not allowed.
For each category below, scan additional files if needed (within the budget — see Hard Gates). Scan each category for candidates. One strong candidate per category is the target; the aggregate cap of 5 is enforced in 1.5b after dropping unsupported candidates.
user in 8 places, account in 6, both referring to the authenticated subject).Each candidate must include:
severity: one of MUST, SHOULD, INFO — see Hard Gates for the matching evidence bar (typically SHOULD/INFO for glossary)title: one-line headline (e.g., "Define canonical term for authenticated subject")evidence: specific file paths or counts (e.g., src/auth/user.ts:12, src/billing/account.ts:8, src/api/routes.ts:34)proposed_addition: exact markdown text for a new glossary entryDrop any candidate that cannot be cited with specific evidence. Drop any candidate where the severity guess cannot be justified from the evidence (no MUST without observable harm).
If more than 5 candidates remain after dropping unsupported ones, rank by:
Surface the top 5. If 0 candidates remain, the candidate list is empty and Q1.5 in Step 3 is skipped silently.
MODE=audit)Compare each entry in EXISTING_CONTENT against current code state. The goal is to detect entries that have gone stale.
Each finding: kind (term-removed / term-renamed / new-high-traffic-term / aspiration-met / aspiration-still-pending), entry (the doc text being challenged), evidence (grep counts or file paths showing the current code state).
No cap on drift findings — every observable drift is surfaced. The user resolves each in Q0.
One short message (3-6 sentences; 3-7 when SUGGEST=on extends with the diagnose-mention sentence). State what you scanned and the headline finding. Example:
"Here's what I picked up: 38 candidate terms after filtering generic ones. The strongest signals areQuote,RFQ,Settlement,Reconciliation,Idempotency Key,Workspace(each appears in ≥3 layers: DB schema, models, routes, docs). I'll ask you which ≤30 should land in the glossary, then refine the definitions."
If create mode and the scan found very little:
"I didn't find much domain-specific vocabulary — mostly generic terms (User, Item, Status). Either the project is early or the domain is genuinely lean. Want to continue building from what I found, or skip the glossary for now?"
If extend mode:
"Your existing glossary covers [N] terms. I scanned the codebase and found [M] additional candidates not covered (and [K] existing definitions that look inconsistent with current code). I'll ask about those, then propose additions/refinements."
If SUGGEST=on AND Step 1.5 produced ≥1 candidate, extend the announcement with: "…and I noticed a few vocabulary inconsistencies or missing definitions worth adding — I'll surface those after we confirm the observed candidates."
If MODE=audit: "Audit mode. Scan + diagnose + drift check complete. Found N drift items (X terms removed/renamed, Y new high-traffic terms undefined, Z provenance re-evaluations) — I'll surface those first in the questions, then walk through observed candidates and suggestions as usual."
Ask in this order, one question per turn. Skip a question if the scan and (for extend mode) the existing file already answered it.
MODE=audit AND Step 1.6 produced ≥1 drift finding)Ask one question per drift finding (do NOT bundle — drift items often have nuanced individual resolutions):
Question: "Drift detected: <entry summary>. Current code state: <evidence>. What's the right resolution?"
Options:
- "Update the doc to match code"
- "Keep the doc — code is wrong / will be fixed"
- "Remove the entry — no longer applies"
- "Both — clarify scope (split into multiple entries)"For provenance re-evaluation findings, the question is different:
Question: "Aspirational entry '<title>' was added on <date>. Evidence at that time: <original evidence>. Current code state: <current evidence>. Has this aspiration been realized?"
Options:
- "Yes — code has caught up. Remove the provenance marker (promote to normal)."
- "No — code still has the original problem. Keep as aspirational; refresh the marker date."
- "Drop the entry — we've decided not to pursue this aspiration."Record each resolution. Apply during Step 4 (Draft Synthesis).
The most important question. Present the pre-filtered candidate list with a one-line draft definition each, grouped by signal strength.
Question: "I scanned identifiers, comments, schemas, and docs. Here are the candidate terms ranked by how many layers they appear in. Which should land in the glossary? (Cap is 30.)"
Multi-select. Group options as:
- High-confidence (3+ layers): [list with draft definitions]
- Medium-confidence (2 layers): [list with draft definitions]
- Edge cases (1 layer but appeared notable): [list]
Recommended option:
- "Top 30 from the list (high + medium confidence, in order)"
If the candidate list is already ≤30 after filtering:
- "All of the above (Recommended)"If the user selects >30, immediately follow up with a single trim question:
Question: "That's more than 30. Which should I drop?"
Multi-select from the over-cap list.SUGGEST=on AND Step 1.5 produced ≥1 candidate)Question: "Here are some things I'd suggest adding even though they're
not currently codified. These are opinionated — pick any you want to
include:"
Options (multi-select, one option per Step 1.5 candidate, plus a "None" escape):
- [suggestion · <severity> · <evidence-summary>] <title>
Evidence: <evidence>
Proposed addition: <one-line summary of proposed_addition>
- ... (one option per remaining candidate, up to 5)
- "None of these — keep the glossary descriptive only"
Use the harness's multi-select question tool. Do not present as plain text.If the user picks none, treat as "no suggestions accepted" and proceed to Q2. Accepted suggestions are carried into Step 4 (Draft & Show) and rendered with provenance markers.
Question: "Are there terms in the code that have multiple names for the same thing? Examples:
- 'Customer' and 'Account' are interchangeable
- 'Order' in the DB but 'Transaction' in the API
- 'SKU' and 'ProductCode' refer to the same identifier
- 'Reconcile' (verb) and 'Reconciliation' (noun)
Free-form text. List each pair/group on its own line, or skip if there are none."Apply user-supplied aliases by:
<alternate>."If Step 1e flagged any contradiction between existing definitions and current code behavior, ask the user how to resolve each:
Question: "Your existing glossary defines '<term>' as '<existing definition>', but the code currently behaves like '<observed>'. What's the right resolution?"
Options:
- "Update the definition to match current behavior"
- "Keep the existing definition — the code is in violation"
- "Drop the term — it no longer applies"
- "Keep both perspectives — I'll clarify in the definition" (free-form follow-up)Definition refinements are handled during the Step 5 tweak loop — the user can call out specific entries to rewrite when reviewing the full draft.
Synthesize the draft using:
Use the canonical alphabetical template (see Output Template section). Show the full draft to the user, then ask:
Question: "How does this look?"
Options:
- "Approve — write it as-is" (Recommended)
- "Tweak — I'll tell you what to change"
- "Start over — wrong direction"
- "Abort — skip this file"On Tweak: capture the user's free-form notes (often "rewrite the Settlement definition to mention refund transitions" or "drop Backfill, add Snapshot"); apply; re-show; re-ask Step 4. Cap at 3 iterations:
"We've done three rounds and the draft still isn't matching what you want. Want to: (a) keep the current draft anyway, (b) skip the glossary for now, or (c) supply the file yourself — you write the markdown, I'll save it?"
On Start over: restart Step 3 from Q1 (scan findings carry over; user answers reset).
On Abort: report skipped (declined mid-skill) to the coordinator and exit.
cat > "$FILE_PATH.tmp" <<EOF
<draft content>
EOF
mv "$FILE_PATH.tmp" "$FILE_PATH"For extend mode: merge EXISTING_CONTENT + the new entries / refinements into a single alphabetically-sorted document, then write atomically. Preserve existing accurate entries; replace only the ones flagged in Q3.
Report to the coordinator one of:
created (mode = create, full draft written)extended (mode = extend, merged content written)replaced (mode = replace, full draft written)skipped (declined mid-skill) (user aborted partway)Each accepted Q1.5 suggestion becomes a new glossary entry. Append a provenance note at the end of the entry using this exact format:
### <Term> · `<slug>`
<Definition text, 1-3 sentences.>
**Aliases:** <comma-separated list, if any>
> _Added via bootstrap suggestion pass (YYYY-MM-DD)._
> _Evidence: <evidence summary from the Q1.5 candidate>._
> _The team has not yet standardized on this term._Replace YYYY-MM-DD with today's date. The three blockquote lines each carry a self-contained italic span (italic spans never cross blockquote line boundaries). The audit skill reads this marker on re-runs to ask whether the team has resolved the inconsistency.
Canonical alphabetical structure (only include letter headings that have entries):
# Glossary
## A
### <Term>
<Definition (≤2 sentences). If the term has alternate spellings or synonyms,
note them: "Also called `<alternate>`.">
## B
### <Term>
<Definition.>
(... alphabetically grouped by first letter)Definition guidelines:
Examples of good entries (illustrative — adapt to your findings):
### Quote A price commitment given to a customer in response to an RFQ, valid until its expiry timestamp. Quotes transition through Pending → Settled, or Pending → Expired if not accepted in time.
### RFQ (Request For Quote) A customer's inbound request for pricing on a specific configuration. RFQs are short-lived; each generates exactly one Quote.
### Idempotency key A client-supplied token attached to every write request, used to deduplicate retries server-side. Required for allPOST/PUT/DELETEendpoints.
| Mistake | Fix |
|---|---|
| Defining generic programming terms (function, class, API) | Domain-specific only |
| Definitions longer than 2 sentences | Trim to ≤2; if longer is needed, the term belongs in its own doc, not a glossary |
| Proposing >30 terms | Trim with the user; never silently |
Circular definitions (X is a kind of X-thing) | Define by what it represents in the domain, not by its name |
| Lifting marketing copy from README without confirming code matches | Definitions must reflect what the code does, not what the README says it does |
| Listing every enum value as a glossary term | Only include lifecycle states with non-obvious semantics |
| Skipping the alphabetical grouping | Always alphabetical; helps lookup |
| Bundling multiple questions in one ask | One question per turn |
| Looping past 3 tweak iterations | Surface to user with bail options |
| Overwriting in extend mode | Extend merges; only replace overwrites |
| Surfacing a diagnose candidate without file-path evidence | Drop it; only evidence-cited candidates pass the gate |
| Surfacing >5 diagnose candidates | Hard cap is 5; rank by severity → evidence → impact, drop the rest |
| Forgetting the provenance marker on an accepted Q1.5 suggestion | Audit relies on the marker to recognize aspirational entries; without it, drift detection breaks |
| Running Step 1.5 when SUGGEST=off | Skip Step 1.5 entirely when off; do not run-but-suppress |
| Skipping Step 1.6 in audit mode | Drift detection is the audit's reason for existing |
| Bundling Q0 drift resolutions into one multi-select | Each item gets its own question — resolutions are not collectively decidable |
| Forgetting to refresh the provenance marker date when "Keep aspirational" is chosen | Audit needs the refresh to track time-since-last-evaluation |
| Forgetting to strip the provenance marker when "Promote to normal" is chosen | The marker is the audit's hook; promoting means removing it |
Database or API → STOP; generic terms are out of scopeA glossary draws from two sources — what the code calls things (identifiers, schema columns, route paths, comments) and what the user means by those things. The first half a subagent could extract; the second half requires conversation. Picking the ≤30 terms that actually matter from a 50-candidate list is a judgment call only the user can make. Resolving aliases (does "Customer" and "Account" mean the same thing here?) requires asking. Confirming that an inline-comment definition still matches reality requires asking. Routing all that through a coordinator (subagent returns 50 candidates → coordinator paraphrases to user → user replies → coordinator re-dispatches with trim instructions) wastes turns and drifts intent.
So this skill stays inline. It scans the code itself, then talks to the user about which terms are load-bearing and what they really mean. The four sibling skills (ss-bs-discovering-constitution, ss-bs-discovering-architecture, ss-bs-discovering-domain-model, ss-bs-discovering-design) follow the same pattern for the same reason.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.