@caddis/cli 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundles/antigravity-plugin/CADDIS-GLOSSARY.md +150 -0
- package/bundles/antigravity-plugin/plugin.json +1 -1
- package/bundles/antigravity-plugin/scripts/caddis_glossary.py +268 -0
- package/bundles/antigravity-plugin/scripts/setup_project_ai.py +47 -0
- package/bundles/antigravity-plugin/skills/_registry.md +1 -0
- package/bundles/antigravity-plugin/skills/glossary/SKILL.md +89 -0
- package/bundles/manifest.json +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Pipeline Glossary
|
|
2
|
+
|
|
3
|
+
> **Shipped as `CADDIS-GLOSSARY.md`.** This defines CADDIS's own vocabulary — the words the
|
|
4
|
+
> toolchain coined, which a user meets constantly and cannot guess from the plain word. Your
|
|
5
|
+
> project's own terms belong in `.caddis/kb/GLOSSARY.md` instead; run `/caddis:glossary` to
|
|
6
|
+
> build one. Two files, two subjects, deliberately different names.
|
|
7
|
+
|
|
8
|
+
Canonical terms used across all agents, skills, and pipeline infrastructure.
|
|
9
|
+
When writing agent instructions, skills, or documentation, use ONLY these terms.
|
|
10
|
+
|
|
11
|
+
Two vocabularies live here and they are NOT interchangeable. **Core Terms** onward describe the
|
|
12
|
+
agent PIPELINE (orchestrator, stages, `pipeline-state.json`). **Toolchain Terms** describe caddis
|
|
13
|
+
as a distributed product (pool, mirror, export target). A word can be canonical in one and absent
|
|
14
|
+
from the other; where they genuinely collide, the collision is named under Flagged ambiguities
|
|
15
|
+
rather than resolved by fiat.
|
|
16
|
+
|
|
17
|
+
Admission test, borrowed from `last30days-skill`'s CONCEPTS.md: a term belongs here when its
|
|
18
|
+
project meaning is **distinct enough from its ordinary technical sense that a newcomer would
|
|
19
|
+
misread it**. `commit` does not belong. `pool` does.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Core Terms
|
|
24
|
+
|
|
25
|
+
| Canonical Term | Definition | DO NOT USE |
|
|
26
|
+
|---------------|------------|------------|
|
|
27
|
+
| artefact | Any file produced by an agent as pipeline output. This is the correct spelling in all contexts — field names, prose, section headers. | artifact, deliverable, output file |
|
|
28
|
+
| stage | A pipeline-level progression step (intent, prd, architect, plan, implement, tester, review, closed) | phase (for pipeline steps), step |
|
|
29
|
+
| phase | A subdivision of work within a Plan (Phase 1, Phase 2…). Phases exist WITHIN the implement stage. | stage (for plan subdivisions), step |
|
|
30
|
+
| chain_id | Feature tracking ID format: `FEAT-YYYY-MMDD-slug`. Links all artefacts for a feature. | feature_id, tracking_id |
|
|
31
|
+
| handoff | Transfer of work from one agent to another via Orchestrator | routing (for the transfer act), delegation, dispatch, hand-off |
|
|
32
|
+
| handoff payload | The `_notes.handoff_payload` object written by Orchestrator via `update_notes` MCP tool before routing to a specialist | routing context, task context |
|
|
33
|
+
| evidence bundle | Anchor's structured proof-of-work document (`agent-docs/anchor-evidence-*.md`) | proof, verification report |
|
|
34
|
+
| gate | A supervision checkpoint requiring approval before pipeline advances (`supervision_gates.*`) | checkpoint, approval point |
|
|
35
|
+
| HARD STOP | Absolute refusal to proceed — security violation, out-of-scope request, or rogue state edit | halt, block, refuse |
|
|
36
|
+
| skill | A reusable knowledge pack in `.github/skills/{category}/{name}/SKILL.md` | SKILL (when referring to the concept, not the filename) |
|
|
37
|
+
| prompt | A reusable prompt file in `.github/prompts/*.prompt.md` | skill (when referring to prompt files — prompts are not skills) |
|
|
38
|
+
| onboarding prompt | The project bootstrap prompt at `.github/prompts/onboarding.prompt.md` | onboarding skill |
|
|
39
|
+
|
|
40
|
+
## Pipeline Modes
|
|
41
|
+
|
|
42
|
+
| Term | Definition |
|
|
43
|
+
|------|------------|
|
|
44
|
+
| supervised | All gates require manual user approval. Default mode. |
|
|
45
|
+
| assisted | Manual gates with AI guidance hints. Auto-routing between stages. |
|
|
46
|
+
| autopilot | All gates auto-satisfied except `intent_approved`. Fully hands-free after intent approval. |
|
|
47
|
+
|
|
48
|
+
## Result Statuses
|
|
49
|
+
|
|
50
|
+
### MCP `notify_orchestrator` — `result_status` parameter
|
|
51
|
+
|
|
52
|
+
| Value | Meaning | Used By |
|
|
53
|
+
|-------|---------|---------|
|
|
54
|
+
| `complete` | Standard stage completion | All agents |
|
|
55
|
+
| `phase_complete` | Multi-phase loop — implement stays in implement for next phase | Implement agent |
|
|
56
|
+
| `recovered` | Recovery after guard failure | Orchestrator (debug flow) |
|
|
57
|
+
|
|
58
|
+
### Agent-Specific Result Fields
|
|
59
|
+
|
|
60
|
+
| Agent | Field | Possible Values | Meaning |
|
|
61
|
+
|-------|-------|-----------------|---------|
|
|
62
|
+
| Tester | `tester_result.status` | `passed`, `failed` | All tests pass / any test fails |
|
|
63
|
+
| Code Reviewer | `Verdict` | `approved`, `revision-requested` | Code meets standards / needs changes |
|
|
64
|
+
| All agents (artefact YAML header) | `approval` | `approved`, `pending`, `revision-requested` | Artefact acceptance status |
|
|
65
|
+
|
|
66
|
+
### Orchestrator Artefact Validation Guards
|
|
67
|
+
|
|
68
|
+
| Guard | Checks |
|
|
69
|
+
|-------|--------|
|
|
70
|
+
| `artefact_exists` | File at `artefact_path` exists on disk |
|
|
71
|
+
| `artefact_approved` | YAML header `approval:` field is `approved` |
|
|
72
|
+
| `all_phases_done` | All implementation phases complete |
|
|
73
|
+
|
|
74
|
+
## File Naming Conventions
|
|
75
|
+
|
|
76
|
+
| Pattern | Example | Usage |
|
|
77
|
+
|---------|---------|-------|
|
|
78
|
+
| Agent file | `frontend-developer.agent.md` | Lowercase kebab-case matching `name` frontmatter field |
|
|
79
|
+
| Skill file | `.github/skills/{category}/{name}/SKILL.md` | Category folder + name folder + SKILL.md |
|
|
80
|
+
| Plan file | `.github/plans/{feature-slug}.md` | Feature slug from chain_id |
|
|
81
|
+
| Evidence file | `agent-docs/anchor-evidence-{feature}.md` | Per-feature evidence bundle |
|
|
82
|
+
| Artefact registry | `agent-docs/ARTIFACTS.md` | Single registry for all pipeline artefacts |
|
|
83
|
+
| Pipeline state | `.github/pipeline-state.json` | Live pipeline state — written ONLY by MCP tools |
|
|
84
|
+
|
|
85
|
+
## Pipeline State Field Ownership
|
|
86
|
+
|
|
87
|
+
All writes to `pipeline-state.json` go through MCP tools. Only `stages[*].status`, `stages[*].artefact`, `stages[*].completed_at`, and `blocked_by` may be set via `editFiles`.
|
|
88
|
+
|
|
89
|
+
| Field | Writer | Tool |
|
|
90
|
+
|-------|--------|------|
|
|
91
|
+
| `current_stage` | Pipeline runner | `notify_orchestrator` |
|
|
92
|
+
| `supervision_gates[*]` | Orchestrator | `satisfy_gate` |
|
|
93
|
+
| `pipeline_mode` | Orchestrator | `set_pipeline_mode` |
|
|
94
|
+
| `_notes.*` | Orchestrator / agents | `update_notes` |
|
|
95
|
+
| `project`, `feature`, `type` | Orchestrator | `pipeline_init` / `pipeline_reset` |
|
|
96
|
+
|
|
97
|
+
## Common Conflations to Avoid
|
|
98
|
+
|
|
99
|
+
| Wrong | Correct | Why |
|
|
100
|
+
|-------|---------|-----|
|
|
101
|
+
| "Phase 3 of the pipeline" | "The implement stage" | Phases are within a Plan; stages are pipeline-level |
|
|
102
|
+
| "The artifact registry" | "The artefact registry" | British spelling is canonical (matches all field names) |
|
|
103
|
+
| "Run the onboarding skill" | "Run the onboarding prompt" | `.prompt.md` files are prompts, not skills |
|
|
104
|
+
| "Route to the agent" | "Hand off to the agent" | Routing is Orchestrator's internal logic; handoff is the transfer act |
|
|
105
|
+
| `[Stage/Phase N]` | `[Phase N]` (within Plan) or `[Stage: implement]` (pipeline-level) | Don't conflate the two with a slash |
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Toolchain Terms
|
|
110
|
+
|
|
111
|
+
caddis-the-product, as opposed to the agent pipeline above. These are the words caddis invented
|
|
112
|
+
out of ordinary English, which is exactly why they need defining: a reader who guesses from the
|
|
113
|
+
plain word gets them wrong. Usage counts were measured across 444 markdown files on 2026-08-29.
|
|
114
|
+
|
|
115
|
+
| Canonical Term | Definition | DO NOT USE |
|
|
116
|
+
|---|---|---|
|
|
117
|
+
| pool | The single source of every shipped resource, living in `.github/` (skills, agents, commands, prompts). Everything a user installs is EXPORTED from the pool; nothing is authored in a bundle. Versioned independently of the CLI, and bumped only by `caddis-push` — never by hand. *(222 uses)* | bundle (for the source), library |
|
|
118
|
+
| bundle | One EXPORTED copy of the pool, shaped for a single target — `dist/runtime-resources/<target>/`. A bundle is generated output; editing one is always a mistake. | pool (for a built copy) |
|
|
119
|
+
| export target | A named consumer in `.github/runtime-targets.json` — claude, antigravity, antigravity-plugin, codex, copilot, plus `-extras` variants. Each takes a different subset and layout from the same pool. | platform, host (for a target) |
|
|
120
|
+
| mirror | The public repo `saajunaid/caddis-plugin`, refreshed by `caddis-push`. The SOURCE repo is private, so the mirror is what any other machine can actually reach. | upstream, remote |
|
|
121
|
+
| relay | `.caddis/relay.md` — the durable resume doc, rewritten by `/caddis:handoff` and injected at SessionStart. Machine-local and gitignored. Only changes when someone runs a handoff, so it is stale between them by design. *(168 uses)* | handoff doc, session notes |
|
|
122
|
+
| session state | `.caddis/session-state.md` — auto-captured by the `Stop` hook at the end of EVERY turn. Distinct from the relay: current without anyone deciding to make it current, and it holds no agreed next step. | relay (they are different files with different guarantees) |
|
|
123
|
+
| drift | A gap between what a consumer HAS installed and what the pool currently ships. `caddis status` reports it per agent. Not code drift, not schema drift. *(160 uses)* | staleness, lag |
|
|
124
|
+
| live-fire | Driving a real binary end to end rather than asserting against a manifest. Coined because three defects in one month passed every test and still gave a human a broken install: the tests asked "does the export match the manifest", never "would this work". An export target is not trusted until it has been live-fired once. | smoke test, integration test, manual test |
|
|
125
|
+
| parking-lot | `.caddis/parking-lot/` — the ONE register of future work. It exists because future work previously scattered to nine places and no session could answer "what is left". Items carry `severity` and `status`; the backlog IS the plan when no plan is active. *(41 uses)* | backlog file, TODO list, icebox |
|
|
126
|
+
| model lane | A named provider route reached by its own binary — `claude-oss`, `claude-glm`, `claude-deepseek` — all speaking the Anthropic protocol. A lane is a route, not a model. | provider, backend, endpoint |
|
|
127
|
+
| core / extras | The two shipping tiers. Core is an EXPLICIT allowlist in `.github/runtime-targets.json`; anything not named there lands in extras. A skill defaults to extras, so placement is a decision, never an accident. | tier 1 / tier 2, full / lite |
|
|
128
|
+
| harness | The agent runtime that loads caddis — Claude Code, agy, Codex, Copilot. caddis is agent-agnostic; "the harness" without a name means whichever one is running. *(135 uses)* | client, IDE, platform |
|
|
129
|
+
|
|
130
|
+
## Flagged ambiguities
|
|
131
|
+
|
|
132
|
+
Named rather than resolved. Pretending the vocabulary is clean is how a glossary starts lying.
|
|
133
|
+
|
|
134
|
+
- **`gate` is overloaded, badly.** Core Terms defines it as a supervision checkpoint requiring
|
|
135
|
+
approval. That is one of at least twelve senses in live use: *exit gate* (20), *quality gate*
|
|
136
|
+
(9), *evidence gate* (5), *decision gate* (3), plus pre-publish, handover and privacy gates —
|
|
137
|
+
none of which involve pipeline supervision. The word appears 1019 times across 168 files.
|
|
138
|
+
**Prefer the full two-word term everywhere**; a bare "gate" is ambiguous and the reader cannot
|
|
139
|
+
tell which one you meant.
|
|
140
|
+
|
|
141
|
+
- **`artefact` vs `artifact`.** Core Terms makes `artefact` canonical, and for pipeline outputs it
|
|
142
|
+
is. But the toolchain's own code says `artifact_root` and "artifact dir" (17 uses in
|
|
143
|
+
`scripts/setup_project_ai.py` alone), and those are API names that cannot be respelled without
|
|
144
|
+
a breaking change. So: **artefact** in pipeline prose and field names; **artifact dir /
|
|
145
|
+
`artifact_root`** when naming the `.caddis/` directory mechanism. Do not "fix" one into the other.
|
|
146
|
+
|
|
147
|
+
- **`skill` means two things across harnesses.** In the pool it is
|
|
148
|
+
`.github/skills/<category>/<name>/SKILL.md`. But agy CONVERTS commands into skills at install
|
|
149
|
+
time, so `/caddis:catchup` ships as a command and arrives as an agy skill. A skill count that
|
|
150
|
+
disagrees between two agents is usually this, not a bug.
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"""caddis_glossary — propose the words a project INVENTED, so they can be defined once.
|
|
2
|
+
|
|
3
|
+
WHY. Every project coins vocabulary out of ordinary English, and those are the worst words in
|
|
4
|
+
the codebase: a reader who guesses from the plain word gets them wrong and never knows. caddis
|
|
5
|
+
itself coined `pool`, `relay`, `drift`, `parking-lot`, `live-fire` — and its own glossary went
|
|
6
|
+
five and a half months without mentioning any of them, because nothing measured the gap.
|
|
7
|
+
|
|
8
|
+
WHAT THIS DOES AND DOES NOT DO. It PROPOSES candidates by measurement. It never writes a
|
|
9
|
+
definition, because a definition is domain knowledge that only a person or a model reading the
|
|
10
|
+
code can supply. A file of correct words with empty meanings is worse than no file: it looks
|
|
11
|
+
authoritative and teaches nothing. `/caddis:glossary` is the half that writes the meanings.
|
|
12
|
+
|
|
13
|
+
python caddis_glossary.py # propose candidates, ranked
|
|
14
|
+
python caddis_glossary.py --check # exit 1 if a proposed term has no entry
|
|
15
|
+
python caddis_glossary.py --scaffold # create the file if it is missing
|
|
16
|
+
|
|
17
|
+
HOW A CANDIDATE IS CHOSEN. Frequency alone is useless — "the file" beats every real term. A
|
|
18
|
+
word is a candidate when it is COMMON IN THIS REPO but is not ordinary technical English. The
|
|
19
|
+
stop-list below is the load-bearing part, and it is deliberately generous: a false positive
|
|
20
|
+
costs a human three seconds to ignore, while a false negative leaves a coined word undefined
|
|
21
|
+
forever, which is the failure being fixed.
|
|
22
|
+
|
|
23
|
+
ACCURACY, MEASURED. On a normal application repo it is good: run against `docket` it proposed
|
|
24
|
+
`board`, `lane`, `card`, `gate` — that project's actual coined vocabulary, top of the list. On a
|
|
25
|
+
HARNESS repo full of documentation ABOUT agents it is noisier, because words like `protocol` and
|
|
26
|
+
`intent` are both ordinary English and genuinely overloaded here. It is a suggester, not an
|
|
27
|
+
oracle; a human or the model decides what earns an entry.
|
|
28
|
+
|
|
29
|
+
Stdlib only, cross-platform, and it never raises on a bad file — it is run by a command and by
|
|
30
|
+
a gate, and a traceback from either is worse than a missing suggestion.
|
|
31
|
+
"""
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import argparse
|
|
35
|
+
import collections
|
|
36
|
+
import os
|
|
37
|
+
import re
|
|
38
|
+
import sys
|
|
39
|
+
|
|
40
|
+
# ── what a project's own vocabulary lives in ────────────────────────────────────────────
|
|
41
|
+
DOC_GLOBS = (".md",)
|
|
42
|
+
SKIP_DIRS = {
|
|
43
|
+
".git", "node_modules", ".venv", "venv", "dist", "build", "__pycache__",
|
|
44
|
+
".mypy_cache", ".pytest_cache", "vendor", "site-packages", ".next", "target",
|
|
45
|
+
# Vendored and reference material is someone ELSE'S vocabulary. Without these, caddis's
|
|
46
|
+
# own run proposed `aws4` (33 files) and `mxgraph` (11) out of bundled AWS and draw-io
|
|
47
|
+
# reference docs — words no caddis reader will ever meet.
|
|
48
|
+
"references", "assets", "fixtures", ".archive", "archive", "examples", "sample",
|
|
49
|
+
"samples", "third_party", "vendored", "node_modules", "bundles", "runtime-resources",
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# Ordinary technical English. A word here is never proposed, however often it appears.
|
|
53
|
+
# Longer than it looks necessary on purpose: the cost of a false positive is a human ignoring
|
|
54
|
+
# one line; the cost of a false negative is a coined word nobody ever defines.
|
|
55
|
+
COMMON = {
|
|
56
|
+
# english scaffolding
|
|
57
|
+
"the", "and", "for", "with", "that", "this", "from", "into", "than", "then", "when",
|
|
58
|
+
"where", "which", "what", "who", "why", "how", "not", "but", "all", "any", "each",
|
|
59
|
+
"one", "two", "only", "also", "more", "most", "less", "some", "such", "same", "other",
|
|
60
|
+
"its", "it's", "you", "your", "our", "their", "they", "them", "has", "have", "had",
|
|
61
|
+
"was", "were", "been", "being", "are", "can", "will", "would", "should", "must", "may",
|
|
62
|
+
"does", "did", "done", "doing", "use", "used", "using", "make", "made", "get", "got",
|
|
63
|
+
"see", "read", "write", "run", "runs", "running", "ran", "set", "put", "take", "give",
|
|
64
|
+
"new", "old", "first", "last", "next", "now", "here", "there", "before", "after",
|
|
65
|
+
"over", "under", "out", "off", "own", "per", "via", "yes", "no", "if", "in", "on", "of",
|
|
66
|
+
"to", "at", "by", "as", "is", "be", "or", "so", "up", "do", "an", "a",
|
|
67
|
+
# ordinary software vocabulary — predictable from the word itself
|
|
68
|
+
"file", "files", "path", "paths", "dir", "directory", "folder", "code", "line", "lines",
|
|
69
|
+
"test", "tests", "testing", "error", "errors", "bug", "fix", "fixed", "build", "built",
|
|
70
|
+
"commit", "commits", "branch", "merge", "push", "pull", "repo", "repository", "git",
|
|
71
|
+
"api", "cli", "url", "http", "https", "json", "yaml", "toml", "html", "css", "sql",
|
|
72
|
+
"user", "users", "name", "names", "value", "values", "key", "keys", "type", "types",
|
|
73
|
+
"list", "lists", "table", "tables", "row", "rows", "column", "field", "fields",
|
|
74
|
+
"function", "method", "class", "module", "package", "library", "script", "scripts",
|
|
75
|
+
"server", "client", "request", "response", "data", "input", "output", "config",
|
|
76
|
+
"version", "release", "install", "update", "delete", "create", "add", "remove",
|
|
77
|
+
"return", "returns", "call", "calls", "check", "checks", "log", "logs", "note", "notes",
|
|
78
|
+
"step", "steps", "case", "cases", "example", "default", "option", "options", "flag",
|
|
79
|
+
"flags", "command", "commands", "tool", "tools", "agent", "agents", "model", "models",
|
|
80
|
+
"session", "sessions", "context", "prompt", "prompts", "token", "tokens", "cache",
|
|
81
|
+
"state", "status", "result", "results", "change", "changes", "work", "works", "time",
|
|
82
|
+
"does", "doc", "docs", "document", "section", "page", "text", "content", "format",
|
|
83
|
+
"project", "projects", "team", "user", "system", "service", "process", "task", "tasks",
|
|
84
|
+
"issue", "issues", "problem", "solution", "reason", "cause", "point", "part", "way",
|
|
85
|
+
"thing", "things", "need", "needs", "want", "know", "like", "just", "even", "still",
|
|
86
|
+
"never", "always", "every", "both", "because", "while", "since", "about", "against",
|
|
87
|
+
# added after the first real run proposed all of these — ordinary in any codebase
|
|
88
|
+
"skill", "skills", "plan", "plans", "phase", "phases", "design", "designs", "review",
|
|
89
|
+
"reviews", "mode", "modes", "pattern", "patterns", "implementation", "reference",
|
|
90
|
+
"description", "descriptions", "workflow", "workflows", "feature", "features",
|
|
91
|
+
"component", "components", "interface", "structure", "approach", "detail", "details",
|
|
92
|
+
"requirement", "requirements", "specification", "architecture", "instructions",
|
|
93
|
+
"guidelines", "standard", "standards", "best", "practice", "practices", "overview",
|
|
94
|
+
"summary", "report", "reports", "action", "actions", "level", "levels", "order",
|
|
95
|
+
"number", "count", "size", "start", "stop", "begin", "end", "open", "close", "load",
|
|
96
|
+
"save", "store", "fetch", "send", "receive", "handle", "handles", "support", "supports",
|
|
97
|
+
"references", "security", "scope", "verification", "react", "python", "typescript",
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
_WORD = re.compile(r"[a-z][a-z0-9]*(?:-[a-z0-9]+)*", re.I)
|
|
101
|
+
|
|
102
|
+
# A term must appear at least this often, in at least this many files, to be proposed.
|
|
103
|
+
# One mention is a passing usage; a coined term earns its definition by recurring.
|
|
104
|
+
MIN_USES = 12
|
|
105
|
+
MIN_FILES = 3
|
|
106
|
+
MAX_SUGGESTIONS = 25
|
|
107
|
+
# A coined term is specific, so in a LARGE corpus it shows up in a minority of files. Measured:
|
|
108
|
+
# `description` appeared in 2112 of ~2500 caddis docs and outranked every real term.
|
|
109
|
+
#
|
|
110
|
+
# But this rule INVERTS on a small repo. Applied unconditionally it deleted docket's four best
|
|
111
|
+
# candidates — `board`, `lane`, `card`, `docket` — because in a 50-file repo the core vocabulary
|
|
112
|
+
# genuinely is in most files. So it only engages once there are enough files for "share" to
|
|
113
|
+
# mean anything.
|
|
114
|
+
MAX_FILE_SHARE = 0.25
|
|
115
|
+
SHARE_RULE_MIN_CORPUS = 200
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _doc_files(root: str) -> list[str]:
|
|
119
|
+
found = []
|
|
120
|
+
for dirpath, dirnames, filenames in os.walk(root):
|
|
121
|
+
dirnames[:] = [d for d in dirnames if d not in SKIP_DIRS and not d.startswith(".venv")]
|
|
122
|
+
for n in filenames:
|
|
123
|
+
if n.endswith(DOC_GLOBS):
|
|
124
|
+
found.append(os.path.join(dirpath, n))
|
|
125
|
+
return found
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def glossary_path(root: str) -> str:
|
|
129
|
+
"""`.caddis/kb/GLOSSARY.md` — beside the KB, which is where reference docs live."""
|
|
130
|
+
return os.path.join(root, ".caddis", "kb", "GLOSSARY.md")
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def defined_terms(path: str) -> set[str]:
|
|
134
|
+
"""Canonical terms are the first cell of each markdown table row."""
|
|
135
|
+
if not os.path.isfile(path):
|
|
136
|
+
return set()
|
|
137
|
+
terms = set()
|
|
138
|
+
try:
|
|
139
|
+
with open(path, encoding="utf-8", errors="replace") as fh:
|
|
140
|
+
for line in fh:
|
|
141
|
+
if not line.startswith("|"):
|
|
142
|
+
continue
|
|
143
|
+
cells = [c.strip() for c in line.strip().strip("|").split("|")]
|
|
144
|
+
if len(cells) < 2 or not cells[0] or set(cells[0]) <= {"-", ":", " "}:
|
|
145
|
+
continue
|
|
146
|
+
head = cells[0].strip("`*").lower()
|
|
147
|
+
if head in {"term", "canonical term", "word"}:
|
|
148
|
+
continue
|
|
149
|
+
terms.add(head)
|
|
150
|
+
except OSError:
|
|
151
|
+
return set()
|
|
152
|
+
return terms
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def propose(root: str) -> list[tuple[str, int, int]]:
|
|
156
|
+
"""Return [(term, uses, files)] — words this repo says often that plain English does not."""
|
|
157
|
+
uses: collections.Counter = collections.Counter()
|
|
158
|
+
files: dict[str, set] = collections.defaultdict(set)
|
|
159
|
+
for f in _doc_files(root):
|
|
160
|
+
try:
|
|
161
|
+
text = open(f, encoding="utf-8", errors="replace").read().lower()
|
|
162
|
+
except OSError:
|
|
163
|
+
continue
|
|
164
|
+
# Strip fenced code and inline code: identifiers are not project vocabulary.
|
|
165
|
+
text = re.sub(r"```.*?```", " ", text, flags=re.S)
|
|
166
|
+
text = re.sub(r"`[^`]*`", " ", text)
|
|
167
|
+
for w in _WORD.findall(text):
|
|
168
|
+
if len(w) < 4 or w in COMMON:
|
|
169
|
+
continue
|
|
170
|
+
uses[w] += 1
|
|
171
|
+
files[w].add(f)
|
|
172
|
+
total = max(1, len(_doc_files(root)))
|
|
173
|
+
out = [
|
|
174
|
+
(w, n, len(files[w]))
|
|
175
|
+
for w, n in uses.items()
|
|
176
|
+
if n >= MIN_USES
|
|
177
|
+
and len(files[w]) >= MIN_FILES
|
|
178
|
+
and (total < SHARE_RULE_MIN_CORPUS or (len(files[w]) / total) <= MAX_FILE_SHARE)
|
|
179
|
+
]
|
|
180
|
+
out.sort(key=lambda r: (-r[1], r[0]))
|
|
181
|
+
return out
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
TEMPLATE = """# Glossary
|
|
185
|
+
|
|
186
|
+
The words this project invented out of ordinary English, defined once.
|
|
187
|
+
|
|
188
|
+
**Admission test:** a term belongs here when its meaning in this project is *distinct enough
|
|
189
|
+
from its ordinary technical sense that a newcomer would misread it*. `commit` does not belong.
|
|
190
|
+
A word this team uses in its own way does.
|
|
191
|
+
|
|
192
|
+
Proposed by `caddis_glossary.py`, which measures which words this repo says often that plain
|
|
193
|
+
English does not. It cannot write the definitions — run `/caddis:glossary` and the model will
|
|
194
|
+
draft them from the actual code, or write them yourself.
|
|
195
|
+
|
|
196
|
+
| Term | Definition | DO NOT USE |
|
|
197
|
+
|---|---|---|
|
|
198
|
+
| _example_ | Replace this row. A definition should say what the word means HERE, and why the ordinary reading is wrong. | the synonyms that cause confusion |
|
|
199
|
+
|
|
200
|
+
## Flagged ambiguities
|
|
201
|
+
|
|
202
|
+
Name the words that are still overloaded rather than pretending the vocabulary is clean. A
|
|
203
|
+
glossary that hides its own dirt starts lying. Delete this section only when there is genuinely
|
|
204
|
+
nothing to flag.
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def main(argv: list[str] | None = None) -> int:
|
|
209
|
+
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
210
|
+
ap.add_argument("--root", default=os.getcwd())
|
|
211
|
+
ap.add_argument("--check", action="store_true",
|
|
212
|
+
help="exit 1 if a proposed term has no entry")
|
|
213
|
+
ap.add_argument("--scaffold", action="store_true",
|
|
214
|
+
help="write the glossary template if it does not exist")
|
|
215
|
+
args = ap.parse_args(argv)
|
|
216
|
+
|
|
217
|
+
root = os.path.abspath(args.root)
|
|
218
|
+
path = glossary_path(root)
|
|
219
|
+
|
|
220
|
+
if args.scaffold:
|
|
221
|
+
if os.path.isfile(path):
|
|
222
|
+
print("[glossary] present — kept: %s" % os.path.relpath(path, root))
|
|
223
|
+
else:
|
|
224
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
225
|
+
with open(path, "w", encoding="utf-8", newline="\n") as fh:
|
|
226
|
+
fh.write(TEMPLATE)
|
|
227
|
+
print("[glossary] wrote %s" % os.path.relpath(path, root))
|
|
228
|
+
return 0
|
|
229
|
+
|
|
230
|
+
candidates = propose(root)
|
|
231
|
+
defined = defined_terms(path)
|
|
232
|
+
missing = [(w, n, f) for w, n, f in candidates if w not in defined]
|
|
233
|
+
|
|
234
|
+
if args.check:
|
|
235
|
+
# Advisory by design. A project may legitimately decide a frequent word needs no
|
|
236
|
+
# definition, and a gate that cannot be satisfied gets bypassed rather than obeyed.
|
|
237
|
+
if not os.path.isfile(path):
|
|
238
|
+
print("[glossary] no %s — run with --scaffold" % os.path.relpath(path, root))
|
|
239
|
+
return 0
|
|
240
|
+
if missing:
|
|
241
|
+
print("[glossary] %d frequent term(s) with no entry:" % len(missing))
|
|
242
|
+
for w, n, f in missing[:MAX_SUGGESTIONS]:
|
|
243
|
+
print(" %-24s %4d uses in %d files" % (w, n, f))
|
|
244
|
+
print(" Define them, or leave them — this is advisory. `/caddis:glossary` drafts them.")
|
|
245
|
+
return 1
|
|
246
|
+
print("[glossary] every frequent term is defined (%d entries)" % len(defined))
|
|
247
|
+
return 0
|
|
248
|
+
|
|
249
|
+
if not candidates:
|
|
250
|
+
print("[glossary] no candidates — too few docs, or nothing recurs enough.")
|
|
251
|
+
return 0
|
|
252
|
+
print("Candidate vocabulary for %s" % root)
|
|
253
|
+
print(" (>= %d uses across >= %d files, ordinary English excluded)\n" % (MIN_USES, MIN_FILES))
|
|
254
|
+
print(" %-26s %6s %6s %s" % ("TERM", "USES", "FILES", "DEFINED?"))
|
|
255
|
+
for w, n, f in candidates[:MAX_SUGGESTIONS]:
|
|
256
|
+
print(" %-26s %6d %6d %s" % (w, n, f, "yes" if w in defined else "-- no --"))
|
|
257
|
+
if missing:
|
|
258
|
+
print("\n %d undefined. Run `/caddis:glossary` to draft definitions from the code."
|
|
259
|
+
% len(missing))
|
|
260
|
+
return 0
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
if __name__ == "__main__":
|
|
264
|
+
try:
|
|
265
|
+
sys.exit(main())
|
|
266
|
+
except Exception as exc: # pragma: no cover — a suggester must never break a caller
|
|
267
|
+
print("[glossary] skipped: %s" % exc)
|
|
268
|
+
sys.exit(0)
|
|
@@ -902,6 +902,39 @@ memory.jsonl
|
|
|
902
902
|
"""
|
|
903
903
|
|
|
904
904
|
|
|
905
|
+
GLOSSARY_TEMPLATE = """\
|
|
906
|
+
# Glossary
|
|
907
|
+
|
|
908
|
+
The words this project invented out of ordinary English, defined once.
|
|
909
|
+
|
|
910
|
+
**Admission test:** a term belongs here when its meaning in this project is *distinct
|
|
911
|
+
enough from its ordinary technical sense that a newcomer would misread it*. `commit` does
|
|
912
|
+
not belong. A word this team uses in its own way does.
|
|
913
|
+
|
|
914
|
+
To find candidates, run the measurer. It ranks the words this repo says often that plain
|
|
915
|
+
English does not, and marks which already have an entry:
|
|
916
|
+
|
|
917
|
+
python <caddis>/scripts/caddis_glossary.py
|
|
918
|
+
|
|
919
|
+
It cannot write the definitions - only a person or the model reading the code can say what
|
|
920
|
+
a coined word MEANS here. Run `/caddis:glossary` to have them drafted, or write them.
|
|
921
|
+
|
|
922
|
+
This file is for YOUR project's vocabulary. caddis's own coined words - pool, relay, drift,
|
|
923
|
+
export target - are defined separately in `CADDIS-GLOSSARY.md` at the plugin root, which also
|
|
924
|
+
serves as a worked example of what a good entry looks like. Do not copy those terms in here.
|
|
925
|
+
|
|
926
|
+
| Term | Definition | DO NOT USE |
|
|
927
|
+
|---|---|---|
|
|
928
|
+
| _example_ | Replace this row. Say what the word means HERE, and why the ordinary reading is wrong. | the synonyms that cause confusion |
|
|
929
|
+
|
|
930
|
+
## Flagged ambiguities
|
|
931
|
+
|
|
932
|
+
Name the words that are still overloaded rather than pretending the vocabulary is clean. A
|
|
933
|
+
glossary that hides its own dirt starts lying. Delete this section only when there is
|
|
934
|
+
genuinely nothing to flag.
|
|
935
|
+
"""
|
|
936
|
+
|
|
937
|
+
|
|
905
938
|
ARTIFACT_CONFIG_EXAMPLE = """\
|
|
906
939
|
# caddis per-repo configuration — a documented template.
|
|
907
940
|
#
|
|
@@ -1198,6 +1231,20 @@ def scaffold_artifact_dir(target: Path, dry: bool) -> list[str]:
|
|
|
1198
1231
|
em.parent.mkdir(parents=True, exist_ok=True)
|
|
1199
1232
|
em.write_text(ENVIRONMENT_MAP_TEMPLATE, encoding="utf-8")
|
|
1200
1233
|
notes.append(f"scaffold: wrote {label}/kb/environment-map.md")
|
|
1234
|
+
# A vocabulary stub, seeded but never auto-filled. `caddis_glossary.py` can measure
|
|
1235
|
+
# which words a repo coined, but only a person or the model reading the code can say
|
|
1236
|
+
# what they MEAN - and a file of correct words with empty meanings looks authoritative
|
|
1237
|
+
# while teaching nothing. The stub carries the admission test so whoever fills it in
|
|
1238
|
+
# knows what qualifies.
|
|
1239
|
+
gl = root / "kb" / "GLOSSARY.md"
|
|
1240
|
+
if gl.exists():
|
|
1241
|
+
notes.append(f"scaffold: {label}/kb/GLOSSARY.md present - kept")
|
|
1242
|
+
else:
|
|
1243
|
+
if not dry:
|
|
1244
|
+
gl.parent.mkdir(parents=True, exist_ok=True)
|
|
1245
|
+
gl.write_text(GLOSSARY_TEMPLATE, encoding="utf-8")
|
|
1246
|
+
notes.append(f"scaffold: wrote {label}/kb/GLOSSARY.md (run /caddis:glossary to fill it)")
|
|
1247
|
+
|
|
1201
1248
|
gi = root / ".gitignore"
|
|
1202
1249
|
if gi.exists():
|
|
1203
1250
|
# APPEND what is missing rather than keeping the file frozen. The old behaviour was
|
|
@@ -76,6 +76,7 @@
|
|
|
76
76
|
| Feature Plan | `feature-plan/` | Create a phased, TDD-structured implementation plan that acts as the durable spine for multi-session work |
|
|
77
77
|
| Gate Preflight | `gate-preflight/` | Deterministic headless preflight — validates a plan against the actual codebase, self-contained (never depends on a skill activating) |
|
|
78
78
|
| Gate Review | `gate-review/` | Deterministic headless code review — adversarial diff review, self-contained (never depends on a skill activating) |
|
|
79
|
+
| Glossary | `glossary/` | Define the words this project invented, in one place — .caddis/kb/GLOSSARY.md |
|
|
79
80
|
| Handoff | `handoff/` | End-of-session handoff — capture exact state so the next session resumes with zero re-discovery |
|
|
80
81
|
| Implement | `implement/` | Headless plan executor — implement an approved plan phase-by-phase on the current feature branch, TDD-first, committing per phase |
|
|
81
82
|
| Kb | `kb/` | Rebuild the KB index (.caddis/kb/DOC-MAP.md) — create it if missing, index un-indexed notes, report dangling links |
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: glossary
|
|
3
|
+
description: Define the words this project invented, in one place — .caddis/kb/GLOSSARY.md
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /glossary — define what this project coined
|
|
7
|
+
|
|
8
|
+
Every project invents vocabulary out of ordinary English, and those are the most dangerous words
|
|
9
|
+
in the codebase: a reader who guesses from the plain word gets it wrong and never finds out.
|
|
10
|
+
caddis itself coined `pool`, `relay`, `drift`, `parking-lot` — and its own glossary went five and
|
|
11
|
+
a half months without mentioning any of them, because nothing measured the gap.
|
|
12
|
+
|
|
13
|
+
Your job is the half a script cannot do: **write what the words mean here.**
|
|
14
|
+
|
|
15
|
+
## Step 1 — get the candidates
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
python <caddis-plugin-root>/scripts/caddis_glossary.py
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
It ranks the words this repo says often that plain English does not, and marks which already
|
|
22
|
+
have an entry. `--scaffold` creates `.caddis/kb/GLOSSARY.md` if it is missing.
|
|
23
|
+
|
|
24
|
+
It is a **suggester, not an oracle**. It is good on an application repo — run against a kanban
|
|
25
|
+
tool it proposed `board`, `lane`, `card` at the top — and noisier on a repo whose docs are ABOUT
|
|
26
|
+
software, where words like `protocol` are both ordinary and genuinely overloaded. Expect to
|
|
27
|
+
discard some suggestions. That is the intended cost: a false positive wastes three seconds, a
|
|
28
|
+
missing term stays undefined forever.
|
|
29
|
+
|
|
30
|
+
If the script is not available, read the repo yourself and look for the same thing.
|
|
31
|
+
|
|
32
|
+
## Step 2 — apply the admission test to each candidate
|
|
33
|
+
|
|
34
|
+
A term belongs **only if its meaning here is distinct enough from its ordinary technical sense
|
|
35
|
+
that a newcomer would misread it.**
|
|
36
|
+
|
|
37
|
+
- `commit`, `branch`, `endpoint` — **no**. The ordinary meaning is correct.
|
|
38
|
+
- A word the team bent to its own purpose — **yes**. That is the whole point.
|
|
39
|
+
|
|
40
|
+
Discard the rest without comment. A padded glossary is skimmed and then ignored.
|
|
41
|
+
|
|
42
|
+
## Step 3 — write each definition from the CODE, not from the word
|
|
43
|
+
|
|
44
|
+
Read where the term is actually used before defining it. A definition that restates the word
|
|
45
|
+
teaches nothing, and a wrong one is worse than a gap because it is believed.
|
|
46
|
+
|
|
47
|
+
Each row gets three things:
|
|
48
|
+
|
|
49
|
+
| Column | What goes in it |
|
|
50
|
+
|---|---|
|
|
51
|
+
| **Term** | The canonical spelling. Pick one and stop using the others. |
|
|
52
|
+
| **Definition** | What it means HERE, and — where it helps — why the ordinary reading misleads. Say the thing a newcomer would get wrong. |
|
|
53
|
+
| **DO NOT USE** | The synonyms actually causing confusion in this repo. Leave blank rather than inventing some. |
|
|
54
|
+
|
|
55
|
+
**A worked example ships with caddis.** `CADDIS-GLOSSARY.md` at the plugin root defines caddis's
|
|
56
|
+
own coined vocabulary the same way — read a few entries before writing yours. It is caddis's
|
|
57
|
+
words, not this project's: never copy its terms into a project glossary.
|
|
58
|
+
|
|
59
|
+
Good: *"pool — the single source of every shipped resource, in `.github/`. Everything installed is EXPORTED from it; nothing is authored in a bundle."*
|
|
60
|
+
|
|
61
|
+
Bad: *"pool — a pool of resources."*
|
|
62
|
+
|
|
63
|
+
## Step 4 — flag what is still dirty
|
|
64
|
+
|
|
65
|
+
Fill the **Flagged ambiguities** section with the words that remain overloaded. This is the part
|
|
66
|
+
people skip and it is the most valuable part, because a glossary that hides its own dirt starts
|
|
67
|
+
lying.
|
|
68
|
+
|
|
69
|
+
Look for a term used in several incompatible senses. In caddis, `gate` is defined as one thing
|
|
70
|
+
and used as at least twelve — exit gate, quality gate, evidence gate, privacy gate. The honest
|
|
71
|
+
move is to name the overload and recommend the two-word form, not to pick a winner by fiat.
|
|
72
|
+
|
|
73
|
+
Also flag a term whose canonical spelling the code itself contradicts. Do not "fix" either side
|
|
74
|
+
when both are load-bearing; document the split and where each applies.
|
|
75
|
+
|
|
76
|
+
## Step 5 — report
|
|
77
|
+
|
|
78
|
+
Say how many terms you added, how many candidates you rejected and roughly why, and what you
|
|
79
|
+
flagged as ambiguous. If you found nothing worth adding, say that — it is a real answer, and
|
|
80
|
+
better than padding the file to look productive.
|
|
81
|
+
|
|
82
|
+
## Keeping it honest
|
|
83
|
+
|
|
84
|
+
Re-run `caddis_glossary.py --check` later. It exits 1 when a frequent term has no entry. It is
|
|
85
|
+
**advisory**: a project may reasonably decide a common word needs no definition, and a gate that
|
|
86
|
+
cannot be satisfied gets bypassed rather than obeyed.
|
|
87
|
+
|
|
88
|
+
Do not enforce the DO-NOT-USE column by grepping. Most banned synonyms are ordinary English —
|
|
89
|
+
"step", "block", "refuse" — and a check that cries wolf gets deleted, leaving no check at all.
|
package/bundles/manifest.json
CHANGED
package/package.json
CHANGED