diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index ca7c291..3bacce7 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1,124 +1,16 @@ { "name": "wisdom", - "version": "2.2.0", + "version": "3.0.0", "owner": { "name": "cmj", "url": "https://github.com/cmj0121" }, "plugins": [ { - "name": "shortcut", - "description": "Dispatches the skill or command whose declared magic word appears in the prompt. Use at the start of a turn to check for a registered trigger phrase, or to list the magic words available across personal, project and plugin skills.", - "version": "2.0.0", - "source": "./plugins/shortcut" - }, - { - "name": "agent-smith", - "description": "Project Leader agent — plans a piece of work, dispatches it to the scrum team and coordinates the iterations. Use to build, implement, refactor or fix something substantial, with or without a named agent.", - "version": "2.1.0", - "source": "./plugins/agent-smith" - }, - { - "name": "agent-ward", - "description": "Architect agent — designs systems and APIs and decides the tech stack. Use before implementation starts, or to weigh one library or protocol against another.", - "version": "2.1.0", - "source": "./plugins/agent-ward" - }, - { - "name": "agent-hale", - "description": "Developer agent — writes clean, maintainable code and its tests from an agreed plan. Use when implementation is the task and the approach is already settled.", - "version": "2.1.0", - "source": "./plugins/agent-hale" - }, - { - "name": "agent-ellis", - "description": "QA agent — reviews code quality and security, runs the suite, and verifies work against its acceptance criteria. Use before a change lands. Not for whole-repo audits (sec-review) or for running tests alone (test-runner).", - "version": "2.1.0", - "source": "./plugins/agent-ellis" - }, - { - "name": "agent-twain", - "description": "Technical Writer agent — writes user documentation, API references, migration guides and tutorials. Use when a change needs documenting or its docs have gone stale.", - "version": "2.1.0", - "source": "./plugins/agent-twain" - }, - { - "name": "agent-page", - "description": "SRE agent — reviews code and infrastructure for operational readiness: observability, reliability, performance, security posture. Use before a release.", - "version": "2.1.0", - "source": "./plugins/agent-page" - }, - { - "name": "agent-ross", - "description": "Release Manager agent — writes commit messages, runs CI/CD and Docker builds, deploys and tags releases. Use when finished work needs to ship. It runs the pipeline; diagnosing or fixing a failing build or test is not its job.", - "version": "2.1.0", - "source": "./plugins/agent-ross" - }, - { - "name": "spec-writer", - "description": "Writes technical specifications — requirements, interfaces, data models and architecture diagrams. Use when a design needs recording before it is built. Not for writing the code it specifies (agent-hale), nor for reviewing a spec already written (agent-ward).", - "version": "2.1.0", - "source": "./plugins/spec-writer" - }, - { - "name": "tenth-man", - "description": "Devil's advocate — challenges the assumptions behind a plan and names the blind spots a group has agreed past. Use before committing to a decision.", - "version": "2.1.0", - "source": "./plugins/tenth-man" - }, - { - "name": "ascii-grapher", - "description": "Draws ASCII diagrams for architecture, data flows, state machines and concepts. Use when a structure is easier to see than to read, or must survive in a terminal. It draws a structure that is already decided — deciding it is agent-ward's.", - "version": "2.1.0", - "source": "./plugins/ascii-grapher" - }, - { - "name": "test-runner", - "description": "Detects the project's test framework, runs its suite, and reports what passed, what failed and why. Runs tests only — it does not review the code (agent-ellis).", - "version": "2.1.0", - "source": "./plugins/test-runner" - }, - { - "name": "changelog-gen", - "description": "Generates changelog entries from git history, grouping conventional commits by type. Use when a release needs notes or a CHANGELOG has fallen behind. It writes the entries; restructuring or reformatting the CHANGELOG file itself is not its job.", - "version": "2.1.0", - "source": "./plugins/changelog-gen" - }, - { - "name": "dep-auditor", - "description": "Audits dependencies for known vulnerabilities and outdated versions across npm, pip, go, cargo and bundler. Use before a release or when a lockfile changes.", - "version": "2.1.0", - "source": "./plugins/dep-auditor" - }, - { - "name": "compactor", - "description": "Re-renders the previous result as a dense, scannable table, dropping prose framing but keeping every data point. Use when an answer was longer than it needed to be. Not for setting a standing output style, and it adds no recommendation the original answer did not contain (briefing).", - "version": "2.1.0", - "source": "./plugins/compactor" - }, - { - "name": "briefing", - "description": "Output style for planning and review agents — keeps results compact, summarises each question before answering it, and drives discussion one numbered topic at a time. Use when running agent-smith or tenth-man, or when the user asks for shorter output or to decide one thing at a time.", - "version": "2.0.0", - "source": "./plugins/briefing" - }, - { - "name": "pr-flow", - "description": "Walks a pull request from its issue to merge-ready — checks the diff against the issue body, then works each reviewer comment test-first. Merging stays with the user.", - "version": "2.1.0", - "source": "./plugins/pr-flow" - }, - { - "name": "sec-review", - "description": "Reviews source for security issues and maps each finding to a CWE — whole project by default, or the scope its caller states. Use when security is the question, not code review.", - "version": "2.1.0", - "source": "./plugins/sec-review" - }, - { - "name": "lingua", - "description": "Answers in the user's chosen language whatever language they write in, restating the question in correct terminology first. Use to set or load that preference. Not a translation service: it does not translate a file, a document or a passage on request.", - "version": "2.1.0", - "source": "./plugins/lingua" + "name": "wisdom", + "description": "Single-purpose skills to plan, build, review and ship software, led by smith.", + "version": "3.0.0", + "source": "./plugins/wisdom" } ] } diff --git a/CLAUDE.md b/CLAUDE.md index a7103fe..369fb6f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,220 +2,68 @@ Guidance for Claude Code when working in this repository. -## Project Overview +## Project -Wisdom is a Claude Code plugin marketplace: AI-agent skill plugins defined as Markdown skill -definitions (`SKILL.md`) with YAML frontmatter, not as source code. +Wisdom is a Claude Code plugin marketplace shipping one plugin, `wisdom`: single-purpose +skills written as Markdown (`SKILL.md`) with YAML frontmatter, not as code. `smith` is the +entry point and coordinates the rest. `README.md` is the roster and the design; keep +`README.zh-TW.md` in step with it. -Plugins follow PoLP (Principle of Least Power) — as declarative as they can be, relying on -Claude's language understanding rather than code logic, so the community can extend them. - -## Architecture - -### Plugin Structure - -Every plugin lives under `plugins//` and must contain: +## Layout ```text -plugins// -├── .claude-plugin/plugin.json # Metadata: name, version, license, author -├── skills//SKILL.md # AI agent instructions with YAML frontmatter -├── README.md -└── LICENSE +.claude-plugin/marketplace.json # registers the wisdom plugin +plugins/wisdom/ +├── .claude-plugin/plugin.json +├── hooks/ # lingua's SessionStart hook +└── skills// + ├── SKILL.md + └── references/ # optional, read only when the body says so +scripts/ # the checks ``` -### Skill Definitions (SKILL.md) - -Frontmatter follows the [Agent Skills standard](https://agentskills.io/specification) in two -layers, and `scripts/check-skill-spec` enforces the split. Anything outside both layers fails. - -**The standard's six** — `name`, `description`, `license`, `allowed-tools`, `metadata`, -`compatibility` — are portable to any client, including claude.ai uploads and the Skills API, -which reject an unknown key outright rather than ignoring it. Three carry rules worth stating: - -- `description`: what the skill does **and when to use it**, third person. The repo ceiling is - 320 characters and its skills average 204 — up from 173 once every one of them gained a - negative boundary clause, which is the trade that bought fewer misfires. The same string is - catalogue copy in four places: `/plugin`, `marketplace.json`, the plugin `README.md` - blockquote and the skill's own frontmatter. All four are compared; the blockquote is - line-wrapped, so an edit by exact string match reaches three of them and leaves the fourth - stale. -- `allowed-tools`: a **YAML list**, the one place this repo knowingly departs from the - standard's space-separated string. 79 of the 173 grants contain a space - (`Bash(git status:*)`), and the space-free spelling `Bash(git:*)` widens the grant from one - subcommand to all of git. Of the two remaining spellings, a comma-separated string is split - on spaces into patterns that match nothing — a permission dropped in silence — while a list - at worst reaches a consumer that cannot use it as given. The field is still typed as a - space-separated string and still marked Experimental, so it is the one to leave. Note the - claim this rests on has narrowed: as of September 2026 tools are normalising a list into a - string rather than rejecting it loudly, which is the quiet handling the list was chosen to - avoid. `CLAUDE_CODE_EXTENSIONS` in `scripts/check-skill-spec` records what would make this - decision worth revisiting. -- `metadata`: string keys to string values only — hence `version: "2.0.0"`, quoted. - -**Claude Code extensions adopted here** — each costs portability, so each records its reason -in `CLAUDE_CODE_EXTENSIONS`; a third one needs the same: - -- `model`: a tier, a full `claude-*` ID, or `inherit` (the same as omitting it). Pin downward - only. Read at session start, so a change takes effect next session. -- `context: fork` and `background: false`: a `model` pin applies for the **rest of the turn**, - so a pinned skill invoked mid-task would move the session that invoked it. Any pinned skill - an agent can reach sets both — `fork` aims the pin at a subagent, `background: false` keeps - the result inline for the caller. - -The body is phase-by-phase instructions, under 500 lines, with a warning at 300 that asks for -a judgement rather than a split. **Form decides what moves, not topic.** A list or table -carries items a run looks up one at a time — a roster, a field table, a rubric — and each row -stands alone, so it survives the move into `references/` intact. Prose carries what joins -them: the condition, the tie-break, the reason. `If both trigger types appear, prefer -Autonomous mode.` is a relation, not an item; as two bullets it becomes two assertions with -nothing between them, and the case neither covers gets improvised. So prose stays in the body -and is shortened in place — which bounds what a split can reach: of `agent-smith`'s 299 lines, -86 are table, list and heading, so moving every movable line still leaves 213, and most of -those 86 are unconditional and would only cost a fetch. A target under that is a rewrite of -the phase text, and is worth planning as one. - -Whether a procedure moves is a second, orthogonal question: unconditional or conditional. A -procedure every run needs is read anyway, one fetch later, so moving it costs a round trip and -buys nothing. A procedure only some runs need is what `references/` is for — put it there and -name the file where the condition is stated, because nothing in `references/` is read unless -the body says to read it. `agent-smith`'s Phase 5 is the example, and so far the only one: it -runs in Autonomous mode alone, so its scoring table and iteration log sit in -`references/iteration.md` and a Partner-mode dispatch never pays for them. Phase 2.5 is -conditional too and still does not qualify — at eight lines, most of them the condition -itself, the fetch would cost more than the lines it saves. - -### Skill Discovery (Three Tiers) - -1. User-level: `~/.claude/skills/`, `~/.claude/commands/` -2. Project-level: `.claude/skills/`, `.claude/commands/` -3. Plugin-bundled: `plugins/*/skills/` +## Writing a skill + +- **One purpose.** A skill that needs a second job calls the skill that owns it, as + `wisdom:`. Name it after its purpose, a verb or a noun, never a persona. +- **Frontmatter:** `name` (matches the directory), `description`, `license`, optional + `allowed-tools` (a YAML list — a grant like `Bash(gh pr view:*)` contains a space, which a + space-separated string cannot hold), and `metadata.shortcut` for magic words + (comma-separated, unique across the plugin; omit when no word is needed). Nothing else: + no per-skill version, no `model` pin. +- **Description:** third person, what it does and when to use it, ≤ 160 characters — it is + loaded in every session. +- **Body:** ≤ 100 lines (`smith` ≤ 150) — it is read in full each run. Only what some runs + need goes to `references/`, linked where the condition is stated. +- **Machine-readable result:** a skill another skill routes on ends in one fixed line + (`VERDICT:`, `RESULT:`, `SECURITY:`, `AUDIT:`, `OPS:`), always emitted, so its absence + means the skill did not run. +- **README:** add the skill to the `## Skills` tables of both READMEs, magic words included. ## Checks -`make test` runs four and reports all four rather than stopping at the first failure: -`scripts/test` (structure), `scripts/check-version-sync` (versions), `scripts/validate` -(semantics), `scripts/check-skill-spec` (the standard). Run it before handing work back. Those -same four run on every commit, ungated — pre-commit's candidate list excludes deletions, so a -path-gated hook sees nothing on a deletion-only commit and is skipped. - -Two more sit outside `make test`: +`make test` runs four checks and reports all of them; run it before handing work back. +pre-commit runs the same four on every commit, plus `scripts/validate-fixtures` when +`scripts/` changes; CI runs all five on every push. -- `scripts/validate-fixtures`, the negative-fixture self-test for `validate` and - `check-skill-spec`. Run it after editing either. It is the one hook still path-gated (on - `^scripts/`), so the commit path runs it and `make test` does not. -- `scripts/check-install-drift`, run by hand from `make doctor`. It reports a skill this repo - ships that the local `~/.claude/skills` also serves — a stale copy there outranks the - installed plugin, so every trigger eval here measures a description the session may never - have loaded. It asserts on the machine, not the repo; in CI there is no `$HOME/.claude`, so - it would pass for the wrong reason. Run it when a skill behaves like an older version of - itself. +| Script | Fails when | +| ---------------------------- | ---------------------------------------------------------------- | +| `scripts/test` | a required file is missing or a manifest name disagrees | +| `scripts/check-version-sync` | plugin versions disagree, or the release lags the latest tag | +| `scripts/validate` | a magic word repeats, a README table drifts, a reference dangles | +| `scripts/check-skill-spec` | frontmatter breaks the Agent Skills standard or the budgets | -CI (`.github/workflows/checks.yml`) runs all five plus the full pre-commit suite on every push -and pull request. +Run `bash scripts/validate-fixtures` after editing `validate` or `check-skill-spec`: it +breaks a temp copy one way at a time and asserts each check notices. `make doctor` reports a +local `~/.claude/skills` copy that shadows a shipped skill. -What that means for edits here: +Green checks do not prove the prose is right; a stale sentence still needs reading. -- A version bump touches three files at once: `marketplace.json`, the plugin's `plugin.json`, - and the skill's `metadata.version`. Never one alone. A release also bumps the **top-level** - `version` in `marketplace.json`, which must not lag the latest `v*` tag — a fourth location - and a separate check. -- A bump tracks what the plugin **does** — its `SKILL.md` body. A change confined to the - `description`, or to the README blockquote, `plugin.json` and marketplace entry that mirror - it, is catalogue copy: the router matches on it, but nothing the plugin does afterwards is - different, so it moves the **top-level** `version` alone. Frontmatter that declares a - contract the skill already honoured — `metadata.verdict` is the case at hand — is not a - behaviour change either. And a plugin moves at most once per release window: between one - `v*` tag and the next, a plugin already bumped is not bumped again, or the number stops - naming a released state and starts counting pull requests. -- A plugin's `description` must read identically in `marketplace.json`, its `plugin.json` and - its `SKILL.md` frontmatter. -- A skill that hands another a machine-readable block declares that marker in - `metadata.verdict`. The check runs both ways: a shown block must be declared, a declared - marker must appear as a block carrying at least one `Field: value` line, and a marker routed - on must be one some skill here emits. Five exist — `__REVIEW_VERDICT__`, `__OPS_VERDICT__`, - `__TEST_RESULT__`, `__AUDIT_RESULT__`, `__SEC_REVIEW_RESULT__`. Inside a fence reads as - emitted; the same token in prose backticks reads as routed on. -- Every skill declares its magic words in `metadata.shortcut`, a comma-separated string - (`shortcut` itself is the sole exception), and they must be unique across all plugins. The - `## Shortcut` section spells each declared word out in backticks for human readers; that - section is documentation, so an extra backtick span there is ordinary prose. -- A plugin README documents exactly the magic words its skill declares — no extras, none - missing — and keeps its H1, `## Installation` and `## License` sections. Under its Magic - Words heading, and only there, EVERY backtick span is read as a magic word, so write - anything else there without backticks. That section ends only at a heading of the same or - higher level, so its subsections are still inside it; a fence there is stripped first. -- A plugin registered in `marketplace.json` must also be named in the top-level `README.md` - prose; a mention only inside a code fence does not count. -- Write a `:` reference only when both halves exist in this repo. -- Every plugin carries `evals/trigger-queries.json`: 20 labelled prompts, half of them - near-misses, split train/validation. Rewriting a `description` means re-running them — tune - on train, judge on validation. `scripts/validate` fails a plugin with no such file, one that - labels every query the same way, one that never splits off a validation half, and one whose - positive queries carry another plugin's magic word: a negative that does is the near-miss, a - positive that does is two skills racing. All 380 of these stay the cheap record — they cost - nothing, run offline, and a rewrite can be judged against them with no runner at all: hand - the frontmatter to a model, ask it for prompts that should and should not fire, and compare - those against the labels already in the file. What they are not is executable, so on their - own they state an intent rather than a passing test. -- `make eval` is the executable half, and it deliberately covers 13 of those 380. The runner - is `claude plugin eval`, which is generally available — no opt-in flag, whatever an older - paragraph here may have said — but each case is a full Claude child session on the - operator's own credential, so it wants a network and real money where the four checks want - neither. That is why it sits outside `make test` for `check-install-drift`'s reason, and why - CI cannot run it: `.github/workflows/checks.yml` carries `permissions: contents: read` and - no secrets, and putting a credential in a public repo to automate a check a human can run by - hand is a bad trade. The 13 are the misses from a 3-sample blind-router baseline over the - whole corpus, which scored 367/380 — the boundaries that actually move, rather than a - sample. Converting the other 367 would buy repetition at a measured $0.142 a run: the 13 at - `runs: 3` come to about $5.50, where all 380 would be roughly $54 at one run each and $324 - at the two-arm default with three. -- A case is `evals//prompt.md` plus a `graders/` directory, where a grader of - `type: tool_used`, `tool: Skill`, `input_match: '"skill"\s*:\s*"'` and `min: 1` asserts - the skill fired and `min: 0` with `max: 0` asserts it did not. Leave the closing quote off - that pattern — it is the spelling measured to match, it still covers a namespaced - `plugin:skill` value, and no skill name here is a prefix of another, so it cannot over-match. - Pass `--ablation none`, because under the default the CLI stops scoring a `tool_used: Skill` - grader and demotes it to a with-only indicator. Two things decide whether a case measures - anything. **A bare query does not fire a skill**: `what are we not seeing here` is a labelled - `tenth-man` positive and it produced `Skill called 0x` with the plugin loaded, while the same - words wrapped in a turn with something to act on — a team that agreed a monorepo move inside - ten minutes, and what are we not seeing — fired first try. So a case is the labelled query - rewritten as a real turn, keeping its intent and vocabulary but never its skill's own - description wording, and a 1:1 migration of the bare queries would measure something else and - mostly fail. **And a skill its owner invokes cannot be graded silent**: `agent-ward` calls - `ascii-grapher` and `spec-writer` itself, so asserting either stayed quiet fails the runs that - routed correctly. Rule out the second skill only where it is not downstream of the first; - where it is, say so in the surviving grader's prose, which the report prints. -- A skill should fire when the request needs something the assistant cannot do unaided — - persist state to a file, run a tool, coordinate other agents, emit a machine-readable - verdict. Where the assistant can simply comply in the current turn, nothing fires, and that - is the right outcome rather than a defect: a trigger-eval positive that expects one is - mislabelled, and no description edit will fix it. The evidence sits inside one plugin's own - results, which is what makes it more than plausible. `lingua`'s - `restate my question before you answer it` passes 3/3 — complying means writing - `refine_question` into a config file, which the assistant cannot do by itself. Its - `stop refining my questions` fires nothing, 0/3, because complying means not doing something, - in this turn. Same skill, same vocabulary, opposite results, so the discriminator is not how - near the wording sits to the description but whether anything has to happen that the - assistant cannot do alone. That reading covers three of the other four failures too: - `briefing`'s two and `agent-hale`'s _the plan is agreed — write it_ all ask for something the - assistant just does. -- The two runners answer different questions, so a disagreement between them is not a tie. The - blind router shows a model only the 19 `name` + `description` pairs and makes it pick exactly - one skill or `none` — free, offline, all 380 queries, but a **forced choice**: given nineteen - candidates it returns the nearest description even where a real session would invoke nobody, - so its "skill A steals from skill B" verdicts overstate. `make eval` instead observes whether - the `Skill` tool was invoked at all, at $0.142 a run over 13 of the 380. The measurement that - separates them: in all five failing cases the `fires` grader reported `Skill called 0x`, and - in every case carrying an exclusion grader the rival reported `0x` as well and the exclusion - passed — the blind router had `compactor` taking both of `briefing`'s queries 3/3 and - `spec-writer` taking `the plan is agreed -- write it` 3/3, and in a real session neither - fires at all. So **a blind-router miss is a hypothesis; a `make eval` miss is an - observation**: do not edit a description on the former alone when a case can be written for - the latter. The blind router's noise floor is about two queries per plugin at three samples — - plugins nobody touched moved that much between runs — so a swing smaller than that is not a - finding either. +## Versions and releases -Passing checks only prove nothing mechanically checkable is broken. Prose accuracy — a stale -table row, a wrong command name — is not covered and still needs review. +- One version, in two places that must agree: the plugin's entry in `marketplace.json` and + `plugins/wisdom/.claude-plugin/plugin.json`. The top-level `version` in `marketplace.json` + must not lag the latest `v*` tag. +- Bump the plugin when what a skill does changes; a description-only edit bumps the + top-level version alone. At most one plugin bump between two tags. +- Never tag or release without the user asking. diff --git a/Makefile b/Makefile index 18cca87..d41998a 100644 --- a/Makefile +++ b/Makefile @@ -38,29 +38,12 @@ test: # run the four repo checks (not the validator self-test) printf '==> %d of %d checks FAILED -- re-run with WISDOM_VERBOSE=1 for per-item detail\n' "$$failed" "$$total"; \ exit 1 -# Deliberately NOT part of `test`, for `doctor`'s reason and then some: every -# case here is a full Claude child session on the operator's own credential, so -# it wants a network and real money where the four checks want neither. CI is -# not an option either -- .github/workflows/checks.yml runs with -# `permissions: contents: read` and no secrets, and adding one to a public repo -# to automate a check a human can run by hand is a bad trade. -# -# --ablation none is not a speed knob. Under the default with-without ablation -# the CLI demotes a `tool_used: Skill` grader to a with-only indicator and stops -# scoring it -- and that grader is the only thing these cases assert. -# --no-publish keeps the HTML report off claude.ai, because a check in this repo -# uploading its results is a surprise nobody asked for. -# -# The CLI takes one plugin per invocation, so the list is derived from the cases -# on disk rather than written out: a case added under a new plugin needs no edit -# here, and a plugin with no cases is never invoked. The ceiling is therefore -# per plugin -- the largest set today is 4 cases x 3 runs, about $1.70 at the -# measured $0.142 a run, and all 13 cases together come to roughly $5.50. -# -# Like `test`, it runs every plugin even after one fails and fails at the end: -# a routing regression in the first plugin is no reason to leave the other -# eight unmeasured once the money is already committed. -eval: # run the committed trigger cases (needs a credential, a network and ~$5.50) +# Deliberately NOT part of `test`: every case is a full Claude child session on +# the operator's own credential, so it wants a network and real money, and CI +# has no secret to give it. --ablation none keeps a `tool_used: Skill` grader +# scored; --no-publish keeps the report off claude.ai. Plugins without cases +# under evals/ are never invoked. +eval: # run the committed trigger cases (needs a credential and a network) @failed=0; \ for plugin in $$(find plugins -path '*/evals/*/prompt.md' | cut -d/ -f1-2 | sort -u); do \ printf '\n==> %s\n' "$$plugin"; \ diff --git a/README.md b/README.md index 6dfed0c..e55f2e0 100644 --- a/README.md +++ b/README.md @@ -1,371 +1,127 @@ # Wisdom -> Help your Claude Code more efficiently and effectively, like me +> Help your Claude Code work more efficiently and effectively, like me -This project is the collection of Claude Code plugins I use, and you can use it the way I do. +[繁體中文](README.zh-TW.md) -## Installation +Wisdom is the set of Claude Code skills I use every day, packaged as one plugin so you can use +them the way I do. -Add the wisdom marketplace to your Claude Code and install the plugin. +## Installation ```bash /plugin marketplace add cmj0121/wisdom +/plugin install wisdom@wisdom ``` -## AI Scrum Team +## Concept -Wisdom organizes AI agents into a scrum team that collaborates to deliver software. Each agent -has a clear role, responsibility boundary, and reporting chain. +v3 is a rewrite from scratch around three rules. -### Core Roles +1. **One skill, one purpose.** Each skill does one thing and is named after it. A skill that + needs a second job calls the skill that owns it instead of growing one. +2. **Shortcuts where they help.** Every skill runs with `/wisdom:`. A skill used often + enough to type in passing also declares a magic word — say `smith` and the dispatcher + starts the lead skill. Words are unique across the plugin. +3. **Fewer tokens.** A description is loaded in every session, so it stays one short + sentence. A body is loaded each time its skill runs, so it stays short too; anything only + some runs need lives in `references/` and is read only then. No personas, no role-play + framing, no repeated project discovery: the plan file carries the context forward. -| Role | Agent | Responsibility | -| -------------------- | ------------- | -------------------------------------------------------- | -| **Project Leader** | `agent-smith` | Plan, dispatch, coordinate sprints, manage git lifecycle | -| **Architect** | `agent-ward` | System design, API design, tech stack decisions | -| **Developer** | `agent-hale` | Implement code, write tests | -| **QA** | `agent-ellis` | Code review, test execution, acceptance verification | -| **Technical Writer** | `agent-twain` | User docs, API docs, migration guides | -| **SRE** | `agent-page` | Observability, reliability, performance review | +## Skills -### Optional Role +`smith` is the entry point. Tell it what you want built and it plans the work, then calls the +other skills in turn. Every skill also works on its own. -| Role | Agent | Responsibility | -| ------------------- | ------------ | -------------------------------------------------- | -| **Release Manager** | `agent-ross` | CI/CD, Docker build, cloud deploy, release tagging | +### Lead -### Support Tools +| Skill | Purpose | Magic word | +| ------- | --------------------------------------------------------------- | ---------- | +| `smith` | Drive a piece of work from idea to merge using the skills below | `smith` | -| Tool | Description | Available To | -| --------------- | ------------------------------------------------ | ------------------------------------ | -| `spec-writer` | Technical specs with architecture diagrams | agent-ward, agent-twain | -| `tenth-man` | Challenges assumptions and surfaces risks | agent-smith, agent-ward | -| `ascii-grapher` | ASCII diagrams for architecture, flows, concepts | agent-ward, agent-twain, agent-page | -| `test-runner` | Detects test framework and runs test suite | agent-hale, agent-ellis, agent-page | -| `changelog-gen` | Generates changelog from git history | agent-ross, agent-twain | -| `dep-auditor` | Audits dependencies for vulns and outdated pkgs | agent-ellis | -| `sec-review` | Security scan mapped to CWE IDs | agent-ellis (diff), agent-ross (all) | +### Build -### Utilities +| Skill | Purpose | Magic word | +| -------- | ----------------------------------------------------------- | ------------- | +| `plan` | Turn an idea into `PLAN.md`: goal, units of work, decisions | `plan it` | +| `design` | Decide an architecture, API or tech choice, with trade-offs | `design it` | +| `spec` | Write a technical specification for an agreed design | `write spec` | +| `code` | Implement one unit of work with its tests | `code it` | +| `test` | Run the project's test suite and report the result | `run tests` | +| `review` | Review a diff for correctness and quality | `review it` | +| `docs` | Write or update user-facing documentation | `document it` | -Standalone plugins, not part of the scrum chain. Each works on its own. +### Ship -| Tool | Description | -| ----------- | ------------------------------------------------------------------------- | -| `shortcut` | Auto-dispatches a skill when your prompt contains its magic word | -| `compactor` | Re-renders the previous result as a dense, scannable table | -| `lingua` | Replies in the language you choose, remembered per project | -| `briefing` | Compact output and one-topic-at-a-time discussion for smith and tenth-man | -| `pr-flow` | Gates a PR on its issue, aligns the diff, works reviews test-first | +| Skill | Purpose | Magic word | +| ----------- | ------------------------------------------------------- | --------------- | +| `commit` | Write a commit message for the staged change and commit | `commit it` | +| `changelog` | Generate changelog entries from git history | `gen changelog` | +| `release` | Bump the version and tag a release — only when asked | `release it` | +| `resolve` | Work a pull request's review comments, test first | `resolve pr` | -### Workflow +### Check -```text - ┌──────┐ idea ┌─────────┐ challenge ┌───────────┐ - │ user │─────────>│ smith │<───────────>│ tenth-man │ - └──────┘ └────┬────┘ verdict └───────────┘ - │ - │ PLAN.md — Context · Units of Work · Decisions · Iteration Log - │ - ┌───────────────────┼────────────────────┬─────────────────────┐ - │ design │ dispatch │ docs · ops │ release (optional) - ▼ ▼ ▼ ▼ -┌─────────┐ ┌───────────────┐ ┌───────────┐ ┌─────────┐ -│ ward │─────>│ hale ×N │ │ twain │ │ ross │ -│ │ │ worktrees │ │ page │ │ │ -└────┬────┘ └───────┬───────┘ └───────────┘ └─────────┘ - ▲ │ - │ ▼ - │ ┌───────────────┐ - │ │ ellis │ - │ └───────┬───────┘ - │ redesign │ fix → re-dispatch hale - └───────────────────┘ -``` +| Skill | Purpose | Magic word | +| ----------- | ---------------------------------------------------------- | ------------ | +| `secure` | Review source for security issues, mapped to CWE | `sec review` | +| `audit` | Audit dependencies for known vulnerabilities and staleness | `audit deps` | +| `ops` | Review operational readiness before a release | `ops review` | +| `challenge` | Argue against a plan and name its blind spots | `tenth man` | -Smith plans first, writing `PLAN.md` as the run's shared memory, then dispatches -**independent units to parallel hale instances**, each in an isolated git worktree. Ellis -reviews each unit as it lands. After QA passes, smith merges the worktrees back -sequentially, then runs docs and ops in parallel before the release step. +### Output -### Verdict Routing +| Skill | Purpose | Magic word | +| ---------- | --------------------------------------------------------- | ---------------- | +| `diagram` | Draw an ASCII diagram of a decided structure | `draw a diagram` | +| `compact` | Re-render the previous answer as a dense table | `compact it` | +| `brief` | Keep answers short and discuss one topic at a time | `brief me` | +| `lingua` | Answer in your chosen language, remembered per project | `reply in` | +| `shortcut` | Dispatch the skill whose magic word appears in the prompt | — | -No agent talks to another directly. Every finding returns to smith, which decides where it -goes next — this is what keeps a review from turning into a side conversation between two -agents that smith cannot see. +## How smith runs ```text - ┌───────┐ __REVIEW_VERDICT__ ┌───────┐ implementation-level ┌──────┐ - │ ellis │──────────────────────>│ smith │─────────────────────────>│ hale │ - └───────┘ FAIL · WARN └───┬───┘ └──────┘ - │ design-level ┌──────┐ - └─────────────────────────────>│ ward │ - └──────┘ + idea ──> smith ──> plan ──> (design) ──> code ×N ──> review ──> docs ──> commit + │ │ ▲ │ + │ └── challenge └── fix ────┘ + │ + └── release · only when you ask ``` -Page reports the same way with `__OPS_VERDICT__` (READY · CONCERN · BLOCK), and smith -dispatches hale for fixes when it blocks. - -Each marker is declared in its emitter's `metadata.verdict`, and `scripts/validate` closes the -loop from both ends: a skill that shows a verdict block must declare it, a declared verdict -must appear as a block with fields in it, and a marker one skill routes on must be one another -skill emits. The five are `__REVIEW_VERDICT__` (ellis), `__OPS_VERDICT__` (page), -`__TEST_RESULT__` (test-runner), `__AUDIT_RESULT__` (dep-auditor) and `__SEC_REVIEW_RESULT__` -(sec-review). Renaming one used to be a silent failure: the caller reads no verdict and -proceeds as though the findings were empty, which is the worst default available. - -## Model Tiers +- `plan` writes `PLAN.md` once — context, units, decisions — and every later skill reads it + instead of rediscovering the project. +- Independent units run in parallel, each `code` in its own git worktree. +- `review` returns a one-line verdict; `smith` routes a failure back to `code` (or to + `design` when the design is at fault). +- `smith` stops for you twice: to approve the plan, and to approve the merge. It never tags + or releases unless you ask. -A skill declares a `model` in its `SKILL.md` frontmatter only to run mechanical work on a -cheaper model. Nothing here pins upward: reasoning-heavy skills inherit whatever model the -session already runs on, so the user's own choice — not the marketplace — decides how much -model a plan or a review gets. +## Token budget -- **Default (inherit)** — everything not listed below, including the reasoning-heavy skills: - `agent-smith`, `agent-ward`, `agent-hale`, `agent-ellis`, `agent-twain`, `agent-page`, - `agent-ross`, `spec-writer`, `tenth-man`, `sec-review` -- **Economical (`haiku`)** — mechanical, deterministic, high-frequency: - `changelog-gen`, `ascii-grapher`, `test-runner`, `dep-auditor`, `compactor`, `shortcut`, `lingua` - -`model` accepts `fable` / `opus` / `sonnet` / `haiku`, a full model ID, or `inherit`; omitting -the field means the same as `inherit`. Changes take effect on the next session — skill -frontmatter is read at session start. - -A pin applies for the rest of the turn, not just while the skill runs, so a skill an agent -invokes mid-task would move the session that invoked it. The four an agent can reach — -`ascii-grapher`, `test-runner`, `changelog-gen`, `dep-auditor` — therefore also set -`context: fork`, which aims the pin at a forked subagent instead, and `background: false`, so -their caller still gets the result in the same turn. `compactor`, `shortcut` and `lingua` pin -bare: you invoke those yourself, so the only turn they move is their own. +| Part | Loaded | Budget | +| ----------------- | ------------------------ | ------------------------------ | +| `description` | every session | one sentence, ≤ 160 characters | +| `SKILL.md` body | each time it runs | ≤ 100 lines (`smith` ≤ 150) | +| `references/*.md` | only when a run needs it | no limit, one topic per file | ## Development -Plugins are markdown and JSON, so there is no build step — what keeps the marketplace -coherent is four checks, each owning one failure domain. The last of them measures the repo -against the [Agent Skills standard](https://agentskills.io/specification). - -| Check | Domain | Fails when | -| ---------------------------- | ----------------- | ---------------------------------------------------------------- | -| `scripts/test` | structural | a required file is missing, or a manifest name/version disagrees | -| `scripts/check-version-sync` | version integrity | a plugin's three versions disagree, or the release lags its tag | -| `scripts/validate` | semantic | a reference, model, magic word, description, section or roster | -| `scripts/check-skill-spec` | standard | a `SKILL.md` breaks the Agent Skills standard | - -They stay four scripts rather than one because they fail for different reasons — a missing -file is a packaging mistake, a version drift is a release mistake, an unresolved skill -reference is an authoring mistake, an unknown frontmatter field is a portability mistake — -and because each is worth running on its own while you fix that one class of problem. - -A fifth script, `scripts/validate-fixtures`, is the self-test for the last two: it mutates a -throwaway copy of the repo to break each check in turn and asserts the check catches it. It -stays out of `make test` — a suite of checks and the proof those checks can still fail are -different jobs. - -A sixth, `scripts/check-install-drift`, is the only one that asserts on the machine rather -than on the repo: it reports a skill shipped here that the local `~/.claude/skills` also -serves. A leftover copy there does not replace the installed plugin — both are offered, as -`` and `:` — so the model chooses between two routers whose descriptions -have since diverged, and every trigger eval in this repo measures a description the session -may never have loaded. It runs from `make doctor`, by hand, and from nowhere else: there is no -`$HOME/.claude` in CI, where it would pass for the wrong reason, and a contributor's own -skills are not this repo's business. +Skills are Markdown with YAML frontmatter following the +[Agent Skills standard](https://agentskills.io/specification); there is no build step. ```text - ┌─ scripts/test structural - make test ──────────┐ │ - │ ├─ scripts/check-version-sync version integrity - git commit ──┬──────┼────>┤ - (pre-commit) │ │ ├─ scripts/validate semantic - CI ──────────┤ └ │ - │ └─ scripts/check-skill-spec Agent Skills standard - │ - └──────────────> scripts/validate-fixtures self-test - (pre-commit: only when scripts/ changes; CI: always) - - make doctor ────────────────> scripts/check-install-drift local install drift - (by hand only: it reads $HOME, not the repo) +plugins/wisdom/ +├── .claude-plugin/plugin.json +└── skills// + ├── SKILL.md + └── references/ # optional ``` -`make test` runs the first four and reports all four; it does not stop at the first failure. -It never runs `scripts/validate-fixtures`. Committing runs all five: the same four -unconditionally, plus the fixtures self-test whenever a file under `scripts/` changes. CI runs -all five unconditionally. So a green `make test` says nothing about whether the checks' own -tests still hold. - -Four of the five are deliberately ungated, and the reason is worth knowing before you add a -`files:` pattern of your own. pre-commit builds its candidate file list with -`--diff-filter=ACMRTUXB`, which excludes deletions, so a commit that only _deletes_ a file -presents zero candidates — and a gated hook with nothing to match is skipped, however exactly -its pattern would have fitted the deleted path. Deleting `plugins//LICENSE`, the -top-level `README.md`, or a check script is precisely what the structural, version and -semantic and standard checks exist to catch, so all four run on every commit regardless of -what you touched. - -### What belongs in a skill body - -A body is read in full every time its skill fires, so it has a budget: under 500 lines, with a -warning at 300 that asks for a judgement rather than a split. - -What moves into `references/` is decided by form, not by topic. A list or table carries items -a run looks up one at a time — a roster, a field table, a rubric — and each row stands alone, -so it survives the move intact. Prose carries what joins them: the condition, the tie-break, -the reason. `If both trigger types appear, prefer Autonomous mode.` is a relation, not an -item; written as two bullets it becomes two assertions with nothing between them, and the case -neither covers gets improvised. So prose stays in the body and is shortened in place. - -That also bounds what a split can achieve. Of `agent-smith`'s 299 body lines, 86 are table, -list and heading, so moving every movable line still leaves 213 — and most of those 86 are -read on every dispatch, so moving them would buy a fetch rather than a saving. A target under -that is a rewrite of the phase text rather than a move, worth planning as one. - -Whether a procedure moves is a second question, orthogonal to the first: is it unconditional -or conditional? A procedure every run needs is read anyway, one fetch later, so moving it -costs a round trip and buys nothing — and risks not being read at all. A procedure only some -runs need is what `references/` is for. Put it there, and name the file at the point the -condition is stated: loading is just-in-time, so nothing in `references/` is read unless the -body says to read it. - -`agent-smith`'s Phase 5 is the example. It runs in Autonomous mode only, so its scoring table -and iteration log sit in `references/iteration.md`, and a Partner-mode dispatch never pays for -them. That is the shape `references/` exists for, and this repo's own machinery for it — -resolved links, a required `## Contents` past 100 lines, no nesting — has exactly that one -user so far. Phase 2.5 is conditional too and still does not qualify: at eight lines, most of -them the condition itself, the fetch would cost more than the lines it saves. - -### Trigger evals - -A skill only helps if it activates, and the `description` is the only thing Claude has at the -moment it decides. It is also the only part of a skill loaded on every session, whether or -not the skill ever fires, so a description here stays well under the 320-character ceiling: -they average 204 — long enough to say what the skill does, when to use it and what it is -_not_ for, short enough that all 19 together cost a session about 1,000 tokens. Every plugin -carries `evals/trigger-queries.json`: 20 labelled prompts, ten that should activate the skill -and ten near-misses that share its vocabulary but need something else. Split 60/40 into train -and validation, so a reworded description is tuned on one half and judged on the other rather -than fitted to the phrasings used to tune it. `scripts/validate` fails a plugin that carries -no such file. - -The scrum agents carry one too. They used to be exempt on the grounds that `agent-smith` -dispatches them rather than a prompt triggering them, and that each is the next one's nearest -near-miss. The first half holds for only part of their traffic — every one of them declares -magic words a user can type. The second half was the argument turned around: being each other's -nearest near-miss is what makes the discrimination worth testing, so their negatives are drawn -from their siblings. `agent-ellis` must not answer "write tests for this"; `agent-ross` must -not answer "generate the changelog". - -A runner is committed now. `make eval` drives `claude plugin eval` — generally available, not -early access — over a suite of committed cases: one for each query that a 3-sample -blind-router run over all 380 actually missed, thirteen of them. It stays outside `make test` -for the reason `scripts/check-install-drift` already established here, only sharper: every -case is a full Claude child session on your own credential, so it wants a network and about -$5.50, and CI has no secret to give it. The other 367 queries are deliberately not converted, -and not only for the money — a bare query does not fire a skill at all, so a case is the -labelled query rewritten as a realistic turn, which is a different measurement from the one -the JSON file makes. - -That file stays the cheap half, and it has other readers: `skillgrade` runs a labelled set -like this one and exits non-zero when the pass rate falls below a threshold, `skillsbench` -measures whether a skill helps an agent at all rather than whether it fires, and the cheapest -check needs no tool — hand the frontmatter to a model, ask it for three prompts that should -fire and three that should not, and compare those against the labels already in the file. - -So a reworded description has a validation path before it lands: thirteen boundaries it can be -run against, and 380 labels it can be read against. - -Only `scripts/validate-fixtures` stays gated, on `^scripts/`: it costs a few seconds and says -nothing new unless a check changes. That gate has the same blind spot — deleting -`scripts/validate` presents no `scripts/` file either — which is why `scripts/test` asserts -that all six check scripts exist and are executable, and why CI runs the fixtures every time. -`scripts/check-install-drift` needs that entry most of all: nothing but `make doctor` ever -runs it, so nothing else would notice it had gone. - -### What the semantic validator enforces - -When you add or edit a plugin, this is the check to know about. It enforces: - -- **Shortcut section** — every skill declares its magic words in a `## Shortcut` section, in - backticks, on a line reading ``prompt contains `word` ``. `shortcut` itself, the - dispatcher, is the only exception. -- **Unique magic words** — no two plugins may claim the same word, and the plugin README's - magic-word list must name exactly what its skill declares, no more and no fewer. -- **README sections** — every plugin README needs an H1 title, `## Installation` and - `## License`. -- **Plugin roster** — every plugin registered in `.claude-plugin/marketplace.json` must be - named in the prose of this top-level README. Prose only: a name that appears solely inside - a fenced code block does not count, because a name in a diagram is not a roster entry. -- **Resolvable references** — a `:` reference in a skill body must point at a - plugin and skill that exist here, or at a known external plugin. -- **Known model tiers** — `model:` must be `fable`, `opus`, `sonnet`, `haiku` or a full - `claude-*` model ID; omit the field to inherit the session default. -- **Agreeing descriptions** — a plugin's one-sentence `description` must read identically in - `.claude-plugin/marketplace.json`, its `plugin.json` and its `SKILL.md` frontmatter. It is - the one piece of prose a plugin repeats verbatim, so the one that can be compared at all. -- **Balanced code fences** — an unterminated fence hides everything after it from the checks. -- **Trigger evals** — every plugin carries `evals/trigger-queries.json`, naming its own skill, - labelled both ways, split both ways, and not so nearly all positives that it could never - catch an over-eager description. A positive query may not carry another plugin's magic word: - a negative that does is the near-miss the set exists for, but a positive that does means both - skills are meant to fire, so whichever wins decides nothing. -- **Verdict contracts** — a skill showing a `__MARKER__` block declares it in - `metadata.verdict`; a declared marker appears as a block with `Field: value` lines in it; - and a marker one skill routes on is one another skill emits. A marker inside a fence is read - as emitted, the same token in prose backticks as routed on. - -### Backticks are reserved - -Two places in this repo are read as declarations rather than as prose: - -- the `## Shortcut` section of any `SKILL.md` -- the Magic Words heading of any plugin `README.md` - -Inside those two sections, **every backtick span is taken as a magic word** — not only the -ones in the `prompt contains` line. Put a filename, a tool name or a skill reference in -backticks there and you have declared it as a trigger word; the validator then reports it as -an undocumented magic word, or as a collision with whichever other plugin also mentioned it. -This is not hypothetical: `plugins/lingua/README.md` had to unwrap two ordinary prose -backticks under its Magic Words heading for exactly this reason. - -So in those two sections, write anything that is not a trigger word without backticks. -Backticks are normal everywhere else in the same file, but the sections reach further than -they look: one ends only at a heading of the _same or higher_ level, so a `### Additional -Triggers` nested under `## Shortcut` is still inside it. - -A code fence is not a way out of the rule. Nothing in a `## Shortcut` section needs one, and a -fence there used to swallow a declaration without a word, so the validator now rejects any -backtick span — and any `prompt contains` line — inside a fence in that section, whether or -not it was meant as a trigger. - -The over-collection is deliberate. Collecting too few words would hide a real collision -behind a green tick; collecting too many fails loudly and takes one edit to fix. - -### Versions and self-tests - -`scripts/check-version-sync` reads four version locations, in two independent checks with two -different failure modes. - -Three of them must be identical, per plugin: its entry in `.claude-plugin/marketplace.json`, -its own `plugin.json`, and its skill's `metadata.version`. Bump them together or the sync -check fails. - -The fourth is the **top-level** `version` in `.claude-plugin/marketplace.json` — the -marketplace's own release number, not any plugin's. It is compared against the latest `v*` git -tag: equal means released, ahead means a release is being prepared, behind is an error. A -plugin bump that leaves it alone is the usual way to hit this one, so cutting a release means -bumping this field too. - -`scripts/validate-fixtures` is outside `make test`, but the commit path runs it whenever -anything under `scripts/` changes. Run it by hand while you edit `scripts/validate`, rather -than finding out at commit time that a check can no longer be made to fail. - -### What the checks cannot tell you - -Green checks mean nothing _mechanically_ checkable is broken. They cannot tell you the prose -is right: a stale table row, a wrong slash command name or an inaccurate description passes -every one of them. That stays a matter of reading it. +Run `make test` before a commit — it checks the layout, the version sync, frontmatter against +the standard, and that magic words are unique. ## DDD (Dream-Driven Development) -This project follows the DDD (Dream-Driven Development) methodology, which means the project -is driven by what I envision. - -All features are based on my needs and my dreams. +This project follows DDD (Dream-Driven Development): it is driven by what I envision. Every +feature comes from my own needs and my own dreams. diff --git a/README.zh-TW.md b/README.zh-TW.md new file mode 100644 index 0000000..7446e9f --- /dev/null +++ b/README.zh-TW.md @@ -0,0 +1,121 @@ +# Wisdom + +> 讓你的 Claude Code 像我一樣,做事更有效率、更有成效 + +[English](README.md) + +Wisdom 是我每天在用的 Claude Code skill 合集,打包成單一 plugin,讓你能照我的方式使用。 + +## 安裝 + +```bash +/plugin marketplace add cmj0121/wisdom +/plugin install wisdom@wisdom +``` + +## 核心概念 + +v3 從零重寫,圍繞三條規則。 + +1. **一個 skill,一個目的。** 每個 skill 只做一件事,並以該件事命名。需要第二項工作時, + 呼叫負責那件事的 skill,而不是自己長出新職責。 +2. **需要時才用 shortcut。** 每個 skill 都能以 `/wisdom:` 執行。常用到會順口說出的 + skill 另外宣告 magic word——例如說 `smith`,dispatcher 就會啟動主導 skill。magic word 在 + 整個 plugin 內不得重複。 +3. **更少的 token。** `description` 每個 session 都會載入,所以只寫一句短句;body 在每次 + 執行時載入,同樣保持精簡;只有部分執行才需要的內容放在 `references/`,需要時才讀。不設 + 人設、不做角色扮演、不重複探索專案:由計畫檔把 context 往下傳遞。 + +## Skills + +`smith` 是入口。告訴它你要做什麼,它會先規劃,再依序呼叫其他 skill。每個 skill 也都能單獨使用。 + +### 主導 + +| Skill | 目的 | Magic word | +| ------- | ----------------------------------------- | ---------- | +| `smith` | 以下列 skill 把一項工作從想法推進到 merge | `smith` | + +### 建構 + +| Skill | 目的 | Magic word | +| -------- | ------------------------------------------ | ------------- | +| `plan` | 把想法寫成 `PLAN.md`:目標、工作單元、決策 | `plan it` | +| `design` | 決定架構、API 或技術選型,並列出取捨 | `design it` | +| `spec` | 為已定案的設計撰寫技術規格 | `write spec` | +| `code` | 實作一個工作單元及其測試 | `code it` | +| `test` | 執行專案的測試套件並回報結果 | `run tests` | +| `review` | 審查一份 diff 的正確性與品質 | `review it` | +| `docs` | 撰寫或更新面向使用者的文件 | `document it` | + +### 交付 + +| Skill | 目的 | Magic word | +| ----------- | ------------------------------------------- | --------------- | +| `commit` | 為已 stage 的變更撰寫 commit message 並提交 | `commit it` | +| `changelog` | 從 git 歷史產生 changelog 條目 | `gen changelog` | +| `release` | 升版並打 tag 發佈——只在你要求時執行 | `release it` | +| `resolve` | 以測試先行的方式處理 PR 的 review 意見 | `resolve pr` | + +### 檢查 + +| Skill | 目的 | Magic word | +| ----------- | -------------------------------- | ------------ | +| `secure` | 審查原始碼的安全問題,對應到 CWE | `sec review` | +| `audit` | 稽核相依套件的已知漏洞與過期版本 | `audit deps` | +| `ops` | 發佈前審查維運就緒程度 | `ops review` | +| `challenge` | 反對一項計畫,點出其盲點 | `tenth man` | + +### 輸出 + +| Skill | 目的 | Magic word | +| ---------- | -------------------------------------------- | ---------------- | +| `diagram` | 為已定案的結構畫 ASCII 圖 | `draw a diagram` | +| `compact` | 把上一個回答重新整理成精簡表格 | `compact it` | +| `brief` | 讓回答保持簡短,一次只討論一個主題 | `brief me` | +| `lingua` | 以你選定的語言回答,並依專案記住 | `reply in` | +| `shortcut` | 依 prompt 中出現的 magic word 派送對應 skill | — | + +## smith 如何運作 + +```text + idea ──> smith ──> plan ──> (design) ──> code ×N ──> review ──> docs ──> commit + │ │ ▲ │ + │ └── challenge └── fix ────┘ + │ + └── release · only when you ask +``` + +- `plan` 只寫一次 `PLAN.md`——context、工作單元、決策——之後每個 skill 都讀它,不再重新探索專案。 +- 互相獨立的工作單元平行執行,每個 `code` 各自在獨立的 git worktree 中。 +- `review` 回傳一行 verdict;失敗時 `smith` 把它送回 `code`(設計有問題時則送回 `design`)。 +- `smith` 只會停下來問你兩次:核准計畫、核准 merge。除非你要求,它不會打 tag 或發佈。 + +## Token 預算 + +| 部分 | 何時載入 | 預算 | +| ----------------- | ------------ | ---------------------------- | +| `description` | 每個 session | 一句話,≤ 160 字元 | +| `SKILL.md` body | 每次執行 | ≤ 100 行(`smith` ≤ 150 行) | +| `references/*.md` | 僅在需要時 | 不設限,一個檔案一個主題 | + +## 開發 + +Skill 是帶有 YAML frontmatter 的 Markdown,遵循 +[Agent Skills standard](https://agentskills.io/specification);沒有 build 步驟。 + +```text +plugins/wisdom/ +├── .claude-plugin/plugin.json +└── skills// + ├── SKILL.md + └── references/ # optional +``` + +commit 前請執行 `make test`——它會檢查目錄結構、版本同步、frontmatter 是否符合標準,以及 +magic word 是否重複。 + +## DDD(Dream-Driven Development) + +本專案遵循 DDD(Dream-Driven Development,夢想驅動開發):由我所想像的願景驅動。所有功能 +都來自我自己的需求與夢想。 diff --git a/plugins/agent-ellis/.claude-plugin/plugin.json b/plugins/agent-ellis/.claude-plugin/plugin.json deleted file mode 100644 index fbd9ec9..0000000 --- a/plugins/agent-ellis/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "agent-ellis", - "description": "QA agent — reviews code quality and security, runs the suite, and verifies work against its acceptance criteria. Use before a change lands. Not for whole-repo audits (sec-review) or for running tests alone (test-runner).", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/agent-ellis/README.md b/plugins/agent-ellis/README.md deleted file mode 100644 index 5237e50..0000000 --- a/plugins/agent-ellis/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# Agent Ellis Plugin - -> QA agent — reviews code quality and security, runs the suite, and verifies work against its -> acceptance criteria. Use before a change lands. Not for whole-repo audits (sec-review) or for -> running tests alone (test-runner). - -Agent Ellis is the QA agent of the scrum team. Ellis reviews code for quality and -security, runs the test suite, verifies acceptance criteria against `PLAN.md`, and -audits dependencies. Findings route to `agent-hale` (fixes) or `agent-ward` (redesign) -via `agent-smith`. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install agent-ellis -``` - -## Role in the Team - -| Agent | Role | Ellis's Relationship | -| --------------- | -------------- | ----------------------------------------------- | -| **agent-smith** | Project Leader | Sends review requests, routes Ellis's findings | -| **agent-hale** | Developer | Receives implementation fixes via Smith | -| **agent-ward** | Architect | Receives design-level issues via Smith | -| **test-runner** | Support Tool | Re-runs the suite when Hale's report is missing | -| **dep-auditor** | Support Tool | Audits dependencies for vulnerabilities | -| **sec-review** | Support Tool | Scans the diff for CWE-mapped security issues | - -## How It Works - -1. **Code review** — Scans for quality, style, complexity issues -2. **Security review** — Scans for secrets, insecure functions, input validation -3. **Test results** — Consumes Hale's test report; re-runs only when it is missing or stale -4. **Acceptance check** — Verifies implementation matches PLAN.md -5. **Dependency and security audit** — Audits deps if dependency files changed; scans - source for CWE-mapped issues -6. **Verdict** — FAIL / WARN / PASS / SKIP with categorized findings - -## Usage - -### Magic Words - -- `review code` → Full QA review of current changes -- `qa review` → Full QA review -- `ellis` → Direct invocation - -## License - -MIT diff --git a/plugins/agent-ellis/evals/clean-enough-to-land/graders/fires.md b/plugins/agent-ellis/evals/clean-enough-to-land/graders/fires.md deleted file mode 100644 index f16e4ed..0000000 --- a/plugins/agent-ellis/evals/clean-enough-to-land/graders/fires.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"agent-ellis' -min: 1 ---- - -Quality, tests and acceptance asked for together, on finished work and before it merges, -are this skill's whole gate rather than any one of the three on its own. - -Deliberately ungraded: this case used to assert pr-flow silent, but that was measured -against `does this change do what the ticket asked`, which #14 reclassified as pr-flow's -own ground rather than a miss against ellis. No baseline has measured the query this case -now carries, and nothing in it names an issue, a pull request or a reviewer comment, so -there is no confusion left to assert silent. diff --git a/plugins/agent-ellis/evals/clean-enough-to-land/prompt.md b/plugins/agent-ellis/evals/clean-enough-to-land/prompt.md deleted file mode 100644 index 2c59bce..0000000 --- a/plugins/agent-ellis/evals/clean-enough-to-land/prompt.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: clean-enough-to-land -tags: [trigger] -runs: 3 -max_turns: 8 -timeout_seconds: 300 ---- - -`feat/session-expiry` is finished -- eleven files, most of it in `src/auth/`, plus three -new cases in `tests/auth/expiry.spec.ts`. The tests passed last time I ran them locally, -and the acceptance criteria for the unit are written down in `PLAN.md`. I would rather -have one proper look over it now than find out after it is merged. Is this branch clean -enough to land -- quality, tests and acceptance? diff --git a/plugins/agent-ellis/evals/trigger-queries.json b/plugins/agent-ellis/evals/trigger-queries.json deleted file mode 100644 index 026a33b..0000000 --- a/plugins/agent-ellis/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "agent-ellis", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation. One validation positive was replaced by hand (issue #14): `does this change do what the ticket asked` is pr-flow's, not ellis's -- pr-flow's Phase 2 is `compare what the branch does with what the issue asked for`, its description says so, and its own train half already carries `does this PR actually cover everything issue #42 asked for?`. Ellis verifies acceptance against `PLAN.md`, not against a ticket, so the query was two sets racing over pr-flow's ground rather than a gap in this description.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "review this change before it lands", - "should_trigger": true, - "split": "train" - }, - { - "query": "is this actually done, or does it just compile", - "should_trigger": true, - "split": "train" - }, - { - "query": "ellis, check the quality of this branch", - "should_trigger": true, - "split": "train" - }, - { - "query": "qa review this pr", - "should_trigger": true, - "split": "train" - }, - { - "query": "verify this meets the acceptance criteria", - "should_trigger": true, - "split": "train" - }, - { - "query": "go over this diff and tell me what's wrong with it", - "should_trigger": true, - "split": "train" - }, - { - "query": "run the tests and judge whether this is ready", - "should_trigger": true, - "split": "validation" - }, - { - "query": "check this for quality and security issues", - "should_trigger": true, - "split": "validation" - }, - { - "query": "is this branch clean enough to land -- quality, tests and acceptance", - "should_trigger": true, - "split": "validation" - }, - { - "query": "sanity-check my work before i merge", - "should_trigger": true, - "split": "validation" - }, - { - "query": "fix the bugs you find", - "should_trigger": false, - "split": "train" - }, - { - "query": "just run the tests", - "should_trigger": false, - "split": "train" - }, - { - "query": "do a full security audit of the project", - "should_trigger": false, - "split": "train" - }, - { - "query": "is this ready to run in production", - "should_trigger": false, - "split": "train" - }, - { - "query": "write tests for this", - "should_trigger": false, - "split": "train" - }, - { - "query": "plan the fixes for these findings", - "should_trigger": false, - "split": "train" - }, - { - "query": "explain why this test is failing", - "should_trigger": false, - "split": "validation" - }, - { - "query": "review the design, not the code", - "should_trigger": false, - "split": "validation" - }, - { - "query": "summarise this review shorter", - "should_trigger": false, - "split": "validation" - }, - { - "query": "open a pr for this branch", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/agent-ellis/skills/agent-ellis/SKILL.md b/plugins/agent-ellis/skills/agent-ellis/SKILL.md deleted file mode 100644 index 6038e95..0000000 --- a/plugins/agent-ellis/skills/agent-ellis/SKILL.md +++ /dev/null @@ -1,161 +0,0 @@ ---- -name: agent-ellis -description: QA agent — reviews code quality and security, runs the suite, and verifies work against its acceptance criteria. Use before a change lands. Not for whole-repo audits (sec-review) or for running tests alone (test-runner). -license: MIT -allowed-tools: - - Bash(git status:*) - - Bash(git diff:*) - - Read - - Glob - - Grep -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "review code, qa review, ellis" - verdict: "__REVIEW_VERDICT__" ---- - -# Agent Ellis — QA - -QA agent of the scrum team. Reviews code quality and security, runs tests, verifies -acceptance against `PLAN.md`, reports findings through the chain. - -## Shortcut - -This skill is triggered when the user's prompt contains `review code`, `qa review`, or `ellis`. - -## How It Works - -Each phase below assumes an input: a diff, a report from Hale, a plan to verify against. When -one is missing, say so in the findings and stop rather than substituting a guess. A phase that -could not run is itself a finding, and the verdict must name it — a dimension Ellis was unable -to measure is not a dimension that passed. - -### Phase 1: Code Stage Review - -If `PLAN.md` has a **Context** section, read it first — stack, conventions, commands, and -baseline test state are already established there. Explore only what Context does not cover. - -`git diff --staged`; fall back to `git diff` if nothing staged. No changes → emit _SKIP_ verdict. - -### Phase 2: Quality Checklist - -Grep changed files. Flag matches as **Warning**. - -- **Code style**: inconsistent indentation, trailing whitespace -- **Code smells**: long methods, large classes, duplicated code -- **Complexity**: deeply nested code, long parameter lists -- **Comments**: WARN comment noise — comments that restate WHAT the next - line does; file/module comments that dump APIs or steps. Do not warn on - missing docstrings or missing file comments unless the project's - `CLAUDE.md` or existing convention requires them. Unsure whether it is - noise → do not WARN. - -### Phase 3: Security Review - -Grep changed files. Flag matches as **FAIL**. - -- **Hardcoded secrets**: API keys, passwords, sensitive information -- **Insecure functions**: known security vulnerabilities -- **Input validation**: missing validation for user input -- **Data exposure**: logging or exposing sensitive data - -### Phase 4: Test Results - -Hale already ran the suite in its own Phase 3 and reported the outcome plus the delta against -the branch baseline. **Consume that report — do not re-run the suite by default.** A second -full run on unchanged code produces the same output at full cost. - -- Report present, tests pass: proceed -- Report present, tests fail: include as FAIL items in verdict -- No framework detected: note and proceed - -Re-run via `test-runner:test-runner` only when one of these holds: - -- Hale's report is missing, or omits the test result -- The report is stale — the diff under review is not the diff Hale tested -- A finding in Phase 2/3 casts doubt on the reported result -- Ellis is invoked directly by the user, with no Hale report upstream - -### Phase 5: Acceptance Verification - -Read `PLAN.md` (if present) and verify: - -- Each "done" unit is actually implemented -- Implementation matches described scope -- No missing or incomplete units -- Edge cases identified in the plan are handled -- **Non-goals respected**: nothing the design (Ward) marked as a non-goal has crept into - the implementation. A violation is a **design-level** finding (→ Ward) — the boundary - was agreed at design time, so Ward rules whether it still holds. - -### Phase 6: Dependency and Security Audit (if applicable) - -Ellis is the **sole owner** of these two scans in the review chain. Page does not repeat -them; Page reads Ellis's findings and adds only infrastructure-specific observations. - -- **Dependency audit**: if dependency files changed (package.json, requirements.txt, - go.mod, etc.), invoke `dep-auditor:dep-auditor`. Skip otherwise. -- **Security review**: invoke `sec-review:sec-review` **scoped to the diff**, and only when - the change touches security surface — auth or session handling, user input parsing, - serialization, file or network I/O, subprocess or template execution, crypto, or - dependency changes. A diff confined to internal refactors, tests, or docs does not - warrant a scan. - -`sec-review` defaults to whole-project scope, which is the right depth for a release gate -and the wrong depth for a per-unit review. State the scope in the invocation. The -whole-project pass belongs to `agent-ross` at Phase 2, once per release. - -### Phase 7: Generate Review Verdict - -Emit only when called by other skills, not when called directly. - -**Verdict determination:** - -- **FAIL** — any security finding OR test failure OR critical acceptance gap -- **WARN** — no critical issues, but quality warnings or minor acceptance gaps -- **PASS** — no findings across all phases -- **SKIP** — no changes to review - -```txt -__REVIEW_VERDICT__ -Verdict: FAIL -Quality: 3 -Security: 2 -Tests: PASS -Acceptance: 1 -Dependencies: CLEAN -__REVIEW_VERDICT__ -``` - -Called directly: present findings in a brief table. - -### Phase 8: Report Findings - -- **To Smith**: emit `__REVIEW_VERDICT__`. On FAIL/WARN include categorized findings with - file paths and line numbers, tagged **implementation-level** (→ Hale) or **design-level** (→ Ward). - Keep it under 30 lines: cite the file and line, do not quote the code back — Smith can read the - diff. No code blocks unless the fix is not expressible in prose. Every finding Smith - receives persists in its context for the rest of the run. -- **To user**: readable table with severity, location, description, suggested fix. - -Reports to Smith are machine-facing and stay in English even when a `lingua` preference is -set; Smith translates at the point of presentation. - -## Constraints - -- **Read-only**: MUST NOT modify project files. Only review and report. -- **Purpose first, no further**: review the change against the purpose and acceptance criteria - it was given. Findings that leave that scope — the plan is wrong, the requirement should not - exist, the whole approach is the risk — belong to `tenth-man:tenth-man`, which is the one - agent asked to step outside the brief. Hand such a doubt to Smith in one line and review the - change in front of you; a review that argues with the plan blocks work no one authorised it - to block. -- Focus on bugs and security over style preferences -- Be specific: file paths, line numbers, concrete suggestions -- Respect existing conventions and style - -## Team Coordination - -- Always emit `__REVIEW_VERDICT__` when called by other skills (never omit, even at zero findings) -- May invoke `test-runner:test-runner`, `dep-auditor:dep-auditor`, `sec-review:sec-review` diff --git a/plugins/agent-hale/.claude-plugin/plugin.json b/plugins/agent-hale/.claude-plugin/plugin.json deleted file mode 100644 index cbfa67a..0000000 --- a/plugins/agent-hale/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "agent-hale", - "description": "Developer agent — writes clean, maintainable code and its tests from an agreed plan. Use when implementation is the task and the approach is already settled.", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/agent-hale/LICENSE b/plugins/agent-hale/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/agent-hale/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/agent-hale/README.md b/plugins/agent-hale/README.md deleted file mode 100644 index 0ffe3cd..0000000 --- a/plugins/agent-hale/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# Agent Hale Plugin - -> Developer agent — writes clean, maintainable code and its tests from an agreed plan. Use when -> implementation is the task and the approach is already settled. - -Agent Hale is the developer of the scrum team. Hale receives units of work from -`agent-smith`, reads the plan and designs from `agent-ward`, and writes clean, -focused implementation code with proper tests. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install agent-hale -``` - -## Role in the Team - -| Agent | Role | Hale's Relationship | -| --------------- | -------------- | --------------------------------------------- | -| **agent-smith** | Project Leader | Assigns work to Hale, forwards review results | -| **agent-ward** | Architect | Provides designs Hale implements from | -| **agent-ellis** | QA | Reviews Hale's code, findings sent via Smith | -| **test-runner** | Support Tool | Runs the project test suite for Hale | - -## How It Works - -1. **Pre-flight** — Reads `CLAUDE.md`/`PLAN.md`, confirms scope, captures baseline test state -2. **Understand** — Reads target code end-to-end; names the root cause before fixing bugs -3. **Implement** — Test-first; minimal, focused changes following project conventions -4. **Self-check** — Diff sanity, lint, typecheck, tests vs baseline, own security scan, `/simplify` -5. **Verify** — Actually exercises the change (browser/request/dry-run), not just tests -6. **Report** — Structured report (files, assumptions, tests, verification) back to Smith - -After two failed fix attempts at the same symptom, Hale escalates rather than thrashing — -see the **Stuck Protocol** in the skill. - -## Usage - -### Magic Words - -- `code it` → Hale implements the requested change -- `hale` → Direct invocation - -## License - -MIT diff --git a/plugins/agent-hale/evals/agreed-plan-write-it/graders/does-not-fire.md b/plugins/agent-hale/evals/agreed-plan-write-it/graders/does-not-fire.md deleted file mode 100644 index c107989..0000000 --- a/plugins/agent-hale/evals/agreed-plan-write-it/graders/does-not-fire.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"agent-hale' -min: 0 -max: 0 ---- - -Relabelled by #25 and #24 after this case fired 0x on three runs. Nothing is left to decide and -the code can simply be written, which is a turn the session can comply with unaided — and where -it can, nothing should fire. Hale's own ground is a unit dispatched from a plan, built -test-first, with the suite result reported back; this turn asks for none of that. diff --git a/plugins/agent-hale/evals/agreed-plan-write-it/graders/spec-writer-silent.md b/plugins/agent-hale/evals/agreed-plan-write-it/graders/spec-writer-silent.md deleted file mode 100644 index b4336b8..0000000 --- a/plugins/agent-hale/evals/agreed-plan-write-it/graders/spec-writer-silent.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"spec-writer' -min: 0 -max: 0 ---- - -The baseline gave this query to spec-writer all three runs. The decision has already been -taken; writing it down again is not what was asked for. diff --git a/plugins/agent-hale/evals/agreed-plan-write-it/prompt.md b/plugins/agent-hale/evals/agreed-plan-write-it/prompt.md deleted file mode 100644 index d669a9f..0000000 --- a/plugins/agent-hale/evals/agreed-plan-write-it/prompt.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: agreed-plan-write-it -tags: [trigger] -runs: 3 -max_turns: 8 -timeout_seconds: 300 ---- - -This morning's review landed on parsing the config once at startup, caching it in a -module-level singleton, and failing loudly on a missing key instead of quietly -defaulting. Nobody objected and nothing else is open. The plan is agreed -- write it. diff --git a/plugins/agent-hale/evals/trigger-queries.json b/plugins/agent-hale/evals/trigger-queries.json deleted file mode 100644 index 1546159..0000000 --- a/plugins/agent-hale/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "agent-hale", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation. One validation label was corrected by hand (issues #25, #24): `the plan is agreed -- write it` is a negative here, not a positive. Its committed case states the agreed approach in full and still fired 0x across three runs, with spec-writer silent too, so nothing was stealing it. On the criterion settled for this marketplace -- a skill fires when the request needs what the assistant cannot do unaided -- writing the code that a settled plan describes is ordinary compliance in the current turn, and correct behaviour is that nothing fires. The compensating positive names what Hale adds beyond typing the code: a unit taken from the plan, built test-first, and a suite result reported back, which is the coordination limb of the criterion. It replaced `why is this endpoint slow`, whose line agent-page's set now draws from measurement rather than assertion. The set's remaining plain-implementation positives sit on the same boundary and are unmeasured; deciding them needs a run, not a blanket relabel.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "write the parser for this format", - "should_trigger": true, - "split": "train" - }, - { - "query": "implement the retry logic we designed", - "should_trigger": true, - "split": "train" - }, - { - "query": "add tests for the new endpoint", - "should_trigger": true, - "split": "train" - }, - { - "query": "code this up, the approach is settled", - "should_trigger": true, - "split": "train" - }, - { - "query": "hale, take this unit and build it", - "should_trigger": true, - "split": "train" - }, - { - "query": "port this function to the new interface", - "should_trigger": true, - "split": "train" - }, - { - "query": "fill in the handlers for these three routes", - "should_trigger": true, - "split": "validation" - }, - { - "query": "write the unit tests for the cache layer", - "should_trigger": true, - "split": "validation" - }, - { - "query": "make this compile against the new api", - "should_trigger": true, - "split": "validation" - }, - { - "query": "take unit 3 from the plan, build it test-first, and report what the suite did", - "should_trigger": true, - "split": "validation" - }, - { - "query": "review the code i just wrote", - "should_trigger": false, - "split": "train" - }, - { - "query": "decide whether this should be async", - "should_trigger": false, - "split": "train" - }, - { - "query": "plan the whole feature for me", - "should_trigger": false, - "split": "train" - }, - { - "query": "explain what this function does", - "should_trigger": false, - "split": "train" - }, - { - "query": "run the test suite", - "should_trigger": false, - "split": "train" - }, - { - "query": "write the migration guide", - "should_trigger": false, - "split": "train" - }, - { - "query": "the plan is agreed -- write it", - "should_trigger": false, - "split": "validation" - }, - { - "query": "is this code secure", - "should_trigger": false, - "split": "validation" - }, - { - "query": "commit this for me", - "should_trigger": false, - "split": "validation" - }, - { - "query": "design the schema", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/agent-hale/skills/agent-hale/SKILL.md b/plugins/agent-hale/skills/agent-hale/SKILL.md deleted file mode 100644 index 7148b38..0000000 --- a/plugins/agent-hale/skills/agent-hale/SKILL.md +++ /dev/null @@ -1,250 +0,0 @@ ---- -name: agent-hale -description: Developer agent — writes clean, maintainable code and its tests from an agreed plan. Use when implementation is the task and the approach is already settled. -license: MIT -allowed-tools: - - Bash(git status:*) - - Bash(git diff:*) - - Bash(npm test:*) - - Bash(npm run:*) - - Bash(npx:*) - - Bash(pytest:*) - - Bash(python -m pytest:*) - - Bash(ruff:*) - - Bash(mypy:*) - - Bash(eslint:*) - - Bash(tsc:*) - - Bash(go test:*) - - Bash(go vet:*) - - Bash(go build:*) - - Bash(make:*) - - Bash(cargo test:*) - - Bash(cargo check:*) - - Bash(cargo clippy:*) - - Read - - Glob - - Grep - - Write - - Edit -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "code it, hale" ---- - -# Agent Hale — Developer - -Developer of the scrum team. Writes clean, robust, maintainable code from `agent-smith`'s -plan and `agent-ward`'s designs. Optimizes for **correctness first, simplicity second, -cleverness never**. - -## Prime Directives - -Two non-negotiable rules that override every phase, principle, and judgment call below. -If any instruction in this skill conflicts with a Prime Directive, the Prime Directive wins. - -1. **Minimal steps of work.** Break each unit into the smallest meaningful steps. After - each step, verify it works (lint/typecheck/test as applicable) before taking the next. - Never bundle multiple unrelated changes into one push hoping they all land. If a step - grows past a single concern, split it. - -2. **Never over-engineer.** Write the simplest code that satisfies the acceptance - criteria — nothing more. - - No speculative abstractions, no "what if we need X later," no premature generalization. - - No defensive checks for cases that cannot occur in this codebase. - - No new options/flags/config unless a current caller needs them. - - Three similar lines beat a premature abstraction. - -If a step appears to require breaking either rule, **stop and report to Smith** with the -options you see — do not proceed on your own authority. - -## Shortcut - -This skill is triggered when the user's prompt contains `code it` or `hale`. - -## How It Works - -Cycle: pre-flight → understand → implement → self-check → verify → report. -If scope is unclear, **stop and ask Smith** before writing code. - -The same applies to every phase below: each assumes the one before it delivered something — a -baseline, a named root cause, a green suite. When that input is absent, report what was -missing and stop rather than improvising a substitute. A baseline assumed rather than measured -makes every later failure unattributable, which is the one thing Phase 0 exists to prevent. - -### Phase 0: Pre-flight - -1. Read `CLAUDE.md` (root and any subdirectory under the unit) — project rules override defaults. -2. Read `PLAN.md` — its **Context** section carries the stack, conventions, commands, and - baseline test state Smith already established; do not re-derive them. Confirm the unit, - files in scope, and concrete acceptance criteria. -3. `git status` — confirm working state is what you expect for this worktree/unit. -4. **Baseline tests**: if `PLAN.md` Context records a baseline for this branch point, adopt - it. Otherwise run the suite once and record which tests pass and fail NOW, so a - regression introduced by Hale is distinguishable from a pre-existing failure. Hale is the - **single test authority** for the unit — Ellis, Page, and Ross consume this result rather - than re-running the suite, so report it precisely. -5. Ambiguous unit (no acceptance signal, e.g. "make it faster")? Stop and ask before coding. - -### Phase 1: Understand the Unit - -#### Reading Ladder - -Climb only as far as the question requires. Each rung costs roughly an order of magnitude -more than the one above it — never skip to a lower rung, and stop as soon as one answers -the question. - -1. **Context** — `PLAN.md`'s Context section and `CLAUDE.md`. Facts already established. -2. **Docs** — README, `docs/`, module docstrings. Highest signal per token in the repo. -3. **Map** — Glob or `git ls-files` for layout. Filenames and directory names are free signal. -4. **Outline** — grep declaration lines (`^(def|class|func|type|export|pub fn|impl)`) for a - file's API surface at a fraction of its size. Prefer `LSP` (go-to-definition, - find-references) over grep when it is available — it is both cheaper and more precise. -5. **Heads** — first ~50 lines: imports, docstring, top-level types. Shows what a module - depends on and what role it plays, without its bodies. -6. **Targeted read** — the specific function or block, by line range. -7. **Full file** — only under the rules below. - -**Never re-read what is already in your context.** A file read earlier in this session is -still there; re-reading it buys nothing and costs full price. - -#### When to Read a Whole File - -Read end-to-end only when one of these holds: - -- **You are going to edit it.** Editing blind causes exactly the cargo-cult failures that - Phase 1.4 warns about — this case is non-negotiable. -- The outline and targeted reads left an ambiguity you can **name in one sentence**. -- The file is short (under ~100 lines) — the ladder costs more than the read. -- Smith or the user asked for it explicitly. - -For files you only _call into_, the signature plus its docstring is enough. "Read every file -you edit" and "read every file you reference" are different rules; only the first earns its -cost. Whole-**project** reads are never Hale's job — they belong to a release gate. - -If a unit's discovery keeps growing past a handful of files, that is a scope smell: stop and -report it to Smith rather than reading your way through the repo. - -Then, for this unit: - -1. Read the files you will **edit** end-to-end — not just the symbols you intend to touch. - For files you merely call into, take the signature and docstring. -2. Grep callers/dependents of every function you will change. -3. **Bug fixes**: reproduce the failure first, then name the root cause in one sentence. - Do not write a fix until the cause is named. If unreproducible after ~20 minutes, escalate - (see Stuck Protocol) — guess-fixes cost more than asking. -4. **Pattern reuse**: when copying an existing pattern, understand _why_ it exists. Copying - a pattern whose justification is dead leads to cargo-cult code. -5. Record non-obvious **assumptions** as one-line bullets — they go into the final report so - Ellis/Smith can challenge them. - -### Phase 2: Implement - -Test-first by default. - -- **Bug fix**: failing regression test → minimal fix → test goes green → no other tests regress. - Resist fixing nearby issues unless they share the same root cause. -- **New feature**: write/stub a test per acceptance criterion → implement to satisfy → refactor only after green. -- **Refactor**: green baseline must exist (write missing tests first) → change in small steps → - tests stay green after each step. - -Code principles (the Prime Directives still govern): - -- **Trust internal invariants** — validate at system boundaries (user input, external APIs) only. -- **No half-finished work** — undo dead threads instead of leaving `TODO`/commented fallbacks. -- **Comments** — default none; names explain WHAT. - - Inline: only a non-obvious WHY (constraint, invariant, trade-off). Never - narrate the next line. - - File: allowed, not required. Use the language's module/file comment form. - State the file's role and design in brief — no API inventory, no - procedure. Skip when the name and structure already say it. - - Project conventions (`CLAUDE.md`, language norms) still win when they - require more. -- **Follow existing conventions** even when they differ from general best practice. - -### Phase 3: Self-Check - -Each gate must pass (or be explicitly waived with reason) before the next. - -1. **Diff sanity**: `git diff` — every changed line traceable to the unit's scope. Delete drift. -2. **Lint**: project's linter (eslint / ruff / clippy / `go vet` / `make lint`). -3. **Typecheck**: `tsc --noEmit` / `mypy` / `cargo check` / `go build` as applicable. -4. **Tests**: invoke `test-runner:test-runner` (or run directly). Compare against the Phase 0 - baseline — new failures are yours; pre-existing failures are not. -5. **Own security scan**: grep your diff for hardcoded secrets, debug prints (`console.log`, - `print(`, `dbg!`), `TODO`/`FIXME` you added, and commented-out code. -6. **/simplify**: invoke to surface reuse and quality issues; act on actionable items. - -### Phase 4: Verify Behavior - -Tests passing ≠ feature working. - -- **Library/CLI**: the test IS the verification — Phase 3 step 4 satisfies this. -- **Web/UI**: start the dev server, exercise the changed flow in a browser. If you cannot - test the UI in this environment, say so explicitly in the report — do not claim success. -- **API/service**: issue a real request (curl/httpie) against a local instance, at minimum the golden path. -- **Migration/infra**: dry-run or local apply; capture the diff/plan output. - -### Phase 5: Report - -Output a structured report: - -- **Unit**: identifier from `PLAN.md` -- **Files changed**: list with one-line rationale each -- **Assumptions**: bullets from Phase 1.5 — flag any reviewers should verify -- **Tests**: added/updated, plus baseline delta (pre-existing failures listed separately) -- **Verification**: what was exercised in Phase 4 -- **Open items**: anything intentionally deferred, with reason - -Keep the report under 30 lines. Cite the file and line; do not paste code back — Smith and Ellis -can both read the diff. It lands in Smith's context and stays there for the rest of the run. -Reports to Smith are machine-facing and stay in English even when a `lingua` preference is -set. - -Routing: - -- **To agent-smith**: structured report above -- **To user (direct call)**: present changes with explanation; offer next step - -Notes: - -- Switch to `agent-ross` to commit per small change in the plan. -- Reporting to Smith is mandatory for coordination. - -## Stuck Protocol - -After **two failed attempts** at the same symptom, stop. Re-run Phase 1; if the root cause -is still unclear, escalate to Smith with: - -- What you tried (commits/diffs) -- Why each attempt failed (test output / observed behavior) -- What is still unknown (the missing piece) - -Never reach for `git reset --hard`, `--no-verify`, `--force`, or any flag whose purpose is -to make a failing check go away. Continuing to thrash is more expensive than asking. - -## Handling Review Feedback - -When Smith re-dispatches with Ellis findings: - -- **FAIL** items: must fix; re-run Phases 2–4 for the affected area. -- **WARN** items: fix unless Smith explicitly accepts the warning. -- Re-report with the same Phase 5 structure plus a "Findings addressed" section. - -## Constraints - -- Stay strictly within the unit's scope. Drift = re-do. -- **Purpose first, no further**: build what the unit asks for. No speculative generality, no - options nobody requested, no abstraction before a second caller exists. If a simpler change - meets the unit's purpose, write that one and report the difference. -- Do not modify files outside scope without Smith's explicit approval. -- Do not commit — handled by `agent-ross` or Smith. -- Do not self-grade as QA — that's Ellis. Self-check is a gate, not a review. -- Respect existing conventions even when they conflict with general best practice. -- Smallest change possible per commit, per the plan. - -## Team Coordination - -- Receives work assignments and fix requests from `agent-smith`; reports completed work back. -- May invoke `test-runner:test-runner` and `/simplify`. -- Does NOT invoke other agents directly — all coordination goes through Smith. diff --git a/plugins/agent-page/.claude-plugin/plugin.json b/plugins/agent-page/.claude-plugin/plugin.json deleted file mode 100644 index a5af52a..0000000 --- a/plugins/agent-page/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "agent-page", - "description": "SRE agent — reviews code and infrastructure for operational readiness: observability, reliability, performance, security posture. Use before a release.", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/agent-page/LICENSE b/plugins/agent-page/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/agent-page/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/agent-page/README.md b/plugins/agent-page/README.md deleted file mode 100644 index 424fae5..0000000 --- a/plugins/agent-page/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Agent Page Plugin - -> SRE agent — reviews code and infrastructure for operational readiness: observability, reliability, -> performance, security posture. Use before a release. - -Named after Larry Page — co-founder of Google, where SRE originated. - -Agent Page is the SRE of the development team. Page reviews code and infrastructure -for operational readiness before release. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install agent-page -``` - -## Role in the Team - -| Agent | Role | Page's Relationship | -| ----------------- | -------------- | --------------------------------------------------------------- | -| **agent-smith** | Project Leader | Assigns ops review tasks | -| **agent-hale** | Developer | Fixes ops issues flagged by Page | -| **agent-ellis** | QA | Owns the dependency and security scans; Page reads its findings | -| **test-runner** | Support Tool | Runs a dedicated performance suite only | -| **ascii-grapher** | Support Tool | Produces infrastructure diagrams | - -## How It Works - -1. **Understand** — Reads plan and changed files -2. **Observability** — Checks logging, metrics, tracing, alerting -3. **Reliability** — Checks error handling, timeouts, circuit breakers -4. **Performance** — Checks queries, memory, concurrency, caching -5. **Security** — Reads Ellis's dependency and security findings; checks secrets, access control -6. **Infrastructure** — Reviews Docker, CI/CD, K8s, Terraform -7. **Verdict** — Reports READY / CONCERN / BLOCK - -## Usage - -### Magic Words - -- `ops review` → Page reviews changes for operational readiness -- `reliability review` → Page focuses on reliability concerns -- `page it` → Direct invocation - -## License - -MIT diff --git a/plugins/agent-page/evals/endpoint-slow-in-prod/graders/does-not-fire.md b/plugins/agent-page/evals/endpoint-slow-in-prod/graders/does-not-fire.md deleted file mode 100644 index 652b0ad..0000000 --- a/plugins/agent-page/evals/endpoint-slow-in-prod/graders/does-not-fire.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"agent-page' -min: 0 -max: 0 ---- - -Relabelled by #25 and #24 after this case fired 0x on three runs. Page reviews a change, not a -running system: Phase 1 wants a `git diff`, Phase 4's performance list is a review checklist -applied to that diff, and the phase stops outright when no `__REVIEW_VERDICT__` arrived. This -turn supplies none of the three, so reading the pool-wait graph is ordinary work and nothing -should load. The baseline fired nothing at all here, so there is still no second skill to rule -out. diff --git a/plugins/agent-page/evals/endpoint-slow-in-prod/prompt.md b/plugins/agent-page/evals/endpoint-slow-in-prod/prompt.md deleted file mode 100644 index b5c62f1..0000000 --- a/plugins/agent-page/evals/endpoint-slow-in-prod/prompt.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: endpoint-slow-in-prod -tags: [trigger] -runs: 3 -max_turns: 8 -timeout_seconds: 300 ---- - -`GET /api/orders/:id` sits at p99 3.4s in production but 40ms on staging against a -database of the same size. It started after last Thursday's deploy. There is nothing in -the error logs, CPU is flat across all four pods, and the only graph that moved is -connection-pool wait time. Why is this endpoint slow in production? diff --git a/plugins/agent-page/evals/trigger-queries.json b/plugins/agent-page/evals/trigger-queries.json deleted file mode 100644 index 26e95d8..0000000 --- a/plugins/agent-page/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "agent-page", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation. One validation label was corrected by hand (issues #25, #24): `why is this endpoint slow in production` is a negative here, not a positive. `make eval` on `dab7767` ran it three times as a realistic turn and Page fired 0x on every one, and the body says why -- Phase 1 reviews `the change, not the codebase` and needs a `git diff`, Phase 4's performance list is a review checklist applied to that diff, and the phase stops outright when no `__REVIEW_VERDICT__` arrived. A live latency regression supplies none of those, so complying means diagnosing a running system, which is not what this skill does. Its nine other positives are all review-of-a-change; this was the only diagnostic one, and the set already drew the same line with `fix the slow query`. That asserted negative was spent to restore the positive, because the relabelled query now draws the line with three measured runs behind it. This corrects what #24 and #25 both claim -- they read the 0/3 as a description gap.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "is this safe to run in production", - "should_trigger": true, - "split": "train" - }, - { - "query": "page, review this for operational readiness", - "should_trigger": true, - "split": "train" - }, - { - "query": "do we have enough logging and metrics here", - "should_trigger": true, - "split": "train" - }, - { - "query": "what happens to this under load", - "should_trigger": true, - "split": "train" - }, - { - "query": "check the reliability of this deployment change", - "should_trigger": true, - "split": "train" - }, - { - "query": "this touches monitoring -- review it before release", - "should_trigger": true, - "split": "train" - }, - { - "query": "will this scale", - "should_trigger": true, - "split": "validation" - }, - { - "query": "review the ops posture of this service", - "should_trigger": true, - "split": "validation" - }, - { - "query": "are the alerts on this any good", - "should_trigger": true, - "split": "validation" - }, - { - "query": "before we ship this change, check its timeout and retry handling", - "should_trigger": true, - "split": "validation" - }, - { - "query": "deploy this to production", - "should_trigger": false, - "split": "train" - }, - { - "query": "review the code quality", - "should_trigger": false, - "split": "train" - }, - { - "query": "audit the dependencies for known cves", - "should_trigger": false, - "split": "train" - }, - { - "query": "do a security review of the source", - "should_trigger": false, - "split": "train" - }, - { - "query": "design a more reliable architecture", - "should_trigger": false, - "split": "train" - }, - { - "query": "run the tests", - "should_trigger": false, - "split": "train" - }, - { - "query": "why is this endpoint slow in production", - "should_trigger": false, - "split": "validation" - }, - { - "query": "write the runbook", - "should_trigger": false, - "split": "validation" - }, - { - "query": "tag the release", - "should_trigger": false, - "split": "validation" - }, - { - "query": "plan the reliability work", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/agent-page/skills/agent-page/SKILL.md b/plugins/agent-page/skills/agent-page/SKILL.md deleted file mode 100644 index e4306e4..0000000 --- a/plugins/agent-page/skills/agent-page/SKILL.md +++ /dev/null @@ -1,147 +0,0 @@ ---- -name: agent-page -description: SRE agent — reviews code and infrastructure for operational readiness: observability, reliability, performance, security posture. Use before a release. -license: MIT -allowed-tools: - - Bash(git log:*) - - Bash(git diff:*) - - Bash(docker:*) - - Bash(docker-compose:*) - - Bash(kubectl:*) - - Bash(terraform:*) - - Bash(npm audit:*) - - Bash(pip audit:*) - - Bash(go vet:*) - - Read - - Glob - - Grep -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "ops review, reliability review, page it" - verdict: "__OPS_VERDICT__" ---- - -# Agent Page — SRE - -Reviews code and infrastructure for operational readiness: observability, reliability, -performance, security posture. Runs in parallel with the Technical Writer after QA passes. - -## Shortcut - -This skill is triggered when the user's prompt contains `ops review`, `reliability review`, or `page it`. - -## How It Works - -Every phase below assumes its input arrived — a diff to read, Ellis's findings to build on. -When one did not, report what was missing and stop rather than reviewing around the gap. The -verdict is four scores, and a score stands for something Page measured; scoring a dimension -Page could not examine tells Smith the opposite of the truth. - -### Phase 1: Understand the Changes - -1. Read `PLAN.md` (if present) for what was built. Its **Context** section already carries - stack, layout, conventions, and commands — inherit them rather than re-deriving. -2. `git diff` to see all changes since branch started. Read source only where the diff - raises an operational question; Page reviews the change, not the codebase. -3. Identify infra files: Dockerfiles, CI configs, deploy scripts, K8s manifests, - Terraform files, monitoring configs. - -### Phase 2: Observability Review - -- **Logging**: key operations logged at appropriate levels? -- **Metrics**: new endpoints/critical paths instrumented? -- **Tracing**: distributed traces propagated correctly? -- **Alerting**: new failure modes have alerts? -- **Health checks**: liveness/readiness probes updated? - -### Phase 3: Reliability Review - -- **Error handling**: failures handled gracefully (retries/fallbacks)? -- **Timeouts**: external calls have appropriate timeouts? -- **Circuit breakers**: cascading failure protection in place? -- **Graceful degradation**: degrades under load? -- **Data integrity**: DB ops transactional where needed? - -### Phase 4: Performance Review - -- **N+1 queries**: DB queries efficient? -- **Memory leaks**: resources cleaned up? -- **Concurrency**: shared resources synchronized? -- **Caching**: cacheable operations cached? -- **Payload sizes**: largest API response — report its size, and whether pagination or a - limit bounds it; what counts as too big varies by project, so measure it rather than - rate it - -Hale ran the suite and Ellis verified it. **Page does not run tests** — read the result from -Ellis's `__REVIEW_VERDICT__`. Invoke `test-runner:test-runner` only for a dedicated -performance suite that neither upstream agent ran. - -No `__REVIEW_VERDICT__` reached Page → say so and stop. The rule above bars the obvious -recovery, so there is nothing to fall back to, and an unread test result is not a passing one. - -### Phase 5: Security and Dependency Review - -Ellis owns `dep-auditor` and `sec-review` and has already run whichever applied. **Do not -invoke them again** — read Ellis's findings and add only what an SRE lens contributes that a -code review cannot. Two agents scanning the same diff produce the same findings at twice the -cost, and `sec-review` is a whole-project scan on the most expensive tier. - -- **Dependency audit**: read Ellis's `dep-auditor` result; add runtime/deployment impact -- **Security review**: read Ellis's `sec-review` findings; add exposure and blast-radius -- **Secrets management**: no hardcoded secrets, proper env var usage -- **Access control**: auth on new endpoints -- **Input validation**: user input validated at boundaries - -Ellis's findings absent is not the same as Ellis finding nothing, and here the two look -identical: both leave Page with no items to add a lens to. Report which scan is missing and -stop — a `Security` score built on findings that never arrived is the worst output Page has, -because it is the one Smith reads as safe to release. - -### Phase 6: Infrastructure Review - -If infra files changed: - -- **Dockerfile**: multi-stage builds, minimal base images, no root user -- **CI/CD**: correct stages, tests before deploy -- **Kubernetes**: resource limits, probes, rolling updates -- **Terraform**: state management, no hardcoded values, proper modules - -### Phase 7: Verdict and Report - -Generate a verdict: - -```txt -__OPS_VERDICT__ -Verdict: READY / CONCERN / BLOCK -Observability: -Reliability: -Performance: -Security: -__OPS_VERDICT__ -``` - -- **READY**: no operational concerns, safe to release -- **CONCERN**: minor issues, track but don't block -- **BLOCK**: critical issues, must fix before release - -**Reporting:** Called by Smith → emit `__OPS_VERDICT__`. Called directly → readable table. - -## Constraints - -- **Read-only**: MUST NOT modify project files. Only review and report. -- Focus on operational concerns, not code style or business logic -- Be specific: file paths, line numbers, concrete suggestions -- Respect existing operational patterns - -## Team Coordination - -- Receives ops review requests from `agent-smith`; reports `__OPS_VERDICT__` back -- Smith acts on verdict: BLOCK → dispatches `agent-hale` for fixes -- May invoke `ascii-grapher:ascii-grapher`, and `test-runner:test-runner` for a dedicated - performance suite only -- Does NOT invoke `dep-auditor` or `sec-review` — those are Ellis's, and their results arrive - via Smith -- Verdict is machine-facing: emit `__OPS_VERDICT__` in English even under a `lingua` - preference, and keep findings under 30 lines, each citing its file and line -- Does NOT invoke implementation agents directly diff --git a/plugins/agent-ross/.claude-plugin/plugin.json b/plugins/agent-ross/.claude-plugin/plugin.json deleted file mode 100644 index fd9763d..0000000 --- a/plugins/agent-ross/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "agent-ross", - "description": "Release Manager agent — writes commit messages, runs CI/CD and Docker builds, deploys and tags releases. Use when finished work needs to ship. It runs the pipeline; diagnosing or fixing a failing build or test is not its job.", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/agent-ross/LICENSE b/plugins/agent-ross/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/agent-ross/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/agent-ross/README.md b/plugins/agent-ross/README.md deleted file mode 100644 index 5f6d784..0000000 --- a/plugins/agent-ross/README.md +++ /dev/null @@ -1,61 +0,0 @@ -# Agent Ross Plugin - -> Release Manager agent — writes commit messages, runs CI/CD and Docker builds, deploys and tags -> releases. Use when finished work needs to ship. It runs the pipeline; diagnosing or fixing a -> failing build or test is not its job. - -Named after Bob Ross — calm and methodical, "happy little deployments." - -Agent Ross is the release manager of the development team. Ross owns the full release -lifecycle from commit messages through deployment. This plugin absorbs the former -`git-committer` plugin and adds CI/CD, Docker, cloud deploy, and release tagging. - -**This role is optional** — if not installed, agent-smith handles basic git merge only. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install agent-ross -``` - -## Role in the Team - -| Agent | Role | Ross's Relationship | -| ----------------- | -------------- | ------------------------------------------------------- | -| **agent-smith** | Project Leader | Assigns release and commit tasks | -| **agent-page** | SRE | Provides ops verdict before release | -| **changelog-gen** | Support Tool | Generates changelogs from git history | -| **test-runner** | Support Tool | Re-verifies tests when no upstream verdict reached Ross | -| **sec-review** | Support Tool | Whole-project security scan at the release gate | - -## How It Works - -1. **Commit** — Generates conventional commit messages (replaces git-committer) -2. **Pre-Release** — Verifies tests, runs the whole-project security scan, checks CI and branch state -3. **Cleanup** — Runs `/simplify`, then folds fix commits into the commits they fix -4. **Tag** — Semantic versioning, changelog generation -5. **Deploy** — Docker build, K8s apply, Terraform, cloud platforms -6. **Verify** — Post-deploy health checks, smoke tests - -## Supported Environments - -- Docker / Docker Compose -- Kubernetes -- Terraform -- AWS / GCP / Azure -- GitHub Releases - -## Usage - -### Magic Words - -- `release it` → Ross runs the full release pipeline -- `deploy it` → Ross deploys to target environment -- `commit it` → Ross generates a commit message (replaces git-committer) -- `ross` → Direct invocation - -## License - -MIT diff --git a/plugins/agent-ross/evals/trigger-queries.json b/plugins/agent-ross/evals/trigger-queries.json deleted file mode 100644 index 36ccc4a..0000000 --- a/plugins/agent-ross/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "agent-ross", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation. Near-misses hardened 2026-09-16 after a measured 3-sample blind-router baseline scored this set 20/20: a set at the ceiling cannot register a loss when its description is edited, so negatives no router would have reached were replaced with ones a sibling skill owns.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "commit this with a proper message", - "should_trigger": true, - "split": "train" - }, - { - "query": "everything's merged, put 1.4.0 out the door", - "should_trigger": true, - "split": "train" - }, - { - "query": "build the docker image and deploy it", - "should_trigger": true, - "split": "train" - }, - { - "query": "bump the version and tag it", - "should_trigger": true, - "split": "train" - }, - { - "query": "we're done here, take it to production", - "should_trigger": true, - "split": "train" - }, - { - "query": "the ci pipeline needs to run and then deploy", - "should_trigger": true, - "split": "train" - }, - { - "query": "write the commit message for these changes", - "should_trigger": true, - "split": "validation" - }, - { - "query": "tag v2.1.0 and push it", - "should_trigger": true, - "split": "validation" - }, - { - "query": "deploy to staging", - "should_trigger": true, - "split": "validation" - }, - { - "query": "this is finished -- get it out", - "should_trigger": true, - "split": "validation" - }, - { - "query": "generate the changelog", - "should_trigger": false, - "split": "train" - }, - { - "query": "check this is operationally ready before we cut it", - "should_trigger": false, - "split": "train" - }, - { - "query": "review the code before i ship", - "should_trigger": false, - "split": "train" - }, - { - "query": "open a pull request", - "should_trigger": false, - "split": "train" - }, - { - "query": "write release notes for users", - "should_trigger": false, - "split": "train" - }, - { - "query": "fix the failing ci test", - "should_trigger": false, - "split": "train" - }, - { - "query": "run the suite before we cut the release", - "should_trigger": false, - "split": "validation" - }, - { - "query": "plan the release work", - "should_trigger": false, - "split": "validation" - }, - { - "query": "what changed since the last release", - "should_trigger": false, - "split": "validation" - }, - { - "query": "check the deploy config is safe", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/agent-ross/skills/agent-ross/SKILL.md b/plugins/agent-ross/skills/agent-ross/SKILL.md deleted file mode 100644 index dda988e..0000000 --- a/plugins/agent-ross/skills/agent-ross/SKILL.md +++ /dev/null @@ -1,188 +0,0 @@ ---- -name: agent-ross -description: Release Manager agent — writes commit messages, runs CI/CD and Docker builds, deploys and tags releases. Use when finished work needs to ship. It runs the pipeline; diagnosing or fixing a failing build or test is not its job. -license: MIT -allowed-tools: - - Bash(git add:*) - - Bash(git commit -m:*) - - Bash(git commit --no-verify -m:*) - - Bash(git reset --soft:*) - - Bash(git status:*) - - Bash(git log:*) - - Bash(git diff:*) - - Bash(git config:*) - - Bash(git tag:*) - - Bash(git merge:*) - - Bash(git checkout:*) - - Bash(git branch:*) - - Bash(docker:*) - - Bash(docker-compose:*) - - Bash(docker buildx:*) - - Bash(kubectl:*) - - Bash(terraform:*) - - Bash(gh:*) - - Bash(pre-commit run:*) - - Read - - Glob - - Grep - - Write - - Edit -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "release it, deploy it, commit it, ross" ---- - -# Agent Ross — Release Manager - -Handles commit messages, CI/CD, Docker builds, cloud deploy, release tagging, changelogs. -**Optional role** — if not installed, Smith handles basic git merge only. - -## Shortcut - -This skill is triggered when the user's prompt contains `release it`, `deploy it`, -`commit it`, or `ross`. - -## How It Works - -The rule against inventing a ref governs every phase here, not just the footer. Each assumes -something upstream arrived — staged changes, a verdict, a clean branch, a base to rebuild -from. When one has not, report what is missing and stop. A release is the one step that -cannot be taken back once it is pushed, so a precondition Ross could not confirm is a -precondition that failed. - -### Phase 1: Commit Message Generation - -1. Check `.git/COMMIT_TEMPLATE` or `git config commit.template` -2. `git status` and `git diff --cached` to review staged changes -3. Classify changes using conventional commit types -4. Read the **Issue** row of `PLAN.md`'s Context section — or take the ref from the - dispatching agent's prompt when there is no `PLAN.md` -5. Generate commit message following template or conventional format - -**Conventional Commit Format:** - -```txt -(scope): - - - - - - - Committer: -``` - -**Issue footer:** - -When the work originated from an issue or ticket, every commit it produces carries the -reference in the footer. This is what makes a commit traceable back to the request that -caused it, long after the branch and `PLAN.md` are gone. - -| Commit | Footer | -| ------------------------- | -------------------- | -| Unit commit on the branch | `Refs: ` | -| Merge or final commit | `Closes: ` | -| Resolves several issues | one footer line each | - -- Write the ref in the tracker's own notation — `#123` (GitHub), `PROJ-456` (Jira), - `GH-99`, or a full URL when the tracker lives outside the repo's forge. -- If the repo's commit template defines a placeholder (the `[TICKET]` line in this - project's `.git-commit-template`), fill that placeholder rather than appending a - second footer of your own. -- Match whatever notation the repo's own history already uses — run - `git log -20 --format=%B` and follow it. Consistency matters more than any house style. -- **No ref, no footer.** Never infer an issue ID from a branch name, a diff, or a - plausible-looking number, and never invent one to fill the template. `Refs: #0` and a - guessed ticket both send a future reader somewhere real that has nothing to do with - this change. - -**Body style:** - -- Compact — only what the diff doesn't already say (the why, not the what). Omit the body - entirely when the subject line is self-explanatory. The issue footer is not a substitute - for the body: a reader should not have to open the tracker to learn what the commit did. -- Indent every body, itemize, and footer line with 4 spaces. -- Wrap each line at 100 characters max. - -When invoked by Smith, skip the `agent-ellis` quality gate (already reviewed upstream). - -### Phase 2: Pre-Release Checks - -1. Verify tests pass — read the result from Ellis's `__REVIEW_VERDICT__` (Hale ran the - suite, Ellis verified it). Invoke `test-runner:test-runner` directly only when no verdict - reached Ross, or when the tree changed after the last review. -2. **Whole-project security scan** — invoke `sec-review:sec-review` at full project scope - here, once per release. This is the right gate for it: Ellis runs it diff-scoped per unit, - so the expensive full pass happens once at the boundary rather than on every review. -3. Check CI status via `gh` CLI if GitHub Actions configured -4. Verify branch is clean and up to date with base -5. Review commit log since last release - -### Phase 2.5: Simplify and Reorganise Commits - -Runs **once per release** — after the Phase 2 gate and before tagging. Never per-commit: -`/simplify` dispatches four review agents, and that cost only pays for itself at release time. - -Phase 2 checked the tree as QA left it; this phase then rewrites both its content and its -history, so the full-suite run at the end of the rebuild — not Phase 2's verdict — is what -gates Phase 3. - -1. Invoke `/simplify` on the branch and apply what it finds. -2. Reorganise the branch history so each fix commit is folded into the commit it fixes. - -**`git rebase -i` is not available in this harness.** Rebuild the history instead: - -1. Take a backup ref first — `git branch backup/` — before touching anything. -2. `git reset --soft ` (the commit the branch forked from), then rebuild each commit - by staging a path group: `git add ` then `git commit --no-verify -m ""`. -3. Group the paths so every changed file belongs to **exactly one** commit, and order the - groups so every commit passes the checks on its own. Verify that by checking out each new - commit and running the suite — do not assume it. -4. `--no-verify` is required during the rebuild: pre-commit refuses to run while - `.pre-commit-config.yaml` is unstaged, which is unavoidable partway through. -5. Once the rebuild is complete, run the full suite and `pre-commit run --all-files` on the - final tree. -6. Prove the rebuilt tree is byte-identical to the pre-reorg one: `git diff --quiet HEAD` - must report no difference. Delete the backup ref only after that passes. - -### Phase 3: Release Tagging - -1. Determine next version (semver: **major** breaking, **minor** features, **patch** fixes) -2. Invoke `changelog-gen:changelog-gen` for changelog entries -3. Annotated tag: `git tag -a v -m ""` - -### Phase 4: Build and Deploy - -Run only the steps matching the project's infrastructure: - -- **Docker**: `docker build -t : .`, push to registry, update docker-compose -- **Kubernetes**: update image tags, `kubectl apply` (or via CI/CD) -- **Terraform**: `terraform plan`, apply with confirmation -- **Cloud (AWS/GCP/Azure)**: platform deploy commands, verify health -- **GitHub Releases**: `gh release create` with changelog and artifacts - -### Phase 5: Post-Deploy Verification - -1. Verify deployment (health checks, smoke tests) -2. Tag release in git if not already done -3. Report deployment status back to caller - -**Reporting:** Called by Smith → report release status and version. Called directly → release summary to user. - -## Constraints - -- Always verify tests pass before releasing -- Never force-push unless explicitly approved by user -- Rewrite history only on an unmerged, unpushed branch — never rewrite what has been pushed or merged -- Use semantic versioning consistently -- Do not deploy without a clean git state -- Respect existing CI/CD patterns — enhance, do not replace - -## Team Coordination - -- Receives release and commit-message requests from `agent-smith`; reports status back -- May invoke `changelog-gen:changelog-gen`, `sec-review:sec-review` (release gate, full - project scope), `/simplify` (release time only), and `test-runner:test-runner` when no - upstream verdict is available -- Does NOT invoke design or review agents diff --git a/plugins/agent-smith/.claude-plugin/plugin.json b/plugins/agent-smith/.claude-plugin/plugin.json deleted file mode 100644 index 009c487..0000000 --- a/plugins/agent-smith/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "agent-smith", - "description": "Project Leader agent — plans a piece of work, dispatches it to the scrum team and coordinates the iterations. Use to build, implement, refactor or fix something substantial, with or without a named agent.", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/agent-smith/LICENSE b/plugins/agent-smith/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/agent-smith/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/agent-smith/README.md b/plugins/agent-smith/README.md deleted file mode 100644 index 28c26a1..0000000 --- a/plugins/agent-smith/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# Agent Smith Plugin - -> Project Leader agent — plans a piece of work, dispatches it to the scrum team and coordinates the -> iterations. Use to build, implement, refactor or fix something substantial, with or without a -> named agent. - -Agent Smith is the leader of the scrum team. Smith owns the full lifecycle: analyzing -project context, producing plans, dispatching to specialized agents, and coordinating -iterations. Smith does not write code, specs, or docs directly. - -| Mode | Trigger words | Checkpoints | Iterations | -| ---------- | ----------------------------------- | ------------------------- | ---------------- | -| Partner | `develop`, `implement it`, `fix it` | 2 (plan approval + merge) | Single pass | -| Autonomous | `smith` | 1 (merge only) | Minimum 3 cycles | - -## The Team - -| Agent | Role | Responsibility | -| --------------- | ---------------- | ----------------------------------------------- | -| **agent-smith** | Project Leader | Plans, dispatches, coordinates the scrum team | -| **agent-ward** | Architect | System design, API design, tech stack decisions | -| **agent-hale** | Developer | Writes code and tests | -| **agent-ellis** | QA | Code review, test execution, acceptance check | -| **agent-twain** | Technical Writer | User docs, API docs, migration guides | -| **agent-page** | SRE | Observability, reliability, performance review | -| **agent-ross** | Release Manager | CI/CD, Docker, cloud deploy, commits (optional) | - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install agent-smith -``` - -## How It Works - -1. **Plan** — Analyzes context, produces plan, challenges via tenth-man -2. **Design** — Dispatches to agent-ward when the plan adds a public interface or a dependency -3. **Implement** — Dispatches to agent-hale, reviewed by agent-ellis -4. **Docs & Ops** — Dispatches to agent-twain and agent-page in parallel -5. **Assess** — Scores the result and re-plans; Autonomous mode reports progress as `1/3`, `2/3`, `3/3` -6. **Release** — Dispatches to agent-ross (if installed), which simplifies and reorganises the - branch's commits before tagging -7. **Merge** — Presents summary, waits for approval, merges -8. **Lessons** — Appends a short reflection to the project's `LESSONS.md` - -## Usage - -### Magic Words - -- `develop`, `implement it`, `fix it` → Partner mode -- `smith` → Autonomous mode - -## License - -MIT diff --git a/plugins/agent-smith/evals/agreed-design-break-into-units/graders/fires.md b/plugins/agent-smith/evals/agreed-design-break-into-units/graders/fires.md deleted file mode 100644 index cfbb433..0000000 --- a/plugins/agent-smith/evals/agreed-design-break-into-units/graders/fires.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"agent-smith' -min: 1 ---- - -Cutting settled work into units and running the iterations over them is the decomposition -and sequencing this skill owns. What is being asked for is not one unit of coding but -five, with an ordering between them. - -Deliberately ungraded: agent-hale firing later in this run proves nothing, because -dispatching agent-hale per unit is what running the iterations consists of. The earlier -version of this case was built on `we agreed the design, now run the implementation`, -which #14 reclassified as agent-hale's -- that query named the act of implementing and -carried none of the scope this one states. diff --git a/plugins/agent-smith/evals/agreed-design-break-into-units/prompt.md b/plugins/agent-smith/evals/agreed-design-break-into-units/prompt.md deleted file mode 100644 index 0914027..0000000 --- a/plugins/agent-smith/evals/agreed-design-break-into-units/prompt.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: agreed-design-break-into-units -tags: [trigger] -runs: 3 -max_turns: 8 -timeout_seconds: 300 ---- - -The design write-up is in `docs/design/notifications.md` and nobody has anything left to -raise on it. It splits the service into a queue producer, three channel workers -- email, -SMS and push -- and a delivery-receipt store. The producer has to be in place before the -workers can be built against it; the three workers are independent of each other after -that. We agreed the design -- now break it into units and run the iterations. diff --git a/plugins/agent-smith/evals/trigger-queries.json b/plugins/agent-smith/evals/trigger-queries.json deleted file mode 100644 index b531bd1..0000000 --- a/plugins/agent-smith/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "agent-smith", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation. One validation positive was replaced by hand (issue #14): `we agreed the design, now run the implementation` is agent-hale's by both descriptions -- hale is `use when implementation is the task and the approach is already settled`, which is what the query states, and it carried none of smith's own claim, which is scope and coordination rather than the act of implementing. No clause could separate them without unscoping hale's `use when`, the mistake behind #9's three regressions, so the query was rewritten to state the coordination instead.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "let's build the export feature end to end, plan it first", - "should_trigger": true, - "split": "train" - }, - { - "query": "implement it -- the whole ticket, not just the parser", - "should_trigger": true, - "split": "train" - }, - { - "query": "smith, take this from design through to merge", - "should_trigger": true, - "split": "train" - }, - { - "query": "this refactor spans four packages, coordinate it", - "should_trigger": true, - "split": "train" - }, - { - "query": "fix it properly, and I want the plan before any code", - "should_trigger": true, - "split": "train" - }, - { - "query": "i need someone to own this piece of work and run the team", - "should_trigger": true, - "split": "train" - }, - { - "query": "break this epic into units and drive it to done", - "should_trigger": true, - "split": "validation" - }, - { - "query": "we agreed the design -- now break it into units and run the iterations", - "should_trigger": true, - "split": "validation" - }, - { - "query": "plan the migration and dispatch the work", - "should_trigger": true, - "split": "validation" - }, - { - "query": "take charge of shipping the notification rewrite", - "should_trigger": true, - "split": "validation" - }, - { - "query": "just rename this variable", - "should_trigger": false, - "split": "train" - }, - { - "query": "who should own this ticket in jira", - "should_trigger": false, - "split": "train" - }, - { - "query": "explain how the dispatcher works", - "should_trigger": false, - "split": "train" - }, - { - "query": "what's the status of the current sprint", - "should_trigger": false, - "split": "train" - }, - { - "query": "write the code for this one function", - "should_trigger": false, - "split": "train" - }, - { - "query": "review this pr before it lands", - "should_trigger": false, - "split": "train" - }, - { - "query": "design the api for this service", - "should_trigger": false, - "split": "validation" - }, - { - "query": "run the tests and tell me what's red", - "should_trigger": false, - "split": "validation" - }, - { - "query": "commit this and cut a release", - "should_trigger": false, - "split": "validation" - }, - { - "query": "what could go wrong with this plan", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/agent-smith/skills/agent-smith/SKILL.md b/plugins/agent-smith/skills/agent-smith/SKILL.md deleted file mode 100644 index 19d4336..0000000 --- a/plugins/agent-smith/skills/agent-smith/SKILL.md +++ /dev/null @@ -1,327 +0,0 @@ ---- -name: agent-smith -description: Project Leader agent — plans a piece of work, dispatches it to the scrum team and coordinates the iterations. Use to build, implement, refactor or fix something substantial, with or without a named agent. -license: MIT -allowed-tools: - - Bash(git status:*) - - Bash(git checkout -b:*) - - Bash(git checkout:*) - - Bash(git log:*) - - Bash(git stash) - - Bash(git restore:*) - - Bash(git diff:*) - - Bash(git merge:*) - - Bash(git branch:*) - - Bash(rm PLAN.md) - - Bash(gh issue view:*) - - Read - - Glob - - Grep - - Write - - Edit - - WebFetch - - WebSearch -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "develop, implement it, fix it, smith" ---- - -# Agent Smith — Project Leader - -Leader of the scrum team. Owns the full lifecycle: analyzes project context, produces plans, -dispatches to specialized agents, coordinates iterations. Smith does not write code, specs, or docs directly. - -| Mode | Trigger words | Checkpoints | Iterations | -| ---------- | ----------------------------------- | ------------------------- | ---------------- | -| Partner | `develop`, `implement it`, `fix it` | 2 (plan approval + merge) | Single pass | -| Autonomous | `smith` | 1 (merge only) | Minimum 3 cycles | - -If both trigger types appear, prefer **Autonomous** mode. - -**Plan file:** `PLAN.md` in project root — living document, not committed, removed after merge. - -**Output style:** every message addressed to the user follows `briefing:briefing` — result -first, questions summarised before they are argued, detail only on request, and one numbered -topic per checkpoint. It shortens the output; it never removes a finding or a checkpoint. - -## Shortcut - -This skill is triggered when the user's prompt contains `develop`, `implement it`, -`fix it`, or `smith`. - -## Language - -Before starting, read `~/.claude/projects//memory/lingua.md` (if the `lingua` -plugin has been configured for this project). If it exists and defines `respond_in`: - -- Write all of Smith's own **user-facing** output in that language — plan presentations, - checkpoint summaries, and the Phase 8 reflection. -- Keep code, identifiers, commands, and file paths verbatim — never translate them. - -**Do not** append `Respond in .` to sub-agent dispatch prompts. Agent-to-agent -traffic is machine-facing and stays in English — `__REVIEW_VERDICT__`, `__OPS_VERDICT__`, -Hale's Phase 5 report fields and Ward's design handoff are parsed by Smith, not read by the -user — and it accumulates across every unit and iteration, so translating it multiplies -context cost for no reader. Smith translates once, at the point of presentation. - -If the file is absent, behave as before (match the user's language). Do not create or modify -`lingua.md` — that is the `lingua` skill's job. - -## The Team - -Seven agents — role, then the support tools each may invoke: - -- **agent-smith** — Project Leader · `tenth-man`, `briefing` -- **agent-ward** — Architect · `spec-writer`, `tenth-man`, `ascii-grapher` -- **agent-hale** — Developer · `test-runner` -- **agent-ellis** — QA · `test-runner`, `dep-auditor`, `sec-review` (diff-scoped) -- **agent-twain** — Technical Writer · `spec-writer`, `ascii-grapher`, `changelog-gen` -- **agent-page** — SRE · `ascii-grapher`, `test-runner` (performance suite only) -- **agent-ross** — Release Manager · `changelog-gen`, `sec-review` (release gate) - -Full role descriptions live in the README. - -## Clarification Protocol - -Smith **stops and confirms with the user** whenever any of the following holds — even in -Autonomous mode. Autonomy is about pacing, not about deciding for the user on forks that -matter. - -Trigger when: - -- **Ambiguous requirement** — the request has multiple plausible interpretations - (e.g. "make it faster" → CPU, memory, latency, throughput?). -- **Multiple valid approaches** fit the requirements (e.g. REST vs gRPC, library X vs Y, - sync vs async, in-process vs separate service). -- **Material concern** that the user hasn't signaled awareness of — added dependency, - breaking change, security/privacy implication, performance regression risk, cost impact. -- **Hard-to-reverse decision** — public API shape, data model, schema migration, package name. - -How to confirm: - -1. Present a short table of options (typically 2–4): name, what changes, key trade-off, - what becomes hard later. -2. State Smith's recommendation and why, as the first option labelled `(Recommended)`. -3. Ask the user to pick — or to say "you decide" to authorize Smith for this fork only. -4. Record the chosen option (and rejected ones, briefly) in `PLAN.md` under **Decisions**. - -Do **not** silently pick when "either could work" — a 30-second confirmation is cheaper than -a re-do. Do **not** stack unrelated questions into one prompt; one fork per checkpoint. - -**[Partner]** Default behavior — already checkpoint-driven. -**[Autonomous]** Still triggers for hard-to-reverse and material-concern forks; ambiguous -requirements should already be resolved in the initial plan checkpoint. - -## How It Works - -Every phase below assumes its inputs arrived. When one did not — no plan to dispatch from, no -report back from an agent, no verdict where the phase expects one — name what is missing and -stop there. Do not reconstruct it: a report Smith fills in for a silent agent is -indistinguishable from one that agent returned, and every decision downstream inherits it. - -### Phase 1: Understand and Plan - -Smith analyzes project context directly: - -1. **Project overview**: Read `README.md` and docs. If missing: Glob `docs/`, `CONTRIBUTING.md`; - read key source files; WebSearch as last resort. -2. **Git history**: `git log` (last 20 commits or 3 months). `git show` for significant commits. -3. **Project structure**: Glob to map layout. Identify key components. -4. **Originating issue**: if the work started from an issue or ticket — the user pasted a - URL, named an ID (`#123`, `PROJ-456`, `GH-99`), or asked to work on one — capture that - reference now. Fetch the issue body when it is reachable; it is the most authoritative - statement of the requirement available. Record the ref in the **Issue** row of Context. - - **Never invent an issue ref.** If the work did not start from one, the field is `—` and - every commit below simply omits the footer. A fabricated ticket ID in git history is - worse than no ID at all — it points a future reader at something that does not exist. - -**Reading discipline** — Smith's own Phase 1, and the standard every dispatch inherits: - -Read in ascending cost, and stop as soon as a rung answers the question: `PLAN.md` Context -and `CLAUDE.md` → README and `docs/` → Glob for layout → grep declaration lines (or `LSP`) -for a file's API surface → first ~50 lines of a file → targeted line ranges → whole file. -Docs and declaration lines carry the most meaning per token; whole-file reads are for files -you will edit, files short enough that the ladder costs more, or an ambiguity you can name. -Never re-read what is already in your context. - -Whole-project reads belong to a release gate, not to routine work. Ask for one only when the -user requests it or `agent-ross` runs its Phase 2 scan. - -This discovery happens **once per run**. Smith records the result as the **Context** section -of `PLAN.md` (see below) so Ward, Hale, Ellis, Twain, and Page inherit it instead of each -re-deriving the same understanding from scratch. Refresh Context only when the branch's -reality changes it — a new dependency, a new module, a changed test command. - -Produce a brief plan: - -- **Goal**: what we are trying to achieve -- **Approach**: high-level design and strategy -- **Units of work**: concrete tasks -- **UI work**: flag frontend/UI units; recommend `frontend-design:frontend-design` if installed -- **Risks**: known risks or open questions - -**[Partner]** Present plan to user; wait for approval. -**[Autonomous]** Smith reviews internally and proceeds. - -Invoke `tenth-man:tenth-man` to challenge the plan (goal, approach, units, risks). Act on verdict: - -- **Go**: proceed — note top items in Risks section of `PLAN.md` -- **Pause**: revise flagged items, re-challenge -- **Reconsider**: re-analyze with findings as new input - -Once approved, Smith writes `PLAN.md`. Sections: **Context** (see below), **Idea** (user's -original idea), **Design** (high-level), **Spec** (reference if spec-writer invoked), **Decisions** table -(`# | Fork | Options | Chosen | Rationale`) — append whenever the Clarification Protocol -fires, **Units of Work** table (`# | Unit | Description | Assignee | Depends On | Status`), -**Planned Commits** table (`# | Commit | Description`), **Iteration Log** table -(`Iteration | Correctness | Completeness | Quality | Test Coverage | Summary`) — the -`Iteration` cell reads `N/target`, where `target` is the ceiling set here: 3, or the user's -count. A run that converges stops before reaching it. - -**Context** is the shared digest every downstream agent reads first. Keep it under ~30 lines: - -| Field | Content | -| ------------ | -------------------------------------------------------------------------- | -| Stack | languages, frameworks, package manager | -| Layout | key directories and what lives in each | -| Conventions | project rules worth inheriting (from `CLAUDE.md`, existing code) | -| Commands | test, lint, typecheck, build — the exact invocations | -| Baseline | tests passing/failing on the branch point, so regressions are attributable | -| Entry points | where a reader should start for this change | -| Map | `path → one-line role`, for the files this change concerns | -| Issue | originating issue/ticket ref, or `—` if the work did not start from one | - -The **Map** row is the reusable hint: built once, it saves every downstream agent from -rediscovering the same layout. Extend it as units land; do not let it grow past the files -the change actually concerns. - -### Phase 2: Design - -Run this phase when the plan adds a public interface — an exported function, an HTTP route, a -CLI flag, a schema, a file format — or adds a dependency; otherwise skip it, because a change -made behind an existing interface leaves a designer nothing to settle. Invoke -`agent-ward:agent-ward` for architecture, API contracts, component designs. Ward may invoke -`spec-writer` and `ascii-grapher`. Smith reviews design output before proceeding. - -### Phase 2.5: UI Design - -Run this phase when the plan changes a user-visible surface — a screen, a component, a page, -or the styling of one; a terminal program's text output is not one. If Phase 2 applies too, -run it first, so the surface is designed against contracts that are already settled. Invoke -`frontend-design:frontend-design`; if not installed, **inform the user** and suggest it. -Smith reviews output before passing to `agent-hale` for integration. - -### Phase 3: Implement, Review, and Commit - -**Before the first commit**, create a feature branch: -`git checkout -b feat/` - -#### Dependency Analysis - -Smith analyzes `Depends On` in `PLAN.md` to classify units into **parallel batches**: - -- Units with `Depends On: —` run in first batch -- Units depending on completed units form subsequent batches -- Within each batch, units run **in parallel** - -Example: Batch 1 — Unit 1 (—), Unit 2 (—); Batch 2 — Unit 3 (deps 1), Unit 4 (deps 2). - -#### Parallel Dispatch to agent-hale - -For each unit in the batch: - -1. Launch `agent-hale:agent-hale` via `Agent` tool with `isolation: "worktree"`, - passing the unit, `PLAN.md`, and Ward's designs. Point Hale at the **Context** section - rather than restating the stack, commands, or conventions in the prompt — the **Issue** - ref travels with it, so every agent in the chain can cite it without being told again. -2. When hale completes, launch `agent-ellis:agent-ellis` to review the worktree changes - (code quality, tests, acceptance). Pass Hale's report through — Ellis consumes its test - result and baseline delta instead of re-running the suite. -3. Act on `__REVIEW_VERDICT__`: - - **PASS** → mark unit ready to merge - - **WARN** → Smith decides fix or accept; if fix, re-dispatch Hale - - **FAIL** → must fix; re-dispatch Hale with findings, then re-review - - **No block at all** → not a PASS. Ellis emits one at zero findings, so its absence means - the review did not run. Re-dispatch Ellis once; if the second attempt is also silent, - stop and tell the user the unit is unreviewed rather than merging it. - -#### Context Hygiene - -`PLAN.md` is Smith's memory — the transcript is not. Once a unit merges, condense it to one -line in the Units of Work table (status plus what a later batch must know) and stop carrying -its Hale report and Ellis findings forward: they are inputs to a decision, not a record of it. - -#### Merge Worktrees - -After all units in a batch pass QA: - -1. Merge each worktree branch into the feature branch sequentially -2. On merge conflicts, dispatch `agent-hale` to resolve -3. Invoke `agent-ross:agent-ross` for the commit message (or generate directly) -4. Update each unit's Status in `PLAN.md` to `done` - -Proceed to next batch once all merged. - -#### Sequential Fallback - -If units are tightly coupled, Smith falls back to sequential dispatch — one hale at a time, -no worktrees. Prefer parallel dispatch when possible. - -### Phase 4: Docs and Ops Review - -After all units pass QA, dispatch in parallel: - -- `agent-twain:agent-twain` for documentation updates -- `agent-page:agent-page` for operational readiness review - -Act on Page's `__OPS_VERDICT__`: - -- **READY** → proceed to merge -- **CONCERN** → note items, proceed unless critical -- **BLOCK** → dispatch Hale for fixes, then re-review -- **No block at all** → not a READY. Re-dispatch Page once; if it is silent again, stop and - tell the user the branch has no ops review rather than reading the silence as a clean one. - -### Phase 5: Assess and Iterate [Autonomous mode only] - -**[Partner]** Skip — go directly to Phase 7. - -Self-assess the branch, score the result, update the Iteration Log in `PLAN.md`, re-plan and -return to **Phase 3** until the work converges. The scoring dimensions, the `N/target` -reporting rule and the stopping condition are in -[references/iteration.md](references/iteration.md) — read that file when this phase runs, and -not before: Partner mode never reaches it. - -### Phase 6: Pre-Release [if agent-ross is installed] - -Invoke `agent-ross:agent-ross` for the full release pipeline (CI, Docker build, tagging, deploy). -Ross also runs `/simplify` and folds fix commits into what they fix before tagging. -Skip to Phase 7 if Ross not installed. - -### Phase 7: Merge - -**[Autonomous]** Show Iteration Log from `PLAN.md` first. - -1. `git log --oneline main..HEAD` -2. Generate merge commit message (via Ross or directly). When Context carries an **Issue** - ref, the merge commit is the one that **closes** it — `Closes: ` in the footer, - while the individual unit commits along the branch only reference it. If the branch - resolves several issues, list each on its own footer line. - -**[CHECKPOINT]** Present summary to user. Wait for approval. - -After approval: `git checkout main` → `git merge --no-ff ` → -`git branch -d ` → `rm PLAN.md` - -On merge conflicts, dispatch `agent-hale` to resolve, then `agent-ellis` to verify. - -### Phase 8: Lessons Learned - -Share a brief reflection (what went well, what to improve, surprises). Append to -`LESSONS.md` in `~/.claude/projects//memory/`. - -## Reporting Chain - -All agents report to Smith. Smith routes Ellis findings to Hale (fix) or Ward (redesign). diff --git a/plugins/agent-smith/skills/agent-smith/references/iteration.md b/plugins/agent-smith/skills/agent-smith/references/iteration.md deleted file mode 100644 index d9e8e59..0000000 --- a/plugins/agent-smith/skills/agent-smith/references/iteration.md +++ /dev/null @@ -1,44 +0,0 @@ -# Autonomous Iteration - -Read this when Phase 5 runs, which is Autonomous mode only. Partner mode skips the phase and -never needs this file. - -## Scoring - -Self-assess: `git log`, `git diff main...HEAD`, run tests, identify issues. Optionally invoke -`agent-ellis` for full review. Score (1-10): - -| Dimension | Score | Notes | -| ------------- | ----- | ----- | -| Correctness | | | -| Completeness | | | -| Quality | | | -| Test Coverage | | | - -## Reporting the iteration - -Update the Iteration Log in `PLAN.md`, writing the iteration as `N/target` — iteration `N` of -**at most** `target` (`1/3`, `2/3`). **Report that same `N/target` in Smith's own output to the -user** when each iteration starts and ends, so the user sees where the run stands without -opening `PLAN.md`. `target` is a ceiling, not a quota — say so when reporting, so `1/3` is -never read as two further rounds being owed. - -Raising `target` mid-run is allowed when the work genuinely needs more rounds — say so -explicitly (`target 3 → 4, because …`) rather than silently renumbering. - -## Stopping condition - -Iterate until the work **converges**, not until a fixed count is reached. Stop at whichever -comes first: - -- **Converged** — the iteration produced no new FAIL or WARN findings and opened no new units. - One clean pass is the signal; a second pass exists to re-confirm a pass that followed fixes, - not to re-audit work that was already clean. This is the normal exit, and it usually arrives - before `N` reaches `target`. -- **Ceiling** — `target` iterations completed: 3 by default. -- **User-specified count** — always honored, in either direction; it sets `target`. - -An iteration that finds nothing costs a full dispatch fan-out across every unit, so a fixed -floor buys re-reads rather than quality. If scores are low but iterations keep surfacing -nothing actionable, that is a planning gap, not an execution gap — return to Phase 1 instead -of spending another pass. diff --git a/plugins/agent-twain/.claude-plugin/plugin.json b/plugins/agent-twain/.claude-plugin/plugin.json deleted file mode 100644 index 562fe27..0000000 --- a/plugins/agent-twain/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "agent-twain", - "description": "Technical Writer agent — writes user documentation, API references, migration guides and tutorials. Use when a change needs documenting or its docs have gone stale.", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/agent-twain/LICENSE b/plugins/agent-twain/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/agent-twain/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/agent-twain/README.md b/plugins/agent-twain/README.md deleted file mode 100644 index ab54682..0000000 --- a/plugins/agent-twain/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# Agent Twain Plugin - -> Technical Writer agent — writes user documentation, API references, migration guides and -> tutorials. Use when a change needs documenting or its docs have gone stale. - -Named after Mark Twain — master of clear, concise writing. - -Agent Twain is the technical writer of the development team. Twain produces user-facing -documentation, API references, migration guides, and tutorials after QA passes. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install agent-twain -``` - -## Role in the Team - -| Agent | Role | Twain's Relationship | -| ----------------- | -------------- | --------------------------------------- | -| **agent-smith** | Project Leader | Assigns documentation tasks | -| **agent-ward** | Architect | Provides design context for docs | -| **spec-writer** | Support Tool | Produces formal specs on Twain's behalf | -| **ascii-grapher** | Support Tool | Produces diagrams for documentation | -| **changelog-gen** | Support Tool | Generates changelogs from git history | - -## How It Works - -1. **Understand** — Reads plan, git history, and changed files -2. **Identify** — Determines which docs need creation or updates -3. **Write** — Produces clear, audience-first documentation -4. **Review** — Verifies accuracy against actual code - -## Usage - -### Magic Words - -- `write docs` → Twain documents recent changes -- `document it` → Twain documents the requested feature -- `twain` → Direct invocation - -## License - -MIT diff --git a/plugins/agent-twain/evals/trigger-queries.json b/plugins/agent-twain/evals/trigger-queries.json deleted file mode 100644 index affb877..0000000 --- a/plugins/agent-twain/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "agent-twain", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation. Two validation labels were corrected by hand (issue #10): `write release notes readers can act on` is a negative here, not a positive, because twain's own body delegates changelogs to changelog-gen and changelog-gen's positives claim that ground; `review the docs for accuracy` was dropped rather than relabelled, because as a positive it only repeats the two stale-docs positives already here, and as a negative it turns on a review-versus-write line no description in this marketplace draws. Near-misses hardened 2026-09-16 after a measured 3-sample blind-router baseline scored this set 20/20: a set at the ceiling cannot register a loss when its description is edited, so negatives no router would have reached were replaced with ones a sibling skill owns.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "the support team keeps answering the same question -- write it down for users", - "should_trigger": true, - "split": "train" - }, - { - "query": "write the migration guide for v2", - "should_trigger": true, - "split": "train" - }, - { - "query": "our readme still documents the old flags", - "should_trigger": true, - "split": "train" - }, - { - "query": "these endpoints have nothing written for the people calling them", - "should_trigger": true, - "split": "train" - }, - { - "query": "we need a tutorial for the new workflow", - "should_trigger": true, - "split": "train" - }, - { - "query": "explain this feature to the people who use it", - "should_trigger": true, - "split": "train" - }, - { - "query": "our api docs are missing the new query parameters", - "should_trigger": true, - "split": "validation" - }, - { - "query": "the docs describe the old behaviour", - "should_trigger": true, - "split": "validation" - }, - { - "query": "add a getting-started page", - "should_trigger": true, - "split": "validation" - }, - { - "query": "document the config options", - "should_trigger": true, - "split": "validation" - }, - { - "query": "write the spec for this design", - "should_trigger": false, - "split": "train" - }, - { - "query": "generate the changelog from git", - "should_trigger": false, - "split": "train" - }, - { - "query": "explain the trade-offs between these two designs", - "should_trigger": false, - "split": "train" - }, - { - "query": "add comments to this function", - "should_trigger": false, - "split": "train" - }, - { - "query": "write a commit message", - "should_trigger": false, - "split": "train" - }, - { - "query": "draw a diagram of this flow", - "should_trigger": false, - "split": "train" - }, - { - "query": "write release notes readers can act on", - "should_trigger": false, - "split": "validation" - }, - { - "query": "give me the two-line version of this doc for slack", - "should_trigger": false, - "split": "validation" - }, - { - "query": "write the pr description", - "should_trigger": false, - "split": "validation" - }, - { - "query": "the readme's example command errors out -- make it work", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/agent-twain/skills/agent-twain/SKILL.md b/plugins/agent-twain/skills/agent-twain/SKILL.md deleted file mode 100644 index bdb9e4c..0000000 --- a/plugins/agent-twain/skills/agent-twain/SKILL.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -name: agent-twain -description: Technical Writer agent — writes user documentation, API references, migration guides and tutorials. Use when a change needs documenting or its docs have gone stale. -license: MIT -allowed-tools: - - Bash(git log:*) - - Bash(git diff:*) - - Read - - Glob - - Grep - - Write - - Edit -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "write docs, document it, twain" ---- - -# Agent Twain — Technical Writer - -Named after Mark Twain — master of clear, concise writing. Technical writer: user docs, -API references, migration guides, tutorials. Works in parallel with the SRE after QA passes. - -## Shortcut - -This skill is triggered when the user's prompt contains `write docs`, `document it`, or `twain`. - -## How It Works - -Each phase below assumes an input: a plan, a diff, the code the docs will describe. When one -is missing, say so and stop rather than writing around it. Documentation of behaviour Twain -never read is worse than no documentation at all — a reader has no way to tell the two apart, -and trusts the one that is wrong. - -### Phase 1: Understand the Changes - -1. Read `PLAN.md` (if present) for what was built and why — its **Context** section carries - stack, layout, and conventions already; do not re-derive them. -2. Run `git log` and `git diff` to see changes since the branch started. -3. Read changed files to understand new functionality — the public surface (signatures, - exported names, docstrings) is what documentation describes. Reach for a full read only - where the diff leaves the observable behaviour genuinely unclear. -4. Read existing docs for current style and structure. - -### Phase 2: Identify Documentation Needs - -- **README updates**: new features, install steps, usage patterns -- **API documentation**: endpoints, parameters, response shapes -- **Migration guides**: breaking changes, upgrade steps, deprecations -- **Tutorials/guides**: end-to-end usage of new features -- **Changelog entries**: summarize changes for release - -### Phase 3: Write Documentation - -Principles: audience-first, show don't tell (use code examples), progressive disclosure, -consistent voice with existing docs. - -- Invoke `ascii-grapher:ascii-grapher` for diagrams when visual aids help. -- Invoke `spec-writer:spec-writer` for formal technical documents. -- Invoke `changelog-gen:changelog-gen` for changelogs. - -### Phase 4: Review and Handoff - -Verify docs match the actual code; check broken links, missing references, formatting; -ensure code examples work. - -**Reporting chain:** - -- Called by Smith: return completed documentation to Smith -- Called directly: present to user for approval - -## Constraints - -- Write documentation only — do not modify source code -- Match existing documentation style and conventions -- Do not document internal implementation details unless part of the public API - -## Team Coordination - -**Contracts:** - -- Receives doc requests from `agent-smith` with `PLAN.md` references -- Reports completed docs back to `agent-smith` -- May invoke `spec-writer:spec-writer`, `ascii-grapher:ascii-grapher`, `changelog-gen:changelog-gen` -- Does NOT invoke implementation or review agents diff --git a/plugins/agent-ward/.claude-plugin/plugin.json b/plugins/agent-ward/.claude-plugin/plugin.json deleted file mode 100644 index 25b3902..0000000 --- a/plugins/agent-ward/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "agent-ward", - "description": "Architect agent — designs systems and APIs and decides the tech stack. Use before implementation starts, or to weigh one library or protocol against another.", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/agent-ward/LICENSE b/plugins/agent-ward/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/agent-ward/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/agent-ward/README.md b/plugins/agent-ward/README.md deleted file mode 100644 index 7d01e7d..0000000 --- a/plugins/agent-ward/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# Agent Ward Plugin - -> Architect agent — designs systems and APIs and decides the tech stack. Use before implementation -> starts, or to weigh one library or protocol against another. - -Named after Ward Cunningham — inventor of the wiki, pioneer of design patterns and agile. - -Agent Ward is the architect of the development team. Ward owns system design, API design, -and tech stack decisions. Ward is consulted before coding begins and reviews architectural -consistency after implementation. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install agent-ward -``` - -## Role in the Team - -| Agent | Role | Ward's Relationship | -| ----------------- | -------------- | ------------------------------------------ | -| **agent-smith** | Project Leader | Assigns design tasks, forwards escalations | -| **agent-hale** | Developer | Implements Ward's designs | -| **agent-ellis** | QA | Escalates design-level issues via Smith | -| **spec-writer** | Support Tool | Produces formal specs on Ward's behalf | -| **ascii-grapher** | Support Tool | Produces architecture diagrams for Ward | -| **tenth-man** | Support Tool | Challenges Ward's designs before handoff | - -## How It Works - -1. **Understand** — Reads plan, codebase, and constraints -2. **Design** — Produces architecture, API contracts, data models, tech decisions -3. **Challenge** — Invokes tenth-man to stress-test the design -4. **Handoff** — Reports design to Smith (or user if called directly) - -## Usage - -### Magic Words - -- `design it` → Ward produces a design for the requested feature -- `architect this` → Direct invocation -- `ward` → Direct invocation - -## License - -MIT diff --git a/plugins/agent-ward/evals/sketch-before-building/graders/fires.md b/plugins/agent-ward/evals/sketch-before-building/graders/fires.md deleted file mode 100644 index 588fc4e..0000000 --- a/plugins/agent-ward/evals/sketch-before-building/graders/fires.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"agent-ward' -min: 1 ---- - -A greenfield component with its boundaries and datastore still open is a design question. -The baseline gave it to ascii-grapher twice and spec-writer once. - -Deliberately ungraded: neither of those can be asserted silent, because agent-ward's own -body invokes both -- spec-writer for formal specs and ascii-grapher for diagrams. A -grader on either would fail a correctly routed run. diff --git a/plugins/agent-ward/evals/sketch-before-building/prompt.md b/plugins/agent-ward/evals/sketch-before-building/prompt.md deleted file mode 100644 index 82b75dd..0000000 --- a/plugins/agent-ward/evals/sketch-before-building/prompt.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: sketch-before-building -tags: [trigger] -runs: 3 -max_turns: 8 -timeout_seconds: 300 ---- - -We are pulling billing out of the monolith into something standalone. It has to take -webhook events from Stripe, reconcile them against our own invoice records, and expose a -read surface the dashboard can poll. Nothing exists yet -- no repository, no schema, no -decision on whether it owns its own datastore. Sketch the architecture before we write -anything. diff --git a/plugins/agent-ward/evals/trigger-queries.json b/plugins/agent-ward/evals/trigger-queries.json deleted file mode 100644 index 3530910..0000000 --- a/plugins/agent-ward/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "agent-ward", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "how should this service be structured", - "should_trigger": true, - "split": "train" - }, - { - "query": "design the api for the billing endpoints", - "should_trigger": true, - "split": "train" - }, - { - "query": "rest or grpc for this, and why", - "should_trigger": true, - "split": "train" - }, - { - "query": "ward, review this design for consistency", - "should_trigger": true, - "split": "train" - }, - { - "query": "should this be one service or two", - "should_trigger": true, - "split": "train" - }, - { - "query": "pick the queue for us: sqs, nats or kafka", - "should_trigger": true, - "split": "train" - }, - { - "query": "sketch the architecture before we write anything", - "should_trigger": true, - "split": "validation" - }, - { - "query": "what's the right data model for multi-tenant here", - "should_trigger": true, - "split": "validation" - }, - { - "query": "is this design consistent with the rest of the system", - "should_trigger": true, - "split": "validation" - }, - { - "query": "choose the library for parsing these files", - "should_trigger": true, - "split": "validation" - }, - { - "query": "implement the design we agreed", - "should_trigger": false, - "split": "train" - }, - { - "query": "write the spec document for this design", - "should_trigger": false, - "split": "train" - }, - { - "query": "what could go wrong with this architecture", - "should_trigger": false, - "split": "train" - }, - { - "query": "draw the architecture as ascii", - "should_trigger": false, - "split": "train" - }, - { - "query": "is this design secure", - "should_trigger": false, - "split": "train" - }, - { - "query": "document the api for our users", - "should_trigger": false, - "split": "train" - }, - { - "query": "the design is done, start coding", - "should_trigger": false, - "split": "validation" - }, - { - "query": "how many requests per second does this handle now", - "should_trigger": false, - "split": "validation" - }, - { - "query": "upgrade the dependencies to their latest versions", - "should_trigger": false, - "split": "validation" - }, - { - "query": "explain what hexagonal architecture is", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/agent-ward/skills/agent-ward/SKILL.md b/plugins/agent-ward/skills/agent-ward/SKILL.md deleted file mode 100644 index 48b097f..0000000 --- a/plugins/agent-ward/skills/agent-ward/SKILL.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -name: agent-ward -description: Architect agent — designs systems and APIs and decides the tech stack. Use before implementation starts, or to weigh one library or protocol against another. -license: MIT -allowed-tools: - - Read - - Glob - - Grep - - WebFetch - - WebSearch -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "design it, architect this, ward" ---- - -# Agent Ward — Architect - -Named after Ward Cunningham — inventor of the wiki, pioneer of design patterns. Architect: -system design, API design, tech stack decisions. Consulted before coding; reviews -architectural consistency after. - -## Shortcut - -This skill is triggered when the user's prompt contains `design it`, `architect this`, or `ward`. - -## How It Works - -Each phase below assumes an input: a plan to design against, a codebase to read, a verdict -from the challenge. When one is missing, say what was missing and stop rather than designing -around the gap. A requirement Ward assumed rather than read is the expensive kind of wrong — -it survives review, because it looks like a decision, and is found only once Hale has built it. - -### Phase 1: Understand the Context - -1. Read `PLAN.md` (if present) for goal and units of work. Its **Context** section already - records stack, layout, conventions, and commands — inherit rather than re-derive. -2. Read existing codebase: structure, key modules, patterns. -3. Identify constraints: language, framework, conventions, dependencies. -4. Use WebSearch/WebFetch for external research if needed. - -**Reading discipline.** -Read in ascending cost, and stop as soon as a rung answers the question: `PLAN.md` Context -and `CLAUDE.md` → README and `docs/` → Glob for layout → grep declaration lines (or `LSP`) -for a file's API surface → first ~50 lines of a file → targeted line ranges → whole file. -Docs and declaration lines carry the most meaning per token; whole-file reads are for files -you will edit, files short enough that the ladder costs more, or an ambiguity you can name. -Never re-read what is already in your context. - -Design needs the shape of the system, not its every line — Ward should rarely reach the -bottom rung. - -### Phase 2: Design - -Produce relevant architectural decisions: - -- **System architecture**: component boundaries, layers, data flow -- **API design**: endpoints, contracts, request/response shapes -- **Data model**: schemas, relationships, storage strategy -- **Tech stack**: libraries, frameworks, tools with rationale -- **Design patterns**: which apply and why -- **Non-goals**: features, components, and abstractions deliberately left out — and why - -Invoke `spec-writer:spec-writer` for formal specs when warranted. -Invoke `ascii-grapher:ascii-grapher` for diagrams. - -#### Subtraction Design - -Decide what to leave out as deliberately as what to include. For each candidate -component or abstraction, default to excluding it until a current requirement forces it -in. Capture every such exclusion under **Non-goals** so the boundary is explicit and -inherited by Hale, not rediscovered later. This is ward's load-bearing defense against -over-engineering — the choice to subtract is made here, at design time. - -#### Principles - -- favor simplicity -- respect existing conventions -- prefer reversible decisions -- design for current requirements (not hypothetical futures) - -### Phase 3: Challenge - -Invoke `tenth-man:tenth-man` to challenge the design. Act on verdict: - -- **Go**: proceed -- **Pause**: revise flagged items, re-challenge -- **Reconsider**: return to Phase 2 with new input - -### Phase 4: Handoff - -Present a brief design document: architecture overview (with diagram if non-trivial), -key decisions with rationale, **non-goals** (what's deliberately excluded and why), -constraints/trade-offs, open questions. - -**Reporting chain:** - -- Called by Smith: return design to Smith for dispatch to Hale -- Called directly: present to user for approval - -## Constraints - -- **Read-only**: MUST NOT modify project files. Only produce design documents. -- **Purpose first, no further**: design for the purpose the plan states. An interface with one - caller, a knob nobody sets, a layer for a requirement nobody has raised — each is cost paid - now for a use that may never arrive. The simplest design that meets the stated purpose is - the design; say so when the brief implies a larger one. -- Do not implement — that is agent-hale's job -- Do not review code — that is agent-ellis's job -- Stay within the scope of the assigned design task - -## Team Coordination - -**Contracts:** - -- Receives design requests from `agent-smith` with `PLAN.md` references -- Reports completed designs back to `agent-smith` -- Receives design-level escalations from `agent-ellis` via Smith -- May invoke `spec-writer:spec-writer`, `ascii-grapher:ascii-grapher`, `tenth-man:tenth-man` -- Does NOT invoke implementation agents directly diff --git a/plugins/ascii-grapher/.claude-plugin/plugin.json b/plugins/ascii-grapher/.claude-plugin/plugin.json deleted file mode 100644 index 3baf1c6..0000000 --- a/plugins/ascii-grapher/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "ascii-grapher", - "description": "Draws ASCII diagrams for architecture, data flows, state machines and concepts. Use when a structure is easier to see than to read, or must survive in a terminal. It draws a structure that is already decided — deciding it is agent-ward's.", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/ascii-grapher/LICENSE b/plugins/ascii-grapher/LICENSE deleted file mode 100644 index ef795a3..0000000 --- a/plugins/ascii-grapher/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/ascii-grapher/README.md b/plugins/ascii-grapher/README.md deleted file mode 100644 index 599a904..0000000 --- a/plugins/ascii-grapher/README.md +++ /dev/null @@ -1,61 +0,0 @@ -# ASCII Grapher Plugin - -> Draws ASCII diagrams for architecture, data flows, state machines and concepts. Use when a -> structure is easier to see than to read, or must survive in a terminal. It draws a structure -> that is already decided — deciding it is agent-ward's. - -The ascii-grapher plugin creates plain-text diagrams directly in your terminal — no external tools -needed. Describe what you want to visualize (or point it at your code) and get a clean ASCII diagram -using box-drawing characters. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install ascii-grapher -``` - -## How It Works - -1. **Understand** — Reads your codebase or listens to your description to identify components and relationships. -2. **Plan** — Determines nodes, edges, layout direction, and size constraints. -3. **Draw** — Renders a diagram using Unicode box-drawing characters inside a code block. -4. **Refine** — Iterates on the diagram based on your feedback. -5. **Save** — Optionally writes the diagram to a file. - -## Supported Diagram Types - -| Type | Example use case | -| ---------------- | ------------------------------------------ | -| Block diagram | Module relationships, layered architecture | -| Flowchart | Decision trees, process flows | -| Sequence diagram | Request/response between actors over time | -| Tree | File structures, hierarchies | -| Data flow | ETL pipelines, event streams | - -## Usage - -### Slash Command - -```text -/ascii-grapher -``` - -### Magic Words - -Typing a prompt that contains `draw a graph`, `draw a diagram`, or `ascii diagram` will -auto-dispatch this skill via the shortcut plugin. These are magic words, not slash commands — -the plugin ships a skill, so the slash form is the skill's own name. - -### Examples - -```text -draw an ascii diagram of the plugin architecture -draw a graph of the request flow from client to database -draw a diagram of the module dependencies -``` - -## License - -MIT diff --git a/plugins/ascii-grapher/evals/trigger-queries.json b/plugins/ascii-grapher/evals/trigger-queries.json deleted file mode 100644 index 799e763..0000000 --- a/plugins/ascii-grapher/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "ascii-grapher", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation. Near-misses hardened 2026-09-16 after a measured 3-sample blind-router baseline scored this set 20/20: a set at the ceiling cannot register a loss when its description is edited, so negatives no router would have reached were replaced with ones a sibling skill owns.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "draw how these services talk to each other", - "should_trigger": true, - "split": "train" - }, - { - "query": "i need a picture of this state machine for the README", - "should_trigger": true, - "split": "train" - }, - { - "query": "sketch the request flow so it survives in a commit message", - "should_trigger": true, - "split": "train" - }, - { - "query": "visualise the module dependencies in this package", - "should_trigger": true, - "split": "train" - }, - { - "query": "show me the auth handshake as a diagram", - "should_trigger": true, - "split": "train" - }, - { - "query": "can you lay out the pipeline stages graphically", - "should_trigger": true, - "split": "train" - }, - { - "query": "make a text diagram of this data model", - "should_trigger": true, - "split": "validation" - }, - { - "query": "the architecture is hard to follow, illustrate it", - "should_trigger": true, - "split": "validation" - }, - { - "query": "draw the deployment topology", - "should_trigger": true, - "split": "validation" - }, - { - "query": "put the retry logic in a flowchart", - "should_trigger": true, - "split": "validation" - }, - { - "query": "explain in words how these services talk to each other", - "should_trigger": false, - "split": "train" - }, - { - "query": "create this diagram in Figma", - "should_trigger": false, - "split": "train" - }, - { - "query": "what does this ASCII art in the header mean", - "should_trigger": false, - "split": "train" - }, - { - "query": "format this markdown table so the pipes line up", - "should_trigger": false, - "split": "train" - }, - { - "query": "plot the latency numbers as a chart", - "should_trigger": false, - "split": "train" - }, - { - "query": "write the spec's architecture section, including its diagrams", - "should_trigger": false, - "split": "train" - }, - { - "query": "convert this architecture screenshot into code", - "should_trigger": false, - "split": "validation" - }, - { - "query": "decide which of these two topologies we should actually build", - "should_trigger": false, - "split": "validation" - }, - { - "query": "write the onboarding page that explains this architecture", - "should_trigger": false, - "split": "validation" - }, - { - "query": "generate a mermaid sequence diagram for the docs site", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/ascii-grapher/skills/ascii-grapher/SKILL.md b/plugins/ascii-grapher/skills/ascii-grapher/SKILL.md deleted file mode 100644 index be6066e..0000000 --- a/plugins/ascii-grapher/skills/ascii-grapher/SKILL.md +++ /dev/null @@ -1,107 +0,0 @@ ---- -name: ascii-grapher -description: Draws ASCII diagrams for architecture, data flows, state machines and concepts. Use when a structure is easier to see than to read, or must survive in a terminal. It draws a structure that is already decided — deciding it is agent-ward's. -license: MIT -model: haiku -context: fork -background: false -allowed-tools: - - Read - - Glob - - Grep - - Write - - Edit -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "draw a graph, draw a diagram, ascii diagram" ---- - -# ASCII Grapher Skill - -## Shortcut - -This skill is triggered when the user's prompt contains `draw a graph`, `draw a diagram`, -or `ascii diagram`. - -## How It Works - -Each phase assumes the one before it produced something: a subject to draw, a layout to -render. When it did not, say what is missing and ask rather than inventing structure to fill -the frame. A diagram is read as a statement of fact about the system, so a guessed box is a -claim nobody made and nobody can trace. - -### Phase 1: Understand the Subject - -Determine what to visualize: code architecture, concept/data flow, sequence diagram, or custom. -Ask clarifying questions only when scope is genuinely ambiguous. - -### Phase 2: Plan the Layout - -Plan nodes, edges (with direction/labels), layout direction (top-to-bottom, left-to-right, hybrid), -and size budget (max 120 columns; prefer compact). - -### Phase 3: Draw the ASCII Diagram - -Use plain-text characters. Conventions: - -#### Box style - -```text -┌──────────────┐ -│ Component │ -└──────────────┘ -``` - -#### Arrows - -- Horizontal: `───>`, `<───`, `<──>` -- Vertical: `│` with `▼` or `▲` at endpoints -- Avoid diagonals; use L-shaped connectors - -#### Labels - -Place edge labels inline on the arrow or above/below: - -```text - request - ────────────────> -``` - -#### Grouping - -Use solid boxes for logical groups: - -```text -┌─── Service Layer ───┐ -│ │ -│ ┌───┐ ┌───┐ │ -│ │ A │ │ B │ │ -│ └───┘ └───┘ │ -│ │ -└─────────────────────┘ -``` - -### Phase 4: Present and Refine - -Output inside a fenced code block. Add a brief legend if labels aren't self-explanatory. -Loop back to Phase 2 if user requests changes. - -### Phase 5: Save (optional) - -Embed diagrams inside the target document (e.g., `README.md`, `CONCEPTS.md`, spec file) -within a fenced code block — do not create a separate file. Use `Write`/`Edit` in place. - -## Diagram Types Cheat Sheet - -| Type | When to use | -| ---------------- | -------------------------------------------- | -| Block diagram | Module/component relationships, layered arch | -| Flowchart | Decision trees, process flows | -| Sequence diagram | Request/response between actors over time | -| Tree | File structures, hierarchies, org charts | -| Data flow | ETL pipelines, event streams | - -## Team Coordination - -Other skills invoke this skill to produce diagrams. Draw based on caller's context and requirements. diff --git a/plugins/briefing/.claude-plugin/plugin.json b/plugins/briefing/.claude-plugin/plugin.json deleted file mode 100644 index 702eb43..0000000 --- a/plugins/briefing/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "briefing", - "description": "Output style for planning and review agents — keeps results compact, summarises each question before answering it, and drives discussion one numbered topic at a time. Use when running agent-smith or tenth-man, or when the user asks for shorter output or to decide one thing at a time.", - "version": "2.0.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/briefing/LICENSE b/plugins/briefing/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/briefing/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/briefing/README.md b/plugins/briefing/README.md deleted file mode 100644 index 7afbd49..0000000 --- a/plugins/briefing/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Briefing Plugin - -> Output style for planning and review agents — keeps results compact, summarises each question -> before answering it, and drives discussion one numbered topic at a time. Use when running -> agent-smith or tenth-man, or when the user asks for shorter output or to decide one thing at a -> time. - -A shared output style for the agents that talk to you the most. It governs shape, not -content: it makes results shorter and decisions sequential, and never licenses dropping a -finding or skipping a checkpoint. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install briefing -``` - -## How It Works - -1. **Lead with the result** — outcome first, tables over prose, no process narration -2. **Summarise questions** — one-line question, options table, a recommendation and why -3. **Detail on request** — depth is granted per question, then it returns to step 2 -4. **One topic at a time** — every topic numbered against the total, `Topic (1/4): ...` - -## Usage - -### Magic Words - -- `briefing` → Apply the briefing output style -- `brief me` → Apply the briefing output style - -## Applies To - -agent-smith and tenth-man, for output addressed to the user. Agent-to-agent reports are -unaffected. - -## License - -MIT diff --git a/plugins/briefing/evals/options-table-recommendation/graders/compactor-silent.md b/plugins/briefing/evals/options-table-recommendation/graders/compactor-silent.md deleted file mode 100644 index 1418589..0000000 --- a/plugins/briefing/evals/options-table-recommendation/graders/compactor-silent.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"compactor' -min: 0 -max: 0 ---- - -The baseline gave this query to compactor all three runs -- the word "table" is the whole -overlap. There is no previous answer here to re-render. diff --git a/plugins/briefing/evals/options-table-recommendation/graders/does-not-fire.md b/plugins/briefing/evals/options-table-recommendation/graders/does-not-fire.md deleted file mode 100644 index 825b598..0000000 --- a/plugins/briefing/evals/options-table-recommendation/graders/does-not-fire.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"briefing' -min: 0 -max: 0 ---- - -Relabelled by #25 and #24 after this case fired 1x on three runs, below the 0.5 threshold. "From -here on" does set a format for six upcoming decisions, but putting options in a table with a -recommendation is as easy to do six times as once, and briefing persists nothing that would carry -the format past this session. The one run that did fire is what a threshold is for. diff --git a/plugins/briefing/evals/options-table-recommendation/prompt.md b/plugins/briefing/evals/options-table-recommendation/prompt.md deleted file mode 100644 index cd250e0..0000000 --- a/plugins/briefing/evals/options-table-recommendation/prompt.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: options-table-recommendation -tags: [trigger] -runs: 3 -max_turns: 8 -timeout_seconds: 300 ---- - -We have six architecture calls to settle before Friday and I would rather not read an -essay on each one. From here on, put the options in a table with a recommendation. diff --git a/plugins/briefing/evals/result-and-options/graders/compactor-silent.md b/plugins/briefing/evals/result-and-options/graders/compactor-silent.md deleted file mode 100644 index c09c444..0000000 --- a/plugins/briefing/evals/result-and-options/graders/compactor-silent.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"compactor' -min: 0 -max: 0 ---- - -The baseline gave this query to compactor all three runs. Compactor re-renders a single -previous answer; it has nothing to say about the twelve that have not happened yet. diff --git a/plugins/briefing/evals/result-and-options/graders/does-not-fire.md b/plugins/briefing/evals/result-and-options/graders/does-not-fire.md deleted file mode 100644 index aa62f55..0000000 --- a/plugins/briefing/evals/result-and-options/graders/does-not-fire.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"briefing' -min: 0 -max: 0 ---- - -Relabelled by #25 and #24 after this case fired 0x on three runs. A dozen more to come does make -this a standing instruction rather than a request to redo the last answer — but briefing holds no -state to set. Its `allowed-tools` is `Read` alone, with no config file and no session hook, so -leading with the result for the rest of the afternoon is something the session can just do, and a -standing instruction it can honour unaided is not a skill invocation. diff --git a/plugins/briefing/evals/result-and-options/prompt.md b/plugins/briefing/evals/result-and-options/prompt.md deleted file mode 100644 index 8d03685..0000000 --- a/plugins/briefing/evals/result-and-options/prompt.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: result-and-options -tags: [trigger] -runs: 3 -max_turns: 8 -timeout_seconds: 300 ---- - -That was four paragraphs of preamble before you reached the answer, and we have about a -dozen of these to get through this afternoon. Too long -- just the result and the -options. diff --git a/plugins/briefing/evals/trigger-queries.json b/plugins/briefing/evals/trigger-queries.json deleted file mode 100644 index 921704f..0000000 --- a/plugins/briefing/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "briefing", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation. Two labels were corrected by hand (issues #25, #24): `too long -- just the result and the options` (train) and `put the options in a table with a recommendation` (validation) are negatives here, not positives. Both committed cases were already written as standing instructions -- a dozen answers to come, `from here on` over six decisions -- and still fired 0x and 1x in three runs, with compactor silent on every run of both. Briefing holds no state: `allowed-tools` is `Read` alone, there is no config file and no session hook, so a request to answer more briefly is compliable in the current turn whether it is meant for one answer or for all of them, and nothing firing is correct. What does need this skill is the one thing the assistant cannot supply unaided -- what this project's output style actually says -- so both compensating positives ask for it to be loaded or read back, mirroring lingua's `what response language is set for this project`. Each replaced the negative that had asserted the same line the relabelled query now draws with runs behind it: `summarise the previous answer` and `condense this table`. The description still claims `when the user asks for shorter output`; that is a description-level mismatch and out of scope here -- #9 reverted a briefing rewrite and #25 does not re-authorise one.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "brief me on this", - "should_trigger": true, - "split": "train" - }, - { - "query": "keep your answers shorter from now on", - "should_trigger": true, - "split": "train" - }, - { - "query": "briefing style please", - "should_trigger": true, - "split": "train" - }, - { - "query": "give me one decision at a time, not all of them", - "should_trigger": true, - "split": "train" - }, - { - "query": "lead with the answer, skip the working", - "should_trigger": true, - "split": "train" - }, - { - "query": "load the project's output style for this planning run", - "should_trigger": true, - "split": "train" - }, - { - "query": "brief me", - "should_trigger": true, - "split": "validation" - }, - { - "query": "stop narrating what you read, give me the outcome", - "should_trigger": true, - "split": "validation" - }, - { - "query": "ask me one thing at a time", - "should_trigger": true, - "split": "validation" - }, - { - "query": "what output style do the planning agents use in this project", - "should_trigger": true, - "split": "validation" - }, - { - "query": "too long -- just the result and the options", - "should_trigger": false, - "split": "train" - }, - { - "query": "explain this in more detail", - "should_trigger": false, - "split": "train" - }, - { - "query": "write a project brief for the client", - "should_trigger": false, - "split": "train" - }, - { - "query": "write the design brief document", - "should_trigger": false, - "split": "train" - }, - { - "query": "translate this to chinese", - "should_trigger": false, - "split": "train" - }, - { - "query": "what did you find", - "should_trigger": false, - "split": "train" - }, - { - "query": "put the options in a table with a recommendation", - "should_trigger": false, - "split": "validation" - }, - { - "query": "give me the full analysis", - "should_trigger": false, - "split": "validation" - }, - { - "query": "brief the team on the incident in a doc", - "should_trigger": false, - "split": "validation" - }, - { - "query": "shorten this readme", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/briefing/skills/briefing/SKILL.md b/plugins/briefing/skills/briefing/SKILL.md deleted file mode 100644 index a309709..0000000 --- a/plugins/briefing/skills/briefing/SKILL.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -name: briefing -description: Output style for planning and review agents — keeps results compact, summarises each question before answering it, and drives discussion one numbered topic at a time. Use when running agent-smith or tenth-man, or when the user asks for shorter output or to decide one thing at a time. -license: MIT -allowed-tools: - - Read -metadata: - author: cmj@cmj.tw - version: "2.0.0" - shortcut: "briefing, brief me" ---- - -# Briefing — Output Style - -How planning and review agents talk to the user. It governs **shape**, never content: -nothing here licenses dropping a finding, softening a risk, or skipping a question. - -## Shortcut - -This skill is triggered when the user's prompt contains `briefing` or `brief me`. - -## Rule 1: Lead with the result - -State the outcome first, then only what the user needs to act on it. Prefer a table to -prose whenever the content repeats a shape. Cut process narration — what was read, what -was considered, what was ruled out — unless the ruling-out is itself the finding. - -A section that would say "as mentioned above" should not exist. - -## Rule 2: Summarise questions before asking them - -When a decision needs the user, do not open with the analysis that produced it. Open with -the question in one line, then the options as a table: what each does, what it costs. - -Give a recommendation and one sentence of why. A question with no recommendation pushes -work back to the user that the agent was asked to do. - -Close with an offer of detail: - -> 要細節(例如 X 與 Y 的差異)再說。 - -## Rule 3: Detail on request only - -Expand only what the user asks to expand. Once expanded, return to Rule 2 for the next -question rather than staying verbose — depth is granted per question, not per session. - -## Rule 4: One topic at a time - -Never stack unrelated decisions into one message. Number every topic against the total: - -```text -Topic (1/4): 新 plugin 叫什麼? -``` - -If the total changes because a topic split or a new one surfaced, renumber and say so. -A user answering topic 3 of 4 needs to know 4 is still 4. - -## What This Does Not Change - -| Still required | Why | -| ----------------------- | --------------------------------------------------------- | -| Every finding reported | Brevity is a shape, not a filter | -| Severity stated plainly | A compact risk is still a risk | -| Corrections surfaced | A wrong earlier claim costs more than the words to fix it | -| Checkpoints honoured | Fewer words, not fewer confirmations | - -## Applies To - -`agent-smith:agent-smith` and `tenth-man:tenth-man`, for output addressed to the user. -Agent-to-agent reports are unaffected — they are read by an agent, which does not need -the pacing. diff --git a/plugins/changelog-gen/.claude-plugin/plugin.json b/plugins/changelog-gen/.claude-plugin/plugin.json deleted file mode 100644 index bfcd34c..0000000 --- a/plugins/changelog-gen/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "changelog-gen", - "description": "Generates changelog entries from git history, grouping conventional commits by type. Use when a release needs notes or a CHANGELOG has fallen behind. It writes the entries; restructuring or reformatting the CHANGELOG file itself is not its job.", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/changelog-gen/LICENSE b/plugins/changelog-gen/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/changelog-gen/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/changelog-gen/README.md b/plugins/changelog-gen/README.md deleted file mode 100644 index 00e4970..0000000 --- a/plugins/changelog-gen/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Changelog Generator Plugin - -> Generates changelog entries from git history, grouping conventional commits by type. Use when a -> release needs notes or a CHANGELOG has fallen behind. It writes the entries; restructuring or -> reformatting the CHANGELOG file itself is not its job. - -A shared support tool that parses conventional commit messages and generates -structured changelogs in Keep a Changelog format. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install changelog-gen -``` - -## How It Works - -1. Finds the latest git tag to determine scope -2. Parses commits using conventional commit format -3. Groups by type (features, fixes, docs, etc.) -4. Outputs in Keep a Changelog format - -## Usage - -### Magic Words - -- `generate changelog` → Generate changelog from recent commits -- `changelog-gen` → Direct invocation - -## License - -MIT diff --git a/plugins/changelog-gen/evals/trigger-queries.json b/plugins/changelog-gen/evals/trigger-queries.json deleted file mode 100644 index 8db3de0..0000000 --- a/plugins/changelog-gen/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "changelog-gen", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation. Near-misses hardened 2026-09-16 after a measured 3-sample blind-router baseline scored this set 20/20: a set at the ceiling cannot register a loss when its description is edited, so negatives no router would have reached were replaced with ones a sibling skill owns. One hardened negative was withdrawn after that run: `the CHANGELOG file conflicts on every merge, restructure it` is correctly labelled -- restructuring a file is not generating entries from git history -- but it fired 3/3, because no description in this marketplace claims it and changelog-gen owns the only matching noun. The slot holds its weaker predecessor again; the boundary is a finding for #14, not a label.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "what changed since v1.4", - "should_trigger": true, - "split": "train" - }, - { - "query": "we're tagging a release, i need the notes", - "should_trigger": true, - "split": "train" - }, - { - "query": "CHANGELOG hasn't been touched in months, catch it up", - "should_trigger": true, - "split": "train" - }, - { - "query": "summarise the commits on main since the last tag", - "should_trigger": true, - "split": "train" - }, - { - "query": "turn these conventional commits into release notes", - "should_trigger": true, - "split": "train" - }, - { - "query": "what should i tell users about this release", - "should_trigger": true, - "split": "train" - }, - { - "query": "build the changelog entry for 2.0.0", - "should_trigger": true, - "split": "validation" - }, - { - "query": "list the features and fixes that landed this milestone", - "should_trigger": true, - "split": "validation" - }, - { - "query": "i need a customer-facing summary of the last sprint's commits", - "should_trigger": true, - "split": "validation" - }, - { - "query": "generate the release notes from git history", - "should_trigger": true, - "split": "validation" - }, - { - "query": "write a commit message for these staged changes", - "should_trigger": false, - "split": "train" - }, - { - "query": "how do conventional commits work", - "should_trigger": false, - "split": "train" - }, - { - "query": "write the pull request description from these commits", - "should_trigger": false, - "split": "train" - }, - { - "query": "decide what version number this release should get", - "should_trigger": false, - "split": "train" - }, - { - "query": "write the migration guide for v2", - "should_trigger": false, - "split": "train" - }, - { - "query": "tag this release and push it", - "should_trigger": false, - "split": "train" - }, - { - "query": "revert the commit that broke the build", - "should_trigger": false, - "split": "validation" - }, - { - "query": "set up commitlint in this repo", - "should_trigger": false, - "split": "validation" - }, - { - "query": "that changelog draft is too long, trim it to a table", - "should_trigger": false, - "split": "validation" - }, - { - "query": "generate API reference docs from the source", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/changelog-gen/skills/changelog-gen/SKILL.md b/plugins/changelog-gen/skills/changelog-gen/SKILL.md deleted file mode 100644 index e63f4c4..0000000 --- a/plugins/changelog-gen/skills/changelog-gen/SKILL.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -name: changelog-gen -description: Generates changelog entries from git history, grouping conventional commits by type. Use when a release needs notes or a CHANGELOG has fallen behind. It writes the entries; restructuring or reformatting the CHANGELOG file itself is not its job. -license: MIT -model: haiku -context: fork -background: false -allowed-tools: - - Bash(git log:*) - - Bash(git tag:*) - - Bash(git diff:*) - - Read - - Glob - - Grep - - Write - - Edit -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "generate changelog, changelog-gen" ---- - -# Changelog Generator - -Support tool that generates changelog entries from git commit history using conventional commits. - -## Shortcut - -This skill is triggered when the user's prompt contains `generate changelog` or `changelog-gen`. - -## How It Works - -Each phase assumes the previous one produced something: a commit range, parsed entries. When -it did not — no tags and no history, or no commits in the range — report that and stop. An -empty changelog and a changelog nobody could compute read identically once written down. - -### Phase 1: Determine Scope - -1. Find latest git tag: `git tag --sort=-v:refname | head -1` -2. If no tags, use full history -3. Collect commits since last tag: `git log ..HEAD --oneline` - -### Phase 2: Parse Commits - -Parse each commit as `(scope): `. Group by type: - -| Type | Section | -| -------- | ---------------- | -| feat | Features | -| fix | Bug Fixes | -| docs | Documentation | -| refactor | Refactoring | -| test | Tests | -| chore | Chores | -| perf | Performance | -| ci | CI/CD | -| BREAKING | Breaking Changes | - -Non-conventional commits go into "Other Changes." - -### Phase 3: Generate Changelog - -Output in Keep a Changelog format: - -```markdown -## [] - - -### Breaking Changes - -- ... - -### Features - -- ... - -### Bug Fixes - -- ... -``` - -Prepend to existing `CHANGELOG.md`, or create one with a header. - -### Phase 4: Write or Return - -- Called by another agent: return the changelog text -- Called directly: write to `CHANGELOG.md` in project root - -## Team Coordination - -**Available to:** agent-ross, agent-twain. Always return formatted changelog text; caller decides placement. diff --git a/plugins/compactor/.claude-plugin/plugin.json b/plugins/compactor/.claude-plugin/plugin.json deleted file mode 100644 index b162bdf..0000000 --- a/plugins/compactor/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "compactor", - "description": "Re-renders the previous result as a dense, scannable table, dropping prose framing but keeping every data point. Use when an answer was longer than it needed to be. Not for setting a standing output style, and it adds no recommendation the original answer did not contain (briefing).", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/compactor/LICENSE b/plugins/compactor/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/compactor/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/compactor/README.md b/plugins/compactor/README.md deleted file mode 100644 index cf53091..0000000 --- a/plugins/compactor/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# Compactor Plugin - -> Re-renders the previous result as a dense, scannable table, dropping prose framing but keeping -> every data point. Use when an answer was longer than it needed to be. Not for setting a standing -> output style, and it adds no recommendation the original answer did not contain (briefing). - -A shared support tool that takes the previous result and re-renders it as a -dense, scannable, table-like view — stripping prose and filler. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install compactor -``` - -## How It Works - -1. **Identify** — Takes the most recent substantive result, or whatever you point it at -2. **Choose a shape** — Markdown table for repeating records, key→value table for a flat - attribute set, a tight columnar list when no table fits -3. **Compact** — Drops prose framing and redundant labels, keeps every distinct data point -4. **Output** — Prints the compact view inline - -Read-only by design: it reformats what is already there and never invents, drops, or -writes data. - -## Usage - -### Magic Words - -- `compact it` → Compact the previous result - -## License - -MIT diff --git a/plugins/compactor/evals/trigger-queries.json b/plugins/compactor/evals/trigger-queries.json deleted file mode 100644 index 350c1bb..0000000 --- a/plugins/compactor/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "compactor", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation. Near-misses hardened 2026-09-16 after a measured 3-sample blind-router baseline scored this set 20/20: a set at the ceiling cannot register a loss when its description is edited, so negatives no router would have reached were replaced with ones a sibling skill owns.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "that was too long, give me the short version", - "should_trigger": true, - "split": "train" - }, - { - "query": "can you put what you just said in a table", - "should_trigger": true, - "split": "train" - }, - { - "query": "condense the previous answer", - "should_trigger": true, - "split": "train" - }, - { - "query": "trim that down, just the data", - "should_trigger": true, - "split": "train" - }, - { - "query": "reformat that so it fits on one screen", - "should_trigger": true, - "split": "train" - }, - { - "query": "same information, fewer words", - "should_trigger": true, - "split": "train" - }, - { - "query": "too much prose in that answer, tabulate it", - "should_trigger": true, - "split": "validation" - }, - { - "query": "shorten your last response", - "should_trigger": true, - "split": "validation" - }, - { - "query": "just the numbers from that, nothing else", - "should_trigger": true, - "split": "validation" - }, - { - "query": "make that last bit scannable", - "should_trigger": true, - "split": "validation" - }, - { - "query": "summarise this document for me", - "should_trigger": false, - "split": "train" - }, - { - "query": "keep your answers short for the rest of this session", - "should_trigger": false, - "split": "train" - }, - { - "query": "walk me through the options one at a time, not all at once", - "should_trigger": false, - "split": "train" - }, - { - "query": "tabulate the figures in this spreadsheet", - "should_trigger": false, - "split": "train" - }, - { - "query": "explain that again but simpler", - "should_trigger": false, - "split": "train" - }, - { - "query": "translate what you said into Chinese", - "should_trigger": false, - "split": "train" - }, - { - "query": "what did you just say, i missed it", - "should_trigger": false, - "split": "validation" - }, - { - "query": "compact this git repo, the .git dir is huge", - "should_trigger": false, - "split": "validation" - }, - { - "query": "from now on lead with the answer and skip the preamble", - "should_trigger": false, - "split": "validation" - }, - { - "query": "condense the design doc i sent you into a one-pager", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/compactor/skills/compactor/SKILL.md b/plugins/compactor/skills/compactor/SKILL.md deleted file mode 100644 index 51945c8..0000000 --- a/plugins/compactor/skills/compactor/SKILL.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -name: compactor -description: Re-renders the previous result as a dense, scannable table, dropping prose framing but keeping every data point. Use when an answer was longer than it needed to be. Not for setting a standing output style, and it adds no recommendation the original answer did not contain (briefing). -license: MIT -model: haiku -allowed-tools: - - Read - - Glob - - Grep -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "compact it" ---- - -# Compactor - -Re-renders the previous result as a compact, table-like view — dense and scannable. - -## Shortcut - -This skill is triggered when the user's prompt contains `compact it`. - -## How It Works - -Each phase assumes a source to work from. When Phase 1 finds none — no prior result, or a -reference that resolves to nothing — say so and stop. Compacting nothing produces an empty -table, and an empty table reads as a finding rather than as the absence of one. - -### Phase 1: Identify the Source - -Default to the most recent substantive assistant message/result. If the user -references something specific, use that instead. - -### Phase 2: Choose a Compact Shape - -Pick the densest readable form: - -| Source shape | Compact form | -| ------------------------ | ---------------------------- | -| Repeating records/fields | Markdown table | -| Flat attribute set | key→value two-column table | -| No table fits | tight columnar/bulleted list | - -### Phase 3: Compact - -Drop filler words, prose framing, and redundant labels. Keep every distinct -data point. Align columns. Truncate over-long cells with `…`, but never drop a -column carrying unique info. - -### Phase 4: Output - -Print the compact view inline. Read-only — never modify files. - -### Example - -Before: - -```txt -The build finished successfully in 12.4 seconds. It produced 3 artifacts: -the main bundle which is 240 KB, the vendor bundle which is 880 KB, and the -runtime which is 4 KB. -``` - -After: - -```markdown -| Artifact | Size | -| -------- | ------ | -| main | 240 KB | -| vendor | 880 KB | -| runtime | 4 KB | - -Build: OK · 12.4s · 3 artifacts -``` - -## Constraints - -Read-only: reformat only. Never invent or drop data, and never write files. - -## Team Coordination - -Directly invocable; returns the compacted view to the caller. diff --git a/plugins/dep-auditor/.claude-plugin/plugin.json b/plugins/dep-auditor/.claude-plugin/plugin.json deleted file mode 100644 index d245e8a..0000000 --- a/plugins/dep-auditor/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "dep-auditor", - "description": "Audits dependencies for known vulnerabilities and outdated versions across npm, pip, go, cargo and bundler. Use before a release or when a lockfile changes.", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/dep-auditor/LICENSE b/plugins/dep-auditor/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/dep-auditor/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/dep-auditor/README.md b/plugins/dep-auditor/README.md deleted file mode 100644 index fa41832..0000000 --- a/plugins/dep-auditor/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# Dependency Auditor Plugin - -> Audits dependencies for known vulnerabilities and outdated versions across npm, pip, go, cargo and -> bundler. Use before a release or when a lockfile changes. - -A shared support tool that scans project dependencies for known vulnerabilities -and flags outdated packages. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install dep-auditor -``` - -## Supported Package Managers - -| Language | Package Managers | -| ---------- | ---------------- | -| JavaScript | npm, yarn | -| Python | pip, pipenv | -| Go | go modules | -| Rust | cargo | -| Ruby | bundler | - -## Usage - -### Magic Words - -- `audit deps` → Audit all project dependencies -- `dep-auditor` → Direct invocation - -## License - -MIT diff --git a/plugins/dep-auditor/evals/trigger-queries.json b/plugins/dep-auditor/evals/trigger-queries.json deleted file mode 100644 index b8397ab..0000000 --- a/plugins/dep-auditor/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "dep-auditor", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation. Near-misses hardened 2026-09-16 after a measured 3-sample blind-router baseline scored this set 20/20: a set at the ceiling cannot register a loss when its description is edited, so negatives no router would have reached were replaced with ones a sibling skill owns.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "are any of our packages known-vulnerable", - "should_trigger": true, - "split": "train" - }, - { - "query": "check whether anything in package-lock is out of date", - "should_trigger": true, - "split": "train" - }, - { - "query": "before we ship, is there a CVE anywhere in our deps", - "should_trigger": true, - "split": "train" - }, - { - "query": "npm audit flagged something but i want the picture across go and python too", - "should_trigger": true, - "split": "train" - }, - { - "query": "the lockfile changed in this PR, anything worrying in it", - "should_trigger": true, - "split": "train" - }, - { - "query": "which of our dependencies are behind their latest release", - "should_trigger": true, - "split": "train" - }, - { - "query": "we haven't touched dependencies in a year, how bad is it", - "should_trigger": true, - "split": "validation" - }, - { - "query": "third-party library security check please", - "should_trigger": true, - "split": "validation" - }, - { - "query": "audit the Gemfile before the release", - "should_trigger": true, - "split": "validation" - }, - { - "query": "is this repo safe from a supply-chain point of view", - "should_trigger": true, - "split": "validation" - }, - { - "query": "should we standardise on zod or yup for validation", - "should_trigger": false, - "split": "train" - }, - { - "query": "why does npm install fail with EACCES on my mac", - "should_trigger": false, - "split": "train" - }, - { - "query": "we're about to release -- is this service operationally ready", - "should_trigger": false, - "split": "train" - }, - { - "query": "our bundle is too big, which dependency should i drop", - "should_trigger": false, - "split": "train" - }, - { - "query": "scan our own source for vulnerabilities, not the packages", - "should_trigger": false, - "split": "train" - }, - { - "query": "review this query builder for SQL injection", - "should_trigger": false, - "split": "train" - }, - { - "query": "resolve this merge conflict in package-lock.json", - "should_trigger": false, - "split": "validation" - }, - { - "query": "list every package we depend on with its licence", - "should_trigger": false, - "split": "validation" - }, - { - "query": "publish this package to npm", - "should_trigger": false, - "split": "validation" - }, - { - "query": "upgrade react from 17 to 18 and fix the breakage", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/dep-auditor/skills/dep-auditor/SKILL.md b/plugins/dep-auditor/skills/dep-auditor/SKILL.md deleted file mode 100644 index 88cea68..0000000 --- a/plugins/dep-auditor/skills/dep-auditor/SKILL.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -name: dep-auditor -description: Audits dependencies for known vulnerabilities and outdated versions across npm, pip, go, cargo and bundler. Use before a release or when a lockfile changes. -license: MIT -model: haiku -context: fork -background: false -allowed-tools: - - Bash(npm audit:*) - - Bash(npm outdated:*) - - Bash(pip audit:*) - - Bash(pip list --outdated:*) - - Bash(go list:*) - - Bash(govulncheck:*) - - Bash(cargo audit:*) - - Bash(cargo outdated:*) - - Bash(bundle audit:*) - - Bash(gh api:*) - - Read - - Glob - - Grep -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "audit deps, dep-auditor" - verdict: "__AUDIT_RESULT__" ---- - -# Dependency Auditor - -Used by agent-page (SRE) and agent-ellis (QA). - -## Shortcut - -This skill is triggered when the user's prompt contains `audit deps` or `dep-auditor`. - -## How It Works - -Each phase assumes the one before it produced something to work on. When it did not, report -that and stop rather than reporting nothing found — the two are not the same, and only one of -them is good news. - -### Phase 1: Detect Package Manager - -Auto-detect by checking lock/config files. If multiple managers detected, audit all. If none -is detected, report that and stop — do not fall through to Phase 4. The table below is a -closed list, so a project outside it is the routine case, and an audit that ran no command -would otherwise emit `Status: CLEAN` and be read as a project with no vulnerable dependencies. - -| Config File | Package Manager | Audit Command | -| ------------------- | --------------- | ------------------- | -| `package-lock.json` | npm | `npm audit` | -| `yarn.lock` | yarn | `npm audit` | -| `requirements.txt` | pip | `pip audit` | -| `Pipfile.lock` | pipenv | `pip audit` | -| `go.sum` | go modules | `govulncheck ./...` | -| `Cargo.lock` | cargo | `cargo audit` | -| `Gemfile.lock` | bundler | `bundle audit` | - -### Phase 2: Vulnerability Scan - -Run audit command(s). For each vulnerability capture: package+version, ID (CVE/GHSA), -severity, description, fix version. - -### Phase 3: Outdated Package Check - -- npm: `npm outdated` -- pip: `pip list --outdated` -- go: `go list -u -m all` -- cargo: `cargo outdated` - -Flag packages more than 2 major versions behind. - -### Phase 4: Report - -Return a structured report: - -```txt -__AUDIT_RESULT__ -Status: CLEAN / WARN / CRITICAL -Vulnerabilities: - Critical: - High: - Medium: - Low: -Outdated: -__AUDIT_RESULT__ -``` - -If vulnerabilities found, include details for each. - -## Team Coordination - -**Available to:** agent-page, agent-ellis. Always emit the `__AUDIT_RESULT__` block when invoked; -caller decides how to act. diff --git a/plugins/lingua/.claude-plugin/plugin.json b/plugins/lingua/.claude-plugin/plugin.json deleted file mode 100644 index 96e2eba..0000000 --- a/plugins/lingua/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "lingua", - "description": "Answers in the user's chosen language whatever language they write in, restating the question in correct terminology first. Use to set or load that preference. Not a translation service: it does not translate a file, a document or a passage on request.", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/lingua/LICENSE b/plugins/lingua/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/lingua/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/lingua/README.md b/plugins/lingua/README.md deleted file mode 100644 index 6c99309..0000000 --- a/plugins/lingua/README.md +++ /dev/null @@ -1,100 +0,0 @@ -# Lingua Plugin - -> Answers in the user's chosen language whatever language they write in, restating the question in -> correct terminology first. Use to set or load that preference. Not a translation service: it -> does not translate a file, a document or a passage on request. - -The lingua plugin makes Claude Code reply in a language you choose, no matter what language -you type in. Optionally it also restates your question in clear, correct terminology before -answering. Preferences are remembered per project. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install lingua -``` - -## How It Works - -### Magic Words - -Registered via the skill's Shortcut section, so the shortcut plugin auto-dispatches them: - -| Magic word | Effect | -| ------------------- | --------------------------------------------- | -| `lingua` | Configure preferences, or show current status | -| `respond in ` | Set and persist the response language | -| `reply in ` | Same as above | - -### First Run - -The first time lingua runs in a project it asks three questions: - -1. **Response language** — e.g. `zh-TW`, `English`, `日本語`. -2. **Refine questions** — restate each question cleanly before answering? (per project). -3. **Technical terms** — keep code and technical terms in their original language? - -Your answers are saved and applied automatically on later sessions. - -### Persistence - -Rules live in the project's persistence memory — the same place `agent-smith` stores -`LESSONS.md`: - -```text -~/.claude/projects//memory/lingua.md -``` - -The file is per-user-per-project and is never committed. - -```yaml ---- -respond_in: zh-TW -discuss_in: auto -refine_question: false -keep_terms_in: en -glossary: [] ---- -``` - -### Automatic Loading - -A `SessionStart` hook loads your saved preference at the start of every session, so replies -come back in your language without typing anything. If no preference is configured, the hook -does nothing. - -Because hooks load when a session begins, a newly saved preference takes effect on the **next** -session. Restart Claude Code (or start a new session) to pick up changes. - -### Updating - -Just say it — "respond in Japanese now", "stop refining", "keep terms in Chinese too". -Lingua rewrites the config and applies the change immediately. - -Saying "lingua off" once lingua is active suspends the rules for the rest of the session -without deleting the config; a later "lingua" re-enables them. - -## Usage - -### Set a language - -```text -respond in zh-TW -``` - -### Show current rules - -```text -/lingua -``` - -### With agent-smith - -When `agent-smith` runs, it reads the same config and answers in your language, and passes -it down so the whole scrum team reports back in that language too. - -## License - -MIT diff --git a/plugins/lingua/evals/restate-before-answering/graders/briefing-silent.md b/plugins/lingua/evals/restate-before-answering/graders/briefing-silent.md deleted file mode 100644 index 49b2542..0000000 --- a/plugins/lingua/evals/restate-before-answering/graders/briefing-silent.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"briefing' -min: 0 -max: 0 ---- - -The baseline gave this query to briefing two runs in three. Briefing summarises a question -to keep an answer short -- nothing here is about length. diff --git a/plugins/lingua/evals/restate-before-answering/graders/fires.md b/plugins/lingua/evals/restate-before-answering/graders/fires.md deleted file mode 100644 index 8386484..0000000 --- a/plugins/lingua/evals/restate-before-answering/graders/fires.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"lingua' -min: 1 ---- - -Restating a cross-language question in the right terms before answering is what this -skill does, and the mixed-language framing is the whole reason it is being asked for. diff --git a/plugins/lingua/evals/restate-before-answering/prompt.md b/plugins/lingua/evals/restate-before-answering/prompt.md deleted file mode 100644 index b9b8e61..0000000 --- a/plugins/lingua/evals/restate-before-answering/prompt.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: restate-before-answering -tags: [trigger] -runs: 3 -max_turns: 8 -timeout_seconds: 300 ---- - -I mix English tech words into my Chinese and I get about half of them wrong -- last week -I said "reverse proxy" when what I actually meant was "load balancer", and you answered -the wrong question for ten minutes. Restate my question before you answer it. diff --git a/plugins/lingua/evals/stop-restating/graders/briefing-silent.md b/plugins/lingua/evals/stop-restating/graders/briefing-silent.md deleted file mode 100644 index 5f106e3..0000000 --- a/plugins/lingua/evals/stop-restating/graders/briefing-silent.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"briefing' -min: 0 -max: 0 ---- - -The baseline gave this query to briefing two runs in three, on the word "questions" -alone. diff --git a/plugins/lingua/evals/stop-restating/graders/fires.md b/plugins/lingua/evals/stop-restating/graders/fires.md deleted file mode 100644 index 626a598..0000000 --- a/plugins/lingua/evals/stop-restating/graders/fires.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"lingua' -min: 1 ---- - -Turning the restating behaviour off is still a change to this skill's setting, so it has -to load in order to honour it. diff --git a/plugins/lingua/evals/stop-restating/prompt.md b/plugins/lingua/evals/stop-restating/prompt.md deleted file mode 100644 index b1703ea..0000000 --- a/plugins/lingua/evals/stop-restating/prompt.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: stop-restating -tags: [trigger] -runs: 3 -max_turns: 8 -timeout_seconds: 300 ---- - -Every time I ask something you first rewrite it into whatever you think the proper term -is, then answer that version instead of mine. I would rather you just answered what I -actually wrote. Stop refining my questions. diff --git a/plugins/lingua/evals/translate-file-to-japanese/graders/does-not-fire.md b/plugins/lingua/evals/translate-file-to-japanese/graders/does-not-fire.md deleted file mode 100644 index 8cee579..0000000 --- a/plugins/lingua/evals/translate-file-to-japanese/graders/does-not-fire.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"lingua' -min: 0 -max: 0 ---- - -A labelled near-miss that the baseline fired on two runs in three. The target language -names a file's contents, not the language the answer should come back in. diff --git a/plugins/lingua/evals/translate-file-to-japanese/prompt.md b/plugins/lingua/evals/translate-file-to-japanese/prompt.md deleted file mode 100644 index 0b53a90..0000000 --- a/plugins/lingua/evals/translate-file-to-japanese/prompt.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: translate-file-to-japanese -tags: [trigger] -runs: 3 -max_turns: 8 -timeout_seconds: 300 ---- - -`docs/getting-started.md` has to ship with the JP release next month. Translate this file -to japanese and put the result at `docs/ja/getting-started.md`. Leave the fenced code -blocks and the heading anchors exactly as they are so the existing links still resolve. diff --git a/plugins/lingua/evals/translate-readme/graders/does-not-fire.md b/plugins/lingua/evals/translate-readme/graders/does-not-fire.md deleted file mode 100644 index 6f6a100..0000000 --- a/plugins/lingua/evals/translate-readme/graders/does-not-fire.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"lingua' -min: 0 -max: 0 ---- - -A labelled near-miss that the baseline fired on two runs in three. Producing a translated -file is an ordinary editing task; nothing here sets or reads a reply-language preference. diff --git a/plugins/lingua/evals/translate-readme/prompt.md b/plugins/lingua/evals/translate-readme/prompt.md deleted file mode 100644 index 682c50f..0000000 --- a/plugins/lingua/evals/translate-readme/prompt.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: translate-readme -tags: [trigger] -runs: 3 -max_turns: 8 -timeout_seconds: 300 ---- - -Our README is English-only and the Taipei team keeps asking for a version they can read. -Take `README.md` and translate the readme into traditional Chinese, then save it as -`README.zh-TW.md` beside the original. diff --git a/plugins/lingua/evals/trigger-queries.json b/plugins/lingua/evals/trigger-queries.json deleted file mode 100644 index 8ee8a97..0000000 --- a/plugins/lingua/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "lingua", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation. `stop refining my questions` (validation) was reviewed under the same criterion (issues #25, #24) and its positive label stands, though the case fires 0x. The criterion asks what complying requires, and here it requires a write: Phase 4 lists `stop refining` by name as a mid-session rule change that updates the config file with `Edit`, and the SessionStart hook reloads `refine_question` every session, so a stop that is not persisted does not stop anything past this one. `lingua off` is not the sharper phrasing to swap in -- it carries the magic word, so it fires whatever the description says, and the body has it suspend for the session without writing the file, making it the less persistent of the two. Relabelling would assert something the body contradicts, and replacing the query would delete the evidence, which is the asymmetry against `restate my question before you answer it` at 3/3: same skill, same vocabulary, opposite results. So this is recorded as a body-versus-description mismatch -- the description names the on-state and never the off-state -- and the failing case is left standing as the observation that would justify fixing it.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "reply in japanese from now on", - "should_trigger": true, - "split": "train" - }, - { - "query": "respond in zh-tw even when i write english", - "should_trigger": true, - "split": "train" - }, - { - "query": "lingua", - "should_trigger": true, - "split": "train" - }, - { - "query": "answer me in traditional chinese please", - "should_trigger": true, - "split": "train" - }, - { - "query": "switch your replies to korean", - "should_trigger": true, - "split": "train" - }, - { - "query": "restate my question before you answer it", - "should_trigger": true, - "split": "train" - }, - { - "query": "always answer in english, i'll write in chinese", - "should_trigger": true, - "split": "validation" - }, - { - "query": "what response language is set for this project", - "should_trigger": true, - "split": "validation" - }, - { - "query": "stop refining my questions", - "should_trigger": true, - "split": "validation" - }, - { - "query": "lingua off", - "should_trigger": true, - "split": "validation" - }, - { - "query": "translate this file to japanese", - "should_trigger": false, - "split": "train" - }, - { - "query": "what language is this code comment in", - "should_trigger": false, - "split": "train" - }, - { - "query": "write the docs in chinese", - "should_trigger": false, - "split": "train" - }, - { - "query": "is this the right term in english", - "should_trigger": false, - "split": "train" - }, - { - "query": "add i18n support to this application", - "should_trigger": false, - "split": "train" - }, - { - "query": "translate the readme", - "should_trigger": false, - "split": "train" - }, - { - "query": "explain this in simpler english", - "should_trigger": false, - "split": "validation" - }, - { - "query": "what does this japanese error message mean", - "should_trigger": false, - "split": "validation" - }, - { - "query": "add locale support to the app", - "should_trigger": false, - "split": "validation" - }, - { - "query": "which languages does this library support", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/lingua/skills/lingua/SKILL.md b/plugins/lingua/skills/lingua/SKILL.md deleted file mode 100644 index d239fa5..0000000 --- a/plugins/lingua/skills/lingua/SKILL.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -name: lingua -description: Answers in the user's chosen language whatever language they write in, restating the question in correct terminology first. Use to set or load that preference. Not a translation service: it does not translate a file, a document or a passage on request. -license: MIT -model: haiku -allowed-tools: - - Read - - Write - - Edit - - Glob -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "lingua, respond in, reply in" ---- - -# Lingua — Response Language - -Answer the user in their chosen language, regardless of the language they write in, and -optionally restate their question in clear, correct terminology first. Preferences are -remembered per project. - -## Shortcut - -This skill is triggered when the user's prompt contains `lingua`, `respond in`, or -`reply in`. - -## Config File - -Per-project rules live in the project's persistence memory: - -```text -~/.claude/projects//memory/lingua.md -``` - -`` is the current working directory with `/` replaced by `-` (the same -convention used for `LESSONS.md`). The file is per-user-per-project and is never committed. - -Schema — YAML frontmatter plus freeform notes: - -```yaml ---- -respond_in: zh-TW # response language (BCP-47 tag or plain name); required -discuss_in: auto # language the user writes in; auto = detect each turn -refine_question: false # restate the user's question cleanly before answering -keep_terms_in: en # keep technical terms / code identifiers in this language -glossary: [] # optional normalizations, e.g. "K8s → Kubernetes" ---- -Freeform per-project language notes. -``` - -## How It Works - -Phase 1's rule against guessing a language generalises to every phase here. Each assumes an -input — a config file, an answer from the user, a rule to apply — and when one is missing, say -what is missing and ask rather than filling it in. A preference Lingua inferred is -indistinguishable from one the user chose, and it reaches the config file either way. - -### Phase 1: Load - -Read the config file for the current project. - -- **Exists** → adopt its rules for the rest of the session; go to Phase 3. -- **Missing** → go to Phase 2 (onboard). - -Never invent a language. If no rule exists, ask — do not guess from the user's input language. - -### Phase 2: Onboard (first run in a project) - -Before continuing the conversation, ask the user with `AskUserQuestion`: - -1. **Response language** — which language should replies be written in? (e.g. `zh-TW`, - `English`, `日本語`). Offer a few common choices plus their input language. -2. **Refine questions** — should each question be restated cleanly with correct terminology - before answering? (on / off). There is no global default; this choice is made per project. -3. **Technical terms** — keep code identifiers and technical terms in their original - language (recommended), or translate them too? - -Write the answers to the config file via `Write`, creating the `memory/` path if needed. -Confirm what was saved in one line, then proceed in the chosen language. - -### Phase 3: Apply - -For the rest of the session: - -- **Respond in `respond_in`.** Translate your entire reply into that language, whatever - language the user writes in. -- **Keep terms in `keep_terms_in`.** Code, identifiers, commands, filenames, and technical - terms stay verbatim — do not translate or transliterate them. Apply `glossary` - normalizations when a listed term appears. -- **If `refine_question: true`**, open the reply with a one-line restatement of what the - user is asking, cleaned up and using correct terminology, so both sides confirm intent. - Keep it short; then answer. Skip the restatement for trivial or already-precise prompts. - -### Phase 4: Re-memory (update on request) - -When the user asks to change any rule mid-session — "respond in Japanese now", "stop -refining", "keep terms in Chinese too" — update the config file with `Edit` (or `Write` if -it must be recreated), confirm the change in one line, and apply it immediately. This also -covers `lingua off`: suspend applying rules for the rest of the session without deleting the -file (a later `lingua` re-enables it). - -### Phase 5: Status (direct invocation) - -When called directly as `lingua` with no change requested, print the active rules and where -they come from: - -| Setting | Value | Source | -| ---------------- | -------- | ---------------- | -| Respond in | … | memory/lingua.md | -| Discuss in | … | … | -| Refine questions | on / off | … | -| Keep terms in | … | … | - -If no config exists, say so and offer to onboard. - -## Automatic Loading (SessionStart hook) - -Once a preference is saved, it applies automatically at the start of every session — no magic -word needed. The plugin's `SessionStart` hook (`hooks/lingua-session-start.py`) reads -`memory/lingua.md` for the current project and injects its rules as session context. When no -preference is configured, the hook is a silent no-op. - -Because hooks load when a session starts, a newly saved preference takes effect on the **next** -session; within the current session, Phases 3–4 already apply it live. - -## Notes - -- Lingua governs **output language only**. It never changes what the user asked for, only how - the answer is phrased. -- Other skills and agents inherit the preference when they read the same config file — see the - Smith integration in `agent-smith`. diff --git a/plugins/pr-flow/.claude-plugin/plugin.json b/plugins/pr-flow/.claude-plugin/plugin.json deleted file mode 100644 index 1aebf77..0000000 --- a/plugins/pr-flow/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "pr-flow", - "description": "Walks a pull request from its issue to merge-ready — checks the diff against the issue body, then works each reviewer comment test-first. Merging stays with the user.", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/pr-flow/LICENSE b/plugins/pr-flow/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/pr-flow/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/pr-flow/README.md b/plugins/pr-flow/README.md deleted file mode 100644 index f56ad78..0000000 --- a/plugins/pr-flow/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# PR Flow Plugin - -> Walks a pull request from its issue to merge-ready — checks the diff against the issue body, then -> works each reviewer comment test-first. Merging stays with the user. - -A utility skill for the pull-request lifecycle. It gates a PR on the issue it serves, aligns -the diff with what that issue asked for, and works reviewer comments one at a time — -test-first when behaviour changes, and kept within issue scope. Merging stays with you. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install pr-flow -``` - -## How It Works - -1. **Issue gate** — find and verify the originating issue; none found → propose one and - create it only after an explicit yes, or record `Issue: —` if you decline -2. **Alignment** — compare the diff with the issue body and settle two lists with you, - missing parts and over-engineered parts, before the PR is opened or edited -3. **Reviewer loop** — take each reviewer item in turn: re-check issue scope, write the test - before the fix when behaviour changes, and challenge out-of-scope items with you first, - then the reviewer - -Every write to GitHub — creating an issue, opening or editing the PR, posting a reviewer -comment — is a checkpoint that waits for your approval. The skill never merges. - -## Usage - -### Magic Words - -- `open pr` → Walk the current branch through the issue gate and alignment, then open the PR -- `resolve pr` → Work the open reviewer comments on the PR, one item at a time -- `pr-flow` → Run the full flow from issue gate to merge-ready - -Note that the words open pr also occur in ordinary prose — a sentence about the open PR -list, for instance — so a stray trigger is possible; the skill reports the issue line first, -which makes an unintended start easy to spot and stop. - -## When To Use Which - -Use `pr-flow` when the work ships as a GitHub pull request with reviewers to answer. Use -`agent-smith` when the work is planned and merged locally without a PR — the two do not -overlap, and `pr-flow` hands back to you when a task turns out to need a plan rather than a PR. - -When `tenth-man`, `agent-hale` and `agent-ellis` are installed, `pr-flow` invokes them for -the over-engineering check, test-first fixes and fix verification. When they are not, it -does the same steps itself. - -## Requirements - -GitHub only. The `gh` CLI must be installed and authenticated (`gh auth status`) for the -repository the PR belongs to. - -## License - -MIT diff --git a/plugins/pr-flow/evals/open-pr-for-branch/graders/fires.md b/plugins/pr-flow/evals/open-pr-for-branch/graders/fires.md deleted file mode 100644 index c4024d6..0000000 --- a/plugins/pr-flow/evals/open-pr-for-branch/graders/fires.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"pr-flow' -min: 1 ---- - -A pushed branch with an issue behind it is the start of this skill's walk from issue to -merge-ready. The baseline fired nothing on two runs in three, so there is no second skill -to rule out. diff --git a/plugins/pr-flow/evals/open-pr-for-branch/prompt.md b/plugins/pr-flow/evals/open-pr-for-branch/prompt.md deleted file mode 100644 index 815827e..0000000 --- a/plugins/pr-flow/evals/open-pr-for-branch/prompt.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: open-pr-for-branch -tags: [trigger] -runs: 3 -max_turns: 8 -timeout_seconds: 300 ---- - -I have pushed `feat/webhook-retry`. It is the work for issue #204 -- six commits across -the retry backoff and its tests -- and it is ready for someone to look at. Open a pull -request for this branch. diff --git a/plugins/pr-flow/evals/trigger-queries.json b/plugins/pr-flow/evals/trigger-queries.json deleted file mode 100644 index c273e4a..0000000 --- a/plugins/pr-flow/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "pr-flow", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "open a pull request for this branch", - "should_trigger": true, - "split": "train" - }, - { - "query": "the reviewer left comments on my PR, work through them", - "should_trigger": true, - "split": "train" - }, - { - "query": "does this PR actually cover everything issue #42 asked for?", - "should_trigger": true, - "split": "train" - }, - { - "query": "apply the changes requested in the review on PR 17", - "should_trigger": true, - "split": "train" - }, - { - "query": "create a PR against main and link it to the issue", - "should_trigger": true, - "split": "train" - }, - { - "query": "address the review feedback and reply to the reviewer", - "should_trigger": true, - "split": "train" - }, - { - "query": "get this branch ready for review as a PR", - "should_trigger": true, - "split": "validation" - }, - { - "query": "resolve the outstanding review threads on my pull request", - "should_trigger": true, - "split": "validation" - }, - { - "query": "check whether the PR diff has drifted from what the issue describes", - "should_trigger": true, - "split": "validation" - }, - { - "query": "the reviewer wants a refactor, is that in scope for this PR?", - "should_trigger": true, - "split": "validation" - }, - { - "query": "commit this", - "should_trigger": false, - "split": "train" - }, - { - "query": "cut a release and tag it", - "should_trigger": false, - "split": "train" - }, - { - "query": "review this code for bugs", - "should_trigger": false, - "split": "train" - }, - { - "query": "list the open issues in this repo", - "should_trigger": false, - "split": "train" - }, - { - "query": "review this PR for bugs", - "should_trigger": false, - "split": "train" - }, - { - "query": "explain what a pull request is", - "should_trigger": false, - "split": "train" - }, - { - "query": "resolve this merge conflict in main.go", - "should_trigger": false, - "split": "validation" - }, - { - "query": "write a spec for the new API", - "should_trigger": false, - "split": "validation" - }, - { - "query": "push my branch to origin", - "should_trigger": false, - "split": "validation" - }, - { - "query": "what does git rebase do?", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/pr-flow/skills/pr-flow/SKILL.md b/plugins/pr-flow/skills/pr-flow/SKILL.md deleted file mode 100644 index 3dbc1b0..0000000 --- a/plugins/pr-flow/skills/pr-flow/SKILL.md +++ /dev/null @@ -1,173 +0,0 @@ ---- -name: pr-flow -description: Walks a pull request from its issue to merge-ready — checks the diff against the issue body, then works each reviewer comment test-first. Merging stays with the user. -license: MIT -allowed-tools: - - Read - - Glob - - Grep - - Bash(git status:*) - - Bash(git diff:*) - - Bash(git log:*) - - Bash(git branch:*) - - Bash(gh issue view:*) - - Bash(gh pr view:*) - - Bash(gh pr diff:*) - - Bash(gh pr checks:*) - - Bash(gh pr list:*) -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "open pr, resolve pr, pr-flow" ---- - -# PR Flow Skill - -Gates a pull request on the issue it serves. Three phases: find and verify the originating -issue (or get permission to create one), align the diff with the issue body before the PR is -opened or updated, then work each reviewer comment in turn — test first when behaviour -changes, challenged when it leaves issue scope. GitHub only, through `gh`. Every write to the -forge is a checkpoint: the pre-authorised tools above are read-only, so `gh issue create`, -`gh pr create`, `gh pr edit` and `gh pr comment` each pass through the permission prompt, and -the skill never runs `gh pr merge`. - -## Shortcut - -This skill is triggered when the user's prompt contains `open pr`, `resolve pr`, or `pr-flow`. - -Each phase below assumes an input: a verified ref, a diff, a list of reviewer items. When one -is missing, say which and stop — with the single exception Phase 1 already names, where a -declined issue becomes `Issue: —` and the run continues. That exception is the shape to copy: -a gap the user has seen and ruled on can be carried forward, a gap nobody has seen cannot. - -## Phase 1: Issue Gate - -Establish which issue this PR serves before reading a line of the diff. - -1. Look for a ref, in this order, and stop at the first hit: - - the user's prompt (`#123`, an issue URL) - - the branch name — `git branch --show-current` — treated as a **hint**, never as a ref - - an existing PR — `gh pr view --json number,title,body,closingIssuesReferences`; take - `closingIssuesReferences` first and parse the body only when it is empty -2. Verify every candidate with `gh issue view --json number,title,body,state,url`. A - number that does not resolve, or resolves to an issue about something else, is not a ref. - A branch called `fix-123` proves nothing until `gh issue view 123` describes this work. -3. No verified ref → **checkpoint**. Draft a title and body from the diff - (`git diff ...HEAD --stat`, `git log ..HEAD --oneline`, where `` is - the base branch — `main` unless the repo says otherwise), show both, and ask whether to - create the issue. Run `gh issue create` only after an explicit yes. -4. The user declines → the ref is `—`. Say so in one line, write "Issue: —" in the PR body - later, and continue. A missing issue is a fact to record, not a reason to stall. -5. Never invent a ref. No plausible number from a branch name, a commit message, or the diff - is ever written as `#n` — the rules `agent-ross:agent-ross` follows for commit footers - apply to the PR body too. - -Report the outcome as one line: `Issue: #123 — ` or `Issue: —`. - -## Phase 2: Alignment - -Compare what the branch does with what the issue asked for. Skip when the ref is `—` and -the user has nothing else to compare against; say so and go straight to opening the PR. - -1. Read the diff and the issue body from Phase 1. Before a PR exists: `git diff <base>...HEAD` - with `<base>` the base branch (`main` unless the repo says otherwise). After one exists: - `gh pr diff <n>`, and take the base from `gh pr view <n> --json baseRefName` rather than - assuming it. -2. Build two lists: - - **Missing** — things the issue asks for that the diff does not deliver - - **Over-engineered** — things the diff delivers that the issue does not ask for: extra - options, abstractions with one caller, speculative generality, unrelated cleanups -3. When `tenth-man:tenth-man` is installed, invoke it on the diff-versus-issue comparison - and fold its findings into the second list. Not installed → apply the same test directly: - for each addition, name the sentence in the issue that requires it, or list it. -4. Present both lists to the user one item at a time and settle each: keep, cut, defer to a - new issue, or amend the issue. Both lists must be settled — empty counts — before the - next step. -5. **Checkpoint.** Draft the PR title and body — what changed, why, `Closes #123` or - `Issue: —` — show the draft, and only after approval run `gh pr create` (no PR yet) or - `gh pr edit <n>` (PR exists). Reflect any cuts from step 4 in the code before opening. - -## Phase 3: Reviewer Loop - -Work reviewer feedback item by item, never as one batch. - -1. Collect the open items from three sources, then list them numbered and take them in order: - - top-level reviews and conversation comments — `gh pr view <n> --json reviews,comments` - - inline review threads (the line-anchored requested changes, which `gh pr view` does - not return) — `gh api repos/{owner}/{repo}/pulls/<n>/comments`, a GET. `gh api` is - deliberately **not** pre-authorised, so this read passes through the permission prompt - exactly as the writes do; the skill never runs `gh api` with `-X`/`--method` or - `-f`/`-F` fields — reads only - - failing checks — `gh pr checks <n>`, each failure an item of its own -2. For each item, before anything else, **re-check issue scope** against the issue body from - Phase 1. This check runs per item, not once per round — a review that is in scope on its - first three comments can leave it on the fourth. Classify the item: - - **In scope** — the issue asks for it or it corrects a defect in delivering it - - **Out of scope** — it asks for work the issue does not cover - - **Added abstraction** — it asks for a layer, option or generalisation the issue does not - need to be delivered -3. In-scope item → comply. Decide whether it **changes behaviour**: - - Changes behaviour (a different output, a new code path, a fixed defect): test first. - When `agent-hale:agent-hale` is installed, dispatch with the explicit instruction - "write the failing test before the fix, then make it pass". Not installed → do the same - directly: failing test, minimal fix, green, no regressions. - - Does not change behaviour (rename, comment, formatting, docs): make the change and state - in one line why there is no test — "rename only, covered by the existing suite" — rather - than leaving the absence unexplained. - - When `agent-ellis:agent-ellis` is installed, have it verify the fix against the item's - wording before replying. Not installed → run the affected tests and quote the result. -4. Out-of-scope or added-abstraction item → challenge, in this order: - - **User first.** Show the item, the sentence in the issue it exceeds (or the absence of - one), and the options: decline with a reason, do it here anyway, or split it to a new - issue. Settle it with the user before any word goes to the reviewer. - - **Reviewer second — checkpoint.** Draft the reply: what the issue covers, why this item - falls outside it, and what is proposed instead. Show the draft. Post it with - `gh pr comment <n> --body` only after the user approves the exact text; edit and - re-show on request. - - Comply when the challenge does not hold. A reviewer asking for a test, a name that - matches the codebase, or an edge case the issue implies is in scope, not a challenge. -5. Every reply to a reviewer — agreement, question, or pushback — is drafted, shown, and - posted only after approval. The skill never speaks to a reviewer on its own. -6. After the last item, summarise: items complied with, items declined (with the reply - posted), tests added, and the `gh pr checks <n>` state. Stop there — merge is the user's. - -## Checkpoints - -Every point where the skill stops and waits for the user. None may be skipped or assumed. - -| # | Where | What waits for the user | -| --- | -------------- | ------------------------------------------------------------------------------------- | -| 1 | Phase 1 step 3 | Creating an issue — `gh issue create` runs only after an explicit yes | -| 2 | Phase 2 step 4 | Settling each missing or over-engineered item | -| 3 | Phase 2 step 5 | Opening or editing the PR — `gh pr create` / `gh pr edit` after the draft is approved | -| 4 | Phase 3 step 4 | Declining or narrowing a reviewer item — the user decides before the reviewer hears | -| 5 | Phase 3 step 5 | Posting any reviewer reply — `gh pr comment` only with the approved text | -| 6 | After Phase 3 | Merging — the skill never runs `gh pr merge`; the user does | - -The `allowed-tools` list enforces the mechanical half of this table: nothing that writes to -GitHub is pre-authorised, so each of those commands also passes through the permission prompt. -`gh api` is left out on the same principle even for its one read (Phase 3 step 1) — it is the -one command that could write, so it is never pre-authorised and is used as a GET only. - -## Team Coordination - -The skill invokes these when installed and does the same work itself when they are not. - -- `tenth-man:tenth-man` — Phase 2, the over-engineered list. Not installed: apply the same - test directly; each addition must trace to a sentence in the issue. -- `agent-hale:agent-hale` — Phase 3, behaviour-changing fixes, dispatched with the explicit - test-first instruction. Not installed: write the failing test, then the minimal fix, directly. -- `agent-ellis:agent-ellis` — Phase 3, verifying a fix against the reviewer's wording. Not - installed: run the affected tests and quote the result. - -The same rules apply either way: test before fix when behaviour changes, a stated reason when -it does not, and a challenge only when an item exceeds scope or adds unneeded abstraction. -The skill does not invoke `agent-smith:agent-smith`; when the work turns out to need a plan -rather than a PR, say so and hand back to the user. - -## Output Style - -Everything addressed to the user follows `briefing:briefing`: the result first — the issue -line, the two alignment lists, the numbered reviewer items — then one numbered topic at a -time, with detail only where asked. Reviewer replies are drafted in full, since they leave the -conversation, but are still shown before they are posted. diff --git a/plugins/sec-review/.claude-plugin/plugin.json b/plugins/sec-review/.claude-plugin/plugin.json deleted file mode 100644 index 8873965..0000000 --- a/plugins/sec-review/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "sec-review", - "description": "Reviews source for security issues and maps each finding to a CWE — whole project by default, or the scope its caller states. Use when security is the question, not code review.", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/sec-review/LICENSE b/plugins/sec-review/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/sec-review/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/sec-review/README.md b/plugins/sec-review/README.md deleted file mode 100644 index 0a32940..0000000 --- a/plugins/sec-review/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# Security Reviewer Plugin - -> Reviews source for security issues and maps each finding to a CWE — whole project by default, or -> the scope its caller states. Use when security is the question, not code review. - -A shared support tool that reads the **whole project** source and surfaces potential -security issues, mapping each to a related CWE ID. Unlike the built-in diff-only -`/security-review` (which only inspects the current branch diff), this reviewer scans -the entire codebase and attaches CWE classifications to every finding. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install sec-review -``` - -## How It Works - -1. **Scope** — Enumerates source with `git ls-files`, skipping vendored and generated code, - then identifies the languages and entry points in use -2. **Review** — Reads and greps for common weakness classes, mapping each to its CWE -3. **Triage** — Rates findings by severity and discards what the codebase makes unreachable -4. **Report** — Lists each finding with its location, CWE ID, and a concrete fix - -Covered weakness classes include injection (SQL, command, template), XSS, hardcoded -secrets, broken authentication and access control, insecure deserialization, path -traversal, SSRF, weak cryptography, and missing input validation. - -Read-only: it reports, and never edits the project. - -## Usage - -### Magic Words - -- `sec-review` → Direct invocation -- `security review` → Whole-project security review - -## License - -MIT diff --git a/plugins/sec-review/evals/trigger-queries.json b/plugins/sec-review/evals/trigger-queries.json deleted file mode 100644 index 8720db5..0000000 --- a/plugins/sec-review/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "sec-review", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation. Near-misses hardened 2026-09-16 after a measured 3-sample blind-router baseline scored this set 20/20: a set at the ceiling cannot register a loss when its description is edited, so negatives no router would have reached were replaced with ones a sibling skill owns. One hardened negative was withdrawn after that run: `does this PR introduce anything unsafe` fired 3/3 and the label, not the router, was wrong -- the description licenses a caller-stated scope, and a PR is one. Its slot now tests the `not code review` clause instead, on the quality-plus-security shape agent-ellis measurably wins.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "is there anything insecure anywhere in this codebase", - "should_trigger": true, - "split": "train" - }, - { - "query": "do a security pass over the whole repo, not just my branch", - "should_trigger": true, - "split": "train" - }, - { - "query": "we're filling in a vendor security questionnaire, find our weak spots", - "should_trigger": true, - "split": "train" - }, - { - "query": "any injection or broken-auth bugs in here", - "should_trigger": true, - "split": "train" - }, - { - "query": "map whatever security issues you find to CWE ids", - "should_trigger": true, - "split": "train" - }, - { - "query": "i inherited this codebase, how bad is the security", - "should_trigger": true, - "split": "train" - }, - { - "query": "find hardcoded secrets and unsafe deserialisation", - "should_trigger": true, - "split": "validation" - }, - { - "query": "which parts of this app would a pentester go for first", - "should_trigger": true, - "split": "validation" - }, - { - "query": "full security review of ~/work/payments please", - "should_trigger": true, - "split": "validation" - }, - { - "query": "audit the source for vulnerabilities before the compliance deadline", - "should_trigger": true, - "split": "validation" - }, - { - "query": "check our dependencies for known CVEs", - "should_trigger": false, - "split": "train" - }, - { - "query": "review the changes on my branch", - "should_trigger": false, - "split": "train" - }, - { - "query": "how should i hash passwords in this app", - "should_trigger": false, - "split": "train" - }, - { - "query": "check our security posture before we go live", - "should_trigger": false, - "split": "train" - }, - { - "query": "review this branch for quality as well as security", - "should_trigger": false, - "split": "train" - }, - { - "query": "rotate this leaked API key", - "should_trigger": false, - "split": "train" - }, - { - "query": "is jose a good JWT library", - "should_trigger": false, - "split": "validation" - }, - { - "query": "write a threat model document for the payments service", - "should_trigger": false, - "split": "validation" - }, - { - "query": "challenge the assumption that our auth model is sound", - "should_trigger": false, - "split": "validation" - }, - { - "query": "our pen test report says X is broken, go fix it", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/sec-review/skills/sec-review/SKILL.md b/plugins/sec-review/skills/sec-review/SKILL.md deleted file mode 100644 index 881f85d..0000000 --- a/plugins/sec-review/skills/sec-review/SKILL.md +++ /dev/null @@ -1,107 +0,0 @@ ---- -name: sec-review -description: Reviews source for security issues and maps each finding to a CWE — whole project by default, or the scope its caller states. Use when security is the question, not code review. -license: MIT -allowed-tools: - - Bash(git ls-files:*) - - Bash(grep:*) - - Read - - Glob - - Grep -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "sec-review, security review" - verdict: "__SEC_REVIEW_RESULT__" ---- - -# Security Reviewer - -Reviews the **whole project** source for potential security issues and maps each to a -related CWE — unlike diff-only reviewers (e.g. the built-in `/security-review`) that -only inspect the current branch diff. - -## Shortcut - -This skill is triggered when the user's prompt contains `sec-review` or `security review`. - -## How It Works - -Each phase below assumes an input: a scope to enumerate, files to read. When one is missing — -the caller named a scope that resolves to nothing, or enumeration returns no source at all — -report that and stop. `Status: CLEAN` is a claim about source that was examined, so source -that was never enumerated earns no status, least of all the reassuring one. - -### Phase 1: Scope - -Enumerate source files with `git ls-files` (fall back to Glob). Skip vendored/generated -code, `node_modules`, build output, and lockfiles. Identify the languages in use and the -entry points (CLI mains, HTTP handlers, request routers, message consumers). - -### Phase 2: Review for Weakness Classes - -Grep/read source for common weakness classes. Map each to its example CWE: - -| Issue Class | Example CWE | -| ---------------------------------- | ----------------- | -| Injection — SQLi | CWE-89 | -| Injection — command | CWE-77 / CWE-78 | -| Injection — template | CWE-94 | -| Cross-site scripting (XSS) | CWE-79 | -| Hardcoded secrets | CWE-798 | -| Broken / missing authentication | CWE-287 | -| Broken access control | CWE-862 / CWE-285 | -| Insecure deserialization | CWE-502 | -| Path traversal | CWE-22 | -| Server-side request forgery (SSRF) | CWE-918 | -| Weak cryptography | CWE-327 | -| Sensitive data exposure | CWE-200 | -| Missing input validation | CWE-20 | -| Insecure randomness | CWE-330 | -| XML external entity (XXE) | CWE-611 | -| Open redirect | CWE-601 | - -### Phase 3: Triage - -For each finding assign a severity (Critical / High / Medium / Low) and the most -specific CWE ID that applies. - -### Phase 4: Report - -**Inline by default.** Present a findings table: - -| File:Line | Issue | Severity | CWE | Suggested Fix | -| --------- | ----- | -------- | --- | ------------- | - -Write a report file (e.g. `SECURITY-REVIEW.md`) **only** when the user explicitly asks. -Default is inline — write nothing. - -When called by another agent, also emit a structured block: - -```txt -__SEC_REVIEW_RESULT__ -Status: CLEAN / WARN / CRITICAL -Findings: <n> - Critical: <n> - High: <n> - Medium: <n> - Low: <n> -__SEC_REVIEW_RESULT__ -``` - -## Constraints - -- **Read-only**: MUST NOT modify project files. Only review and report. -- **Scope comes from the caller**: whole project is the default, not the mandate. `agent-ellis` - invokes this diff-scoped as part of a unit review; `agent-ross` invokes it at full scope once - per release. Scan what the caller asked for, and state which scope was used. -- Be specific: file path, line number, and a concrete fix for each finding. -- Findings are **potential** issues to verify, not proof of exploitability. -- Prefer the most specific CWE that fits the weakness. - -## Team Coordination - -**Available to:** `agent-ellis` (diff scope, per unit) and `agent-ross` (whole project, once -per release). `agent-page` does not invoke this scan — it reads Ellis's findings, because two -agents scanning the same source produce the same findings at twice the cost. Always emit the -`__SEC_REVIEW_RESULT__` block when called by another agent; the caller decides how to act. diff --git a/plugins/shortcut/.claude-plugin/plugin.json b/plugins/shortcut/.claude-plugin/plugin.json deleted file mode 100644 index 81380f6..0000000 --- a/plugins/shortcut/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "shortcut", - "description": "Dispatches the skill or command whose declared magic word appears in the prompt. Use at the start of a turn to check for a registered trigger phrase, or to list the magic words available across personal, project and plugin skills.", - "version": "2.0.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/shortcut/LICENSE b/plugins/shortcut/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/shortcut/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/shortcut/README.md b/plugins/shortcut/README.md deleted file mode 100644 index 6b78b79..0000000 --- a/plugins/shortcut/README.md +++ /dev/null @@ -1,77 +0,0 @@ -# Shortcut Plugin - -> Dispatches the skill or command whose declared magic word appears in the prompt. Use at the start -> of a turn to check for a registered trigger phrase, or to list the magic words available across -> personal, project and plugin skills. - -The shortcut plugin enables magic-word dispatch for Claude Code. When a user's prompt contains -a recognized keyword, the agent automatically invokes the corresponding skill or command. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install shortcut -``` - -## How It Works - -### Magic Word Registration - -Any skill or command file can register a shortcut by declaring the words in its YAML -frontmatter, as a comma-separated string: - -```yaml -metadata: - shortcut: "review code, qa review" -``` - -A `## Shortcut` section in the body then spells the same words out for human readers. It is -documentation: once frontmatter declares the words, a backtick in that section is ordinary -prose and can name a file, a tool or another skill freely. - -Files with no `metadata.shortcut` fall back to the older contract — backtick-quoted words on -a line reading "triggered when the user's prompt contains ..." inside the `## Shortcut` -section — so a skill written before this change keeps working. - -### Three-Tier Scanning - -The plugin scans three directory levels in priority order: - -| Priority | Source | Paths | -| -------- | -------------- | ------------------------------------------ | -| 1 | User-level | `~/.claude/skills/`, `~/.claude/commands/` | -| 2 | Project-level | `.claude/skills/`, `.claude/commands/` | -| 3 | Plugin-bundled | `plugins/*/skills/`, `plugins/*/commands/` | - -Higher-priority sources win when the same magic word is defined in multiple places. - -### Auto-Dispatch - -When the user types a prompt containing a magic word, the shortcut skill automatically -invokes the matched skill and informs the user what was triggered. - -## Usage - -### List All Shortcuts - -```text -/shortcut -``` - -Displays a table of all registered magic words, their skills, sources, and descriptions. - -### Auto-Trigger Example - -If a skill registers the magic word `review`, simply typing: - -```text -Please review this code -``` - -The agent detects `review` and dispatches the code-review skill automatically. - -## License - -MIT diff --git a/plugins/shortcut/evals/trigger-queries.json b/plugins/shortcut/evals/trigger-queries.json deleted file mode 100644 index b94a252..0000000 --- a/plugins/shortcut/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "shortcut", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation. Near-misses hardened 2026-09-16 after a measured 3-sample blind-router baseline scored this set 20/20: a set at the ceiling cannot register a loss when its description is edited, so negatives no router would have reached were replaced with ones a sibling skill owns.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "what shortcuts do i have", - "should_trigger": true, - "split": "train" - }, - { - "query": "list every magic word available", - "should_trigger": true, - "split": "train" - }, - { - "query": "check my prompt for a registered trigger before you start", - "should_trigger": true, - "split": "train" - }, - { - "query": "which skills trigger on what phrases", - "should_trigger": true, - "split": "train" - }, - { - "query": "did i just type a registered trigger word", - "should_trigger": true, - "split": "train" - }, - { - "query": "show me the magic words across my plugins", - "should_trigger": true, - "split": "train" - }, - { - "query": "point me at whichever skill owns the phrase i just used", - "should_trigger": true, - "split": "validation" - }, - { - "query": "is there a shortcut for this", - "should_trigger": true, - "split": "validation" - }, - { - "query": "which command does this phrase run", - "should_trigger": true, - "split": "validation" - }, - { - "query": "list the trigger phrases from all my plugins", - "should_trigger": true, - "split": "validation" - }, - { - "query": "what skills do i have installed", - "should_trigger": false, - "split": "train" - }, - { - "query": "document the magic words in this plugin's readme", - "should_trigger": false, - "split": "train" - }, - { - "query": "add a keyboard shortcut for submit", - "should_trigger": false, - "split": "train" - }, - { - "query": "register 'ship it' as a new trigger phrase for my deploy skill", - "should_trigger": false, - "split": "train" - }, - { - "query": "install this plugin", - "should_trigger": false, - "split": "train" - }, - { - "query": "rebind ctrl+s", - "should_trigger": false, - "split": "train" - }, - { - "query": "add a magic word to this skill's frontmatter", - "should_trigger": false, - "split": "validation" - }, - { - "query": "remove this plugin from the marketplace", - "should_trigger": false, - "split": "validation" - }, - { - "query": "what does this skill's description say", - "should_trigger": false, - "split": "validation" - }, - { - "query": "two of my skills claim the same trigger word, fix it", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/shortcut/skills/shortcut/SKILL.md b/plugins/shortcut/skills/shortcut/SKILL.md deleted file mode 100644 index 5cd0dcf..0000000 --- a/plugins/shortcut/skills/shortcut/SKILL.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -name: shortcut -description: Dispatches the skill or command whose declared magic word appears in the prompt. Use at the start of a turn to check for a registered trigger phrase, or to list the magic words available across personal, project and plugin skills. -license: MIT -model: haiku -allowed-tools: - - Read - - Glob - - Grep -metadata: - author: cmj@cmj.tw - version: "2.0.0" ---- - -# Shortcut Skill - -Recognize magic words in user prompts and dispatch the matching skill or command. - -## Scanning Sources - -Scan these directories for `.md` files, in priority order (highest first): - -| Priority | Source | Path | -| -------- | -------------- | ------------------- | -| 1 | User-level | `~/.claude/skills/` | -| 2 | Project-level | `.claude/skills/` | -| 3 | Plugin-bundled | `plugins/*/skills/` | - -Also scan command directories: - -- `~/.claude/commands/` -- `.claude/commands/` -- `plugins/*/commands/` - -## Magic Word Extraction - -Read the file's YAML frontmatter and take `metadata.shortcut`, a comma-separated string: - -```yaml -metadata: - shortcut: "challenge this, tenth man" -``` - -A file may declare several words; multi-word phrases match as exact substrings. - -### Files without a `metadata.shortcut` - -Fall back to the older contract: find the `## Shortcut` section and take backtick-quoted -words from lines matching `prompt contains {word}`. - -The fallback exists because this skill scans user-level and project-level directories as -well as plugin ones, and a skill written by someone else may still declare its words the -old way. A file that has `metadata.shortcut` is read only from frontmatter — its -`## Shortcut` section is prose for human readers, and a backtick there means nothing. - -## Dispatch Rules - -- Match magic words against the user's prompt; invoke the matching skill or command. -- Multiple matches: prefer highest-priority source, then longest match. -- No match: do nothing. -- After dispatching, inform the user which shortcut was triggered. - -## Direct Invocation - -When called directly (`shortcut:shortcut`), scan all three sources and list discovered shortcuts as a table: - -| Magic Word | Skill / Command | Source | Description | -| ---------- | --------------- | ------ | ----------- | diff --git a/plugins/spec-writer/.claude-plugin/plugin.json b/plugins/spec-writer/.claude-plugin/plugin.json deleted file mode 100644 index ecf10d0..0000000 --- a/plugins/spec-writer/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "spec-writer", - "description": "Writes technical specifications — requirements, interfaces, data models and architecture diagrams. Use when a design needs recording before it is built. Not for writing the code it specifies (agent-hale), nor for reviewing a spec already written (agent-ward).", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/spec-writer/LICENSE b/plugins/spec-writer/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/spec-writer/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/spec-writer/README.md b/plugins/spec-writer/README.md deleted file mode 100644 index 6a3098f..0000000 --- a/plugins/spec-writer/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# Spec Writer Plugin - -> Writes technical specifications — requirements, interfaces, data models and architecture -> diagrams. Use when a design needs recording before it is built. Not for writing the code it -> specifies (agent-hale), nor for reviewing a spec already written (agent-ward). - -The spec-writer plugin produces detailed technical specifications for the development team. -It is invoked by `agent-ward` (Architect) and `agent-twain` (Technical Writer), and uses -`ascii-grapher` for architecture diagrams and flow charts. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install spec-writer -``` - -## How It Works - -### Specification Workflow - -1. **Understand** — Reads `PLAN.md`, project docs, and caller's context -2. **Draft** — Writes specs with embedded architecture diagrams (via `ascii-grapher`) -3. **Finalize** — Ensures documents stay under 5000 words / 800 lines - -### Document Types - -| Document | Location | Content | -| ------------- | ------------ | ------------------------------------------------- | -| `README.md` | Project root | High-level overview, purpose, features, examples | -| `CONCEPTS.md` | Project root | Core concepts, architecture, design principles | -| `docs/*.md` | `docs/` | Implementation details and technical requirements | - -### Diagrams - -The spec-writer automatically invokes `ascii-grapher` to produce: - -- System architecture diagrams -- Data flow diagrams -- Sequence diagrams for critical interactions - -## Usage - -### Magic Words - -- `write spec` → Full specification workflow -- `draft spec` → Full specification workflow -- `spec-writer` → Direct invocation - -## License - -MIT diff --git a/plugins/spec-writer/evals/review-a-spec/graders/does-not-fire.md b/plugins/spec-writer/evals/review-a-spec/graders/does-not-fire.md deleted file mode 100644 index 1d616b4..0000000 --- a/plugins/spec-writer/evals/review-a-spec/graders/does-not-fire.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -type: tool_used -tool: Skill -input_match: '"skill"\s*:\s*"spec-writer' -min: 0 -max: 0 ---- - -A labelled near-miss that the baseline fired on all three runs. The document already -exists and the task is to find its holes; this skill writes specifications rather than -reviewing them. diff --git a/plugins/spec-writer/evals/review-a-spec/prompt.md b/plugins/spec-writer/evals/review-a-spec/prompt.md deleted file mode 100644 index 0a92c6f..0000000 --- a/plugins/spec-writer/evals/review-a-spec/prompt.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: review-a-spec -tags: [trigger] -runs: 3 -max_turns: 8 -timeout_seconds: 300 ---- - -`docs/specs/payments-v2.md` came back from the vendor this morning and I am not confident -it covers everything -- I already know idempotency keys are not in there anywhere. Review -this spec and tell me what is missing before I sign off on it. diff --git a/plugins/spec-writer/evals/trigger-queries.json b/plugins/spec-writer/evals/trigger-queries.json deleted file mode 100644 index 00f319e..0000000 --- a/plugins/spec-writer/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "spec-writer", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "write up the design before we build it", - "should_trigger": true, - "split": "train" - }, - { - "query": "i need an RFC for this API change", - "should_trigger": true, - "split": "train" - }, - { - "query": "document the interface contract between these two services", - "should_trigger": true, - "split": "train" - }, - { - "query": "we agreed on the approach, put it in a spec", - "should_trigger": true, - "split": "train" - }, - { - "query": "draft a technical specification for the new billing flow", - "should_trigger": true, - "split": "train" - }, - { - "query": "the team needs something written down to work from", - "should_trigger": true, - "split": "train" - }, - { - "query": "write the requirements and data model for this feature", - "should_trigger": true, - "split": "validation" - }, - { - "query": "produce a design doc reviewers can comment on", - "should_trigger": true, - "split": "validation" - }, - { - "query": "formalise this proposal so it can be reviewed", - "should_trigger": true, - "split": "validation" - }, - { - "query": "capture the architecture decision and the alternatives we rejected", - "should_trigger": true, - "split": "validation" - }, - { - "query": "design this system for me", - "should_trigger": false, - "split": "train" - }, - { - "query": "write the user guide for this feature", - "should_trigger": false, - "split": "train" - }, - { - "query": "write the changelog for the release", - "should_trigger": false, - "split": "train" - }, - { - "query": "generate an OpenAPI schema from these handlers", - "should_trigger": false, - "split": "train" - }, - { - "query": "review this spec and tell me what's missing", - "should_trigger": false, - "split": "train" - }, - { - "query": "what is an RFC, exactly", - "should_trigger": false, - "split": "train" - }, - { - "query": "write a job description for a backend engineer", - "should_trigger": false, - "split": "validation" - }, - { - "query": "summarise the notes from yesterday's meeting", - "should_trigger": false, - "split": "validation" - }, - { - "query": "turn this spec into Jira tickets", - "should_trigger": false, - "split": "validation" - }, - { - "query": "write the tests described in this spec", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/spec-writer/skills/spec-writer/SKILL.md b/plugins/spec-writer/skills/spec-writer/SKILL.md deleted file mode 100644 index 80b079c..0000000 --- a/plugins/spec-writer/skills/spec-writer/SKILL.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -name: spec-writer -description: Writes technical specifications — requirements, interfaces, data models and architecture diagrams. Use when a design needs recording before it is built. Not for writing the code it specifies (agent-hale), nor for reviewing a spec already written (agent-ward). -license: MIT -allowed-tools: - - Read - - Glob - - Grep - - Write - - Edit -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "write spec, draft spec, spec-writer" ---- - -# Spec Writer Skill - -Support tool that produces technical specifications. Invoked by agent-ward (architecture/design specs), -agent-twain (structured technical documents), and ascii-grapher (architecture diagrams). - -## Shortcut - -This skill is triggered when the user's prompt contains `write spec`, `draft spec`, or `spec-writer`. - -## How It Works - -Each phase assumes an input: a scope from the caller, context to draft from. When one is -missing, say what was missing and stop rather than drafting around it. A spec records -decisions that were already made; a requirement nobody stated is not one of them, and written -down here it becomes one the moment someone builds from it. - -### Phase 1: Understand - -1. Read `PLAN.md` (if present) for context and goals. -2. Review README.md, CONCEPTS.md, and related docs. -3. Understand scope from the caller's request or user prompt. - -### Phase 2: Draft and Review - -Draft technical specs covering: - -- Project overview and goals -- Functional and non-functional requirements -- System architecture and design -- Implementation details and constraints -- Open questions and future considerations - -Invoke `ascii-grapher:ascii-grapher` for system architecture, data flow, and sequence diagrams. -Embed diagrams as fenced code blocks. Split into `docs/` with cross-references if a spec -exceeds one file. When called directly by user, present drafts for review. - -### Phase 3: Finalize - -Keep each document under 5000 words / 800 lines. Loop back to Phase 2 if review feedback requires refinement. - -## Team Coordination - -- Called by **agent-ward**: produce architecture/design specs. Report back to Ward. -- Called by **agent-twain**: produce structured technical documents. Report back to Twain. -- Called by **agent-smith**: produce specs for units of work in `PLAN.md`. Report back to Smith. -- Called **directly by user**: full workflow with user review. diff --git a/plugins/tenth-man/.claude-plugin/plugin.json b/plugins/tenth-man/.claude-plugin/plugin.json deleted file mode 100644 index f5b8bd9..0000000 --- a/plugins/tenth-man/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "tenth-man", - "description": "Devil's advocate — challenges the assumptions behind a plan and names the blind spots a group has agreed past. Use before committing to a decision.", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/tenth-man/LICENSE b/plugins/tenth-man/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/tenth-man/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/tenth-man/README.md b/plugins/tenth-man/README.md deleted file mode 100644 index 3b2e83b..0000000 --- a/plugins/tenth-man/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# Tenth Man Plugin - -> Devil's advocate — challenges the assumptions behind a plan and names the blind spots a group has -> agreed past. Use before committing to a decision. - -Named after the "tenth man rule" — if nine people agree, the tenth must argue the opposite. -This plugin systematically challenges plans, proposals, designs, and code changes to surface -hidden risks and blind spots before they become real problems. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install tenth-man -``` - -## How It Works - -### Challenge Workflow - -1. **Understand** — reads and summarizes the subject under review -2. **Challenge assumptions** — surfaces and stress-tests implicit assumptions, rated by severity -3. **Surface risks** — identifies failure modes, second-order effects, missing perspectives, and reversibility concerns -4. **Suggest alternatives** — proposes concrete mitigations for high-severity items -5. **Verdict** — delivers a Go / Pause / Reconsider recommendation with top action items - -## Usage - -### Slash Command - -```text -/tenth-man -``` - -### Magic Words - -Typing a prompt that contains `challenge this` or `tenth man` will auto-dispatch this skill -via the shortcut plugin. - -### Examples - -```text -/tenth-man Review our plan to migrate from REST to GraphQL -``` - -```text -Here's our proposal for the new auth system. challenge this -``` - -## License - -MIT diff --git a/plugins/tenth-man/evals/trigger-queries.json b/plugins/tenth-man/evals/trigger-queries.json deleted file mode 100644 index e44b15d..0000000 --- a/plugins/tenth-man/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "tenth-man", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation. Near-misses hardened 2026-09-16 after a measured 3-sample blind-router baseline scored this set 20/20: a set at the ceiling cannot register a loss when its description is edited, so negatives no router would have reached were replaced with ones a sibling skill owns.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "challenge this plan", - "should_trigger": true, - "split": "train" - }, - { - "query": "we're about to sign off on this -- someone should take the opposite side", - "should_trigger": true, - "split": "train" - }, - { - "query": "what could go wrong with this approach", - "should_trigger": true, - "split": "train" - }, - { - "query": "we all agreed too fast -- poke holes in it", - "should_trigger": true, - "split": "train" - }, - { - "query": "argue the other side for me", - "should_trigger": true, - "split": "train" - }, - { - "query": "what are we not seeing here", - "should_trigger": true, - "split": "train" - }, - { - "query": "play devil's advocate on this design", - "should_trigger": true, - "split": "validation" - }, - { - "query": "stress-test my assumptions", - "should_trigger": true, - "split": "validation" - }, - { - "query": "tell me why this is a bad idea", - "should_trigger": true, - "split": "validation" - }, - { - "query": "before we commit to this, argue me out of it", - "should_trigger": true, - "split": "validation" - }, - { - "query": "review this code", - "should_trigger": false, - "split": "train" - }, - { - "query": "is this design secure", - "should_trigger": false, - "split": "train" - }, - { - "query": "what are the risks in our dependencies", - "should_trigger": false, - "split": "train" - }, - { - "query": "list the pros and cons", - "should_trigger": false, - "split": "train" - }, - { - "query": "fix the problems in this plan", - "should_trigger": false, - "split": "train" - }, - { - "query": "keep this argument to one topic at a time", - "should_trigger": false, - "split": "train" - }, - { - "query": "what's the best approach here", - "should_trigger": false, - "split": "validation" - }, - { - "query": "summarise the objections raised", - "should_trigger": false, - "split": "validation" - }, - { - "query": "run a security review", - "should_trigger": false, - "split": "validation" - }, - { - "query": "is this ready for production", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/tenth-man/skills/tenth-man/SKILL.md b/plugins/tenth-man/skills/tenth-man/SKILL.md deleted file mode 100644 index c2bae48..0000000 --- a/plugins/tenth-man/skills/tenth-man/SKILL.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -name: tenth-man -description: Devil's advocate — challenges the assumptions behind a plan and names the blind spots a group has agreed past. Use before committing to a decision. -license: MIT -allowed-tools: - - Read - - Glob - - Grep - - Bash(git log:*) - - Bash(git diff:*) -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "challenge this, tenth man" ---- - -# Tenth Man Skill - -Structured devil's advocate: challenges assumptions, surfaces hidden risks, identifies blind spots. - -This is the one agent whose scope is deliberately outside the brief. Where `agent-ellis` -reviews a change against the purpose it was given and `agent-ward` designs for the purpose the -plan states, tenth-man challenges the purpose itself — the premise, the assumption nobody -stated, the requirement the group agreed past. Nothing is out of scope here, including whether -the work should happen at all. - -## Shortcut - -This skill is triggered when the user's prompt contains `challenge this` or `tenth man`. - -Each phase below assumes a subject to challenge. When it is missing or too thin to read — no -plan, no diff, a proposal stated in a single line — say so and stop rather than inventing -assumptions in order to have something to stress-test. Manufactured dissent is this role's -own failure mode, and it spends exactly the credibility the real findings will need. - -## Phase 1: Understand the Subject - -Read the plan, proposal, or code. Gather context from the user's prompt, referenced files, -recent git history (for code changes), and related codebase files. Confirm alignment by -summarizing back in **one sentence**. - -## Phase 2: Challenge Assumptions - -For each implicit assumption: state it explicitly, stress-test ("what if the opposite were true?"), -rate severity (low/medium/high/critical). Present as a numbered list, ordered by severity. - -## Phase 3: Surface Risks and Blind Spots - -Look for: - -- **Failure modes** — production, scale, edge cases -- **Second-order effects** — downstream consequences -- **Missing perspectives** — unrepresented viewpoints/use cases -- **Premature consensus** — converging too fast without exploring alternatives -- **Reversibility** — how hard to undo if wrong - -One-line summary plus brief explanation per risk. - -## Phase 4: Suggest Alternatives or Mitigations - -For each high/critical severity item, propose either an alternative approach or a mitigation. -Keep suggestions concrete and actionable. - -## Phase 5: Verdict - -1. **Go** (risks acceptable) / **Pause** (address items first) / **Reconsider** (re-evaluate fundamentals) -2. **Top 3 items** the group must address regardless -3. Remind: dissent is structural, not personal - -## Team Coordination - -**Contract rules:** - -- Invoked by `agent-smith`: challenge the plan, return verdict (Go/Pause/Reconsider) with top items. Smith acts on verdict. -- Invoked by `agent-ward`: challenge the architecture design, return findings. Ward may revise. -- Invoked directly by user: run the full 5-phase workflow on the provided subject. - -## Output Style - -Follow `briefing:briefing` for everything addressed to the user: the verdict first, each -challenge in one line before its explanation, detail only where asked, and one numbered topic -at a time when the review opens a decision. - -Brevity applies to the wording, never to the findings. A challenge that is real is reported -even when reporting it is inconvenient, and its severity is stated plainly. - -## Tone - -Challenge ideas, not people. Acknowledge strengths before dissecting risks. diff --git a/plugins/test-runner/.claude-plugin/plugin.json b/plugins/test-runner/.claude-plugin/plugin.json deleted file mode 100644 index 2e25b3b..0000000 --- a/plugins/test-runner/.claude-plugin/plugin.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "test-runner", - "description": "Detects the project's test framework, runs its suite, and reports what passed, what failed and why. Runs tests only — it does not review the code (agent-ellis).", - "version": "2.1.0", - "license": "MIT", - "author": { - "name": "cmj", - "url": "https://github.com/cmj0121" - } -} diff --git a/plugins/test-runner/LICENSE b/plugins/test-runner/LICENSE deleted file mode 100644 index cdd1829..0000000 --- a/plugins/test-runner/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 cmj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/plugins/test-runner/README.md b/plugins/test-runner/README.md deleted file mode 100644 index 8df13b0..0000000 --- a/plugins/test-runner/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Test Runner Plugin - -> Detects the project's test framework, runs its suite, and reports what passed, what failed and -> why. Runs tests only — it does not review the code (agent-ellis). - -A shared support tool that auto-detects and runs the project's test framework. -Used by multiple team agents for self-checks, QA, and pre-release verification. - -## Installation - -Install via the wisdom marketplace: - -```bash -/plugin install test-runner -``` - -## Supported Frameworks - -| Language | Frameworks | -| ---------- | --------------- | -| JavaScript | npm test, npx | -| Python | pytest | -| Go | go test | -| Rust | cargo test | -| Java | maven, gradle | -| Ruby | rspec, minitest | -| Elixir | mix test | -| Make | make test | - -## Usage - -### Magic Words - -- `run tests` → Detect and run the test suite -- `test-runner` → Direct invocation - -## License - -MIT diff --git a/plugins/test-runner/evals/trigger-queries.json b/plugins/test-runner/evals/trigger-queries.json deleted file mode 100644 index af9b4de..0000000 --- a/plugins/test-runner/evals/trigger-queries.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "skill": "test-runner", - "about": "Trigger eval queries for this skill's description. A query is labelled with whether the skill should activate for it; the negatives are near-misses that share vocabulary with the skill but need something else. Split fixed so successive description edits are compared on the same ground: tune against train, judge against validation. Near-misses hardened 2026-09-16 after a measured 3-sample blind-router baseline scored this set 20/20: a set at the ceiling cannot register a loss when its description is edited, so negatives no router would have reached were replaced with ones a sibling skill owns.", - "how_to_run": "`make eval` is the committed runner, but it covers only the queries a 3-sample blind-router baseline actually missed, not this whole file -- see CLAUDE.md for why 13 and not 380. To judge the rest: `skillgrade` runs a labelled set like this one and exits non-zero when the pass rate falls below a threshold. Needing nothing installed: run each query with `claude -p --output-format json` and count the runs whose transcript contains a Skill tool_use naming this skill. Cheapest of all, and closest to the router's real conditions: give a model only the name and description of every installed skill, with no bodies and no repo access, and have it pick one skill or none per query. `claude plugin eval`, which `make eval` drives, is generally available rather than early access; what it needs instead is a credential, a network and real money -- $0.142 a run, measured -- which is why it sits outside `make test` and CI does not run it. It will not reproduce this file query-for-query either: a bare query does not fire a skill, so a case is one of these queries rewritten as a realistic turn. This file stays the cheap, free, offline record.", - "runs_per_query": 3, - "trigger_rate_threshold": 0.5, - "queries": [ - { - "query": "can you check whether anything broke after that refactor", - "should_trigger": true, - "split": "train" - }, - { - "query": "run the suite and tell me what's red", - "should_trigger": true, - "split": "train" - }, - { - "query": "i just pulled main, is this branch green", - "should_trigger": true, - "split": "train" - }, - { - "query": "pytest or npm test, whichever this repo uses — just run it", - "should_trigger": true, - "split": "train" - }, - { - "query": "before i open the PR i want to know the tests pass", - "should_trigger": true, - "split": "train" - }, - { - "query": "which tests are failing right now", - "should_trigger": true, - "split": "train" - }, - { - "query": "did my change break anything", - "should_trigger": true, - "split": "validation" - }, - { - "query": "execute the test suite and summarise the failures", - "should_trigger": true, - "split": "validation" - }, - { - "query": "is ~/src/api safe to merge, test-wise", - "should_trigger": true, - "split": "validation" - }, - { - "query": "my manager asked whether the branch is passing", - "should_trigger": true, - "split": "validation" - }, - { - "query": "write a unit test for the parser function", - "should_trigger": false, - "split": "train" - }, - { - "query": "three tests are failing, go fix them", - "should_trigger": false, - "split": "train" - }, - { - "query": "check our test dependencies are up to date", - "should_trigger": false, - "split": "train" - }, - { - "query": "the tests pass -- now tell me if the code is any good", - "should_trigger": false, - "split": "train" - }, - { - "query": "set up a GitHub Actions workflow that runs tests on PRs", - "should_trigger": false, - "split": "train" - }, - { - "query": "the suite takes 20 minutes, how do i speed it up", - "should_trigger": false, - "split": "train" - }, - { - "query": "convert these mocha tests to vitest", - "should_trigger": false, - "split": "validation" - }, - { - "query": "what testing framework should i pick for a new go service", - "should_trigger": false, - "split": "validation" - }, - { - "query": "run the linter over src/", - "should_trigger": false, - "split": "validation" - }, - { - "query": "benchmark this hot function", - "should_trigger": false, - "split": "validation" - } - ] -} diff --git a/plugins/test-runner/skills/test-runner/SKILL.md b/plugins/test-runner/skills/test-runner/SKILL.md deleted file mode 100644 index ea78a3b..0000000 --- a/plugins/test-runner/skills/test-runner/SKILL.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -name: test-runner -description: Detects the project's test framework, runs its suite, and reports what passed, what failed and why. Runs tests only — it does not review the code (agent-ellis). -license: MIT -model: haiku -context: fork -background: false -allowed-tools: - - Bash(npm test:*) - - Bash(npm run:*) - - Bash(npx:*) - - Bash(pytest:*) - - Bash(python -m pytest:*) - - Bash(go test:*) - - Bash(make test:*) - - Bash(cargo test:*) - - Bash(mvn test:*) - - Bash(gradle test:*) - - Bash(bundle exec:*) - - Bash(mix test:*) - - Read - - Glob - - Grep -metadata: - author: cmj@cmj.tw - version: "2.1.0" - shortcut: "run tests, test-runner" - verdict: "__TEST_RESULT__" ---- - -# Test Runner - -Used by agent-hale (self-check), agent-ellis (QA), agent-page (pre-release). - -## Shortcut - -This skill is triggered when the user's prompt contains `run tests` or `test-runner`. - -## How It Works - -Each phase assumes the previous one produced something: a detected framework, a command that -ran. When it did not, report that and stop — Phase 1 already states the rule, and it is the -pattern for all of them. A suite that could not run is not a suite that passed. - -### Phase 1: Detect Test Framework - -Auto-detect by checking config files. If multiple detected, run all. If none, report and stop. - -| Config File | Runner | Command | -| ----------------------------------- | ------- | ------------------- | -| `package.json` with `test` script | npm | `npm test` | -| `pytest.ini` / `pyproject.toml` | pytest | `pytest` | -| `setup.cfg` with `[tool:pytest]` | pytest | `python -m pytest` | -| `go.mod` | go test | `go test ./...` | -| `Makefile` with `test` target | make | `make test` | -| `Cargo.toml` | cargo | `cargo test` | -| `pom.xml` | maven | `mvn test` | -| `build.gradle` / `build.gradle.kts` | gradle | `gradle test` | -| `Gemfile` with `rspec` / `minitest` | bundler | `bundle exec rspec` | -| `mix.exs` | mix | `mix test` | - -### Phase 2: Run Tests - -Execute detected command(s). Capture: total/passed/failed/skipped counts, -failure error messages, duration. - -### Phase 3: Report Results - -Return a structured report: - -```txt -__TEST_RESULT__ -Framework: <name> -Command: <command> -Status: PASS / FAIL -Total: <n> -Passed: <n> -Failed: <n> -Skipped: <n> -Duration: <time> -__TEST_RESULT__ -``` - -If tests fail, include failure details (file, test name, error message). - -## Team Coordination - -**Available to:** agent-hale, agent-ellis, agent-page, agent-ross. Always emit the -`__TEST_RESULT__` block when invoked; caller decides how to act. diff --git a/plugins/wisdom/.claude-plugin/plugin.json b/plugins/wisdom/.claude-plugin/plugin.json new file mode 100644 index 0000000..71f1bae --- /dev/null +++ b/plugins/wisdom/.claude-plugin/plugin.json @@ -0,0 +1,10 @@ +{ + "name": "wisdom", + "description": "Single-purpose skills to plan, build, review and ship software, led by smith.", + "version": "3.0.0", + "license": "MIT", + "author": { + "name": "cmj", + "url": "https://github.com/cmj0121" + } +} diff --git a/plugins/agent-ellis/LICENSE b/plugins/wisdom/LICENSE similarity index 100% rename from plugins/agent-ellis/LICENSE rename to plugins/wisdom/LICENSE diff --git a/plugins/lingua/hooks/hooks.json b/plugins/wisdom/hooks/hooks.json similarity index 100% rename from plugins/lingua/hooks/hooks.json rename to plugins/wisdom/hooks/hooks.json diff --git a/plugins/lingua/hooks/lingua-session-start.py b/plugins/wisdom/hooks/lingua-session-start.py similarity index 100% rename from plugins/lingua/hooks/lingua-session-start.py rename to plugins/wisdom/hooks/lingua-session-start.py diff --git a/plugins/wisdom/skills/audit/SKILL.md b/plugins/wisdom/skills/audit/SKILL.md new file mode 100644 index 0000000..7af195c --- /dev/null +++ b/plugins/wisdom/skills/audit/SKILL.md @@ -0,0 +1,47 @@ +--- +name: audit +description: Audits dependencies for known vulnerabilities and outdated versions across npm, pip, go, cargo and bundler. Use before a release or when a lockfile changes. +license: MIT +metadata: + shortcut: "audit deps" +--- + +# Audit + +Check dependencies for known vulnerabilities and staleness. Report — never upgrade. + +## Steps + +1. **Detect ecosystems** from their manifests and lockfiles; a repo may have several. +2. **Run** each ecosystem's tools. A tool that is not installed: say so and continue with + the rest — never install one without asking. + + | Ecosystem | Vulnerabilities | Outdated | + | --------- | -------------------- | --------------------- | + | npm | `npm audit --json` | `npm outdated --json` | + | pip | `pip-audit -f json` | `pip list --outdated` | + | go | `govulncheck ./...` | `go list -m -u all` | + | cargo | `cargo audit --json` | `cargo outdated` | + | bundler | `bundle audit check` | `bundle outdated` | + +3. **Filter.** A vulnerability counts when the installed version is in the affected range. + Mark whether the package is direct or transitive, and whether it is a dev dependency. + Outdated means a newer major, or a minor more than a year behind — not every patch. + +## Output + +| Sev | Package | Installed | Fixed in | Advisory | Direct? | +| --- | ------- | --------- | -------- | -------- | ------- | + +Then outdated direct dependencies: + +| Package | Installed | Latest | Behind | +| ------- | --------- | ------ | ------ | + +End with one line: + +```text +AUDIT: CLEAN|FINDINGS|INCOMPLETE — <n> vulnerable, <n> outdated, <tools missing> +``` + +`INCOMPLETE` whenever a tool could not run, so a missing scanner never reads as clean. diff --git a/plugins/wisdom/skills/brief/SKILL.md b/plugins/wisdom/skills/brief/SKILL.md new file mode 100644 index 0000000..a95daa9 --- /dev/null +++ b/plugins/wisdom/skills/brief/SKILL.md @@ -0,0 +1,30 @@ +--- +name: brief +description: Sets a standing brief output style — result first, one topic at a time, detail on request. Use when the user asks for shorter answers or one decision at a time. +license: MIT +metadata: + shortcut: "brief me" +--- + +# Brief + +Apply these rules to every reply for the rest of the session. They change the shape of an +answer, never its content: no finding, risk, correction or checkpoint is dropped to be short. + +## Rules + +1. **Result first.** Open with the outcome, then only what the user needs to act on it. Use + a table when items share a shape. Leave out the process — what was read, tried or ruled + out — unless ruling something out is the finding. +2. **Question before analysis.** When the user must decide, state the question in one line, + then the options as a table (what each does, what it costs), then your recommendation and + one sentence of why. End by offering detail. +3. **Detail on request.** Expand only what the user asks about; go back to rule 2 for the + next question. +4. **One topic at a time.** Never stack unrelated decisions in one message. Number them + against the total — `Topic (1/3): …` — and renumber out loud if the total changes. + +## Stop + +`brief off`, or the user asking for full detail, ends the style for the rest of the session. +Detail asked for on one question is not a request to stop. diff --git a/plugins/wisdom/skills/challenge/SKILL.md b/plugins/wisdom/skills/challenge/SKILL.md new file mode 100644 index 0000000..afe88d9 --- /dev/null +++ b/plugins/wisdom/skills/challenge/SKILL.md @@ -0,0 +1,48 @@ +--- +name: challenge +description: Argues against a plan or decision to surface hidden assumptions, risks and blind spots, ending in Go, Pause or Reconsider. Use before committing to a decision. +license: MIT +metadata: + shortcut: "tenth man" +--- + +# Challenge + +Be the dissenting voice. Unlike every other skill, nothing is out of scope — including +whether the work should happen at all. + +A subject too thin to challenge (no plan, one line of intent) is reported as such. Do not +invent assumptions to have something to attack: manufactured dissent spends the credibility +real findings need. + +## Steps + +1. **Restate** the subject in one sentence, so the user can see you read it right. +2. **Assumptions** — name each one the plan relies on without saying so. For each, ask what + happens if the opposite is true, and rate it low / medium / high / critical. +3. **Blind spots** — look for: + - failure modes at scale, under load, on bad input + - second-order effects on users, other teams, later work + - who or what the plan does not account for + - consensus reached before an alternative was weighed + - how costly it is to undo +4. **Alternatives** — for each high or critical item, one concrete alternative or + mitigation. +5. **Verdict.** + +## Output + +Most severe first, one line per item before any detail: + +| # | Sev | Assumption or risk | If wrong | Mitigation | +| --- | --- | ------------------ | -------- | ---------- | + +```text +VERDICT: GO|PAUSE|RECONSIDER — <the top item to address> +``` + +- `GO` — the risks are acceptable as they stand. +- `PAUSE` — address the named items, then proceed. +- `RECONSIDER` — a premise is wrong; rethink before building. + +Challenge the idea, never the people. Name what the plan gets right in one line first. diff --git a/plugins/wisdom/skills/changelog/SKILL.md b/plugins/wisdom/skills/changelog/SKILL.md new file mode 100644 index 0000000..67929dc --- /dev/null +++ b/plugins/wisdom/skills/changelog/SKILL.md @@ -0,0 +1,38 @@ +--- +name: changelog +description: Generates changelog entries from git history, grouped by change type. Use when a release needs notes or the CHANGELOG has fallen behind. +license: MIT +metadata: + shortcut: "gen changelog" +--- + +# Changelog + +Turn a range of commits into changelog entries. Write entries — do not restructure the rest +of the CHANGELOG. + +## Steps + +1. **Pick the range:** the caller's, else the latest tag to `HEAD` + (`git describe --tags --abbrev=0`), else the whole history. +2. **Read** `git log <range> --no-merges --format='%h %s'`, and a commit's body only when + its subject does not say what changed for a user. +3. **Group** by conventional type. Drop what users never see — `test`, `chore`, `ci`, + `style`, refactors with no behaviour change — unless the caller asks for everything. +4. **Rewrite** each kept subject for a user: what changed for them, in the past tense, one + line, with the short hash. Merge commits that describe one change. +5. **Write** into `CHANGELOG.md` under an `Unreleased` heading (or the version the caller + names), following the file's existing format. No CHANGELOG exists: print the entries. + +## Groups + +| Heading | From | +| -------- | ----------------------------------------- | +| Breaking | `!` after the type, or `BREAKING CHANGE:` | +| Added | `feat` | +| Fixed | `fix` | +| Changed | `perf`, behaviour-changing `refactor` | +| Docs | `docs`, only when user-facing | + +Breaking always comes first and says what the user must do. A non-conventional subject is +placed by what the commit does, never dropped for its format. diff --git a/plugins/wisdom/skills/code/SKILL.md b/plugins/wisdom/skills/code/SKILL.md new file mode 100644 index 0000000..a4eac99 --- /dev/null +++ b/plugins/wisdom/skills/code/SKILL.md @@ -0,0 +1,47 @@ +--- +name: code +description: Implements one unit of work with its tests, following the project's conventions. Use when what to build is settled and the code is the task. +license: MIT +metadata: + shortcut: "code it" +--- + +# Code + +Implement one unit and its tests. Read the unit's row and Context in `PLAN.md` when one +exists; otherwise the prompt is the unit. + +## Steps + +1. **Understand.** Read only what the unit touches: the files it edits in full, everything + else by declaration lines. Never re-read a file already in context. If the unit is + ambiguous, ask — do not guess an interface. +2. **Baseline.** Run the project's tests once (the `test` skill, or Context's command) so a + failure afterwards is attributable. +3. **Build, test first:** + - Bug: failing regression test → minimal fix → green. + - Feature: one test per acceptance criterion → implement → refactor only once green. + - Refactor: green before, small steps, green after every step. +4. **Check.** Run the tests again; exercise the change the way a user would when tests + cannot (a request, a CLI run, a page load). +5. **Report** in the format below. + +## Code rules + +- Build what the unit asks for — no speculative options, layers or abstractions. +- Follow the project's existing conventions over general best practice. +- Validate at system boundaries only; trust internal invariants. +- No comments that restate the code; no `TODO`s or dead fallbacks left behind. +- Stuck after two attempts at the same failure: stop and report what was tried. + +## Report + +```text +Unit: <id or one line> +Files: <path> — <why>, one per line +Tests: <added/changed>; <pass>/<total>, baseline <pass>/<total> +Verified: <what was exercised beyond tests, or "tests only"> +Open: <deferred items and why, or none> +``` + +Do not commit — that is `commit`'s job. diff --git a/plugins/wisdom/skills/commit/SKILL.md b/plugins/wisdom/skills/commit/SKILL.md new file mode 100644 index 0000000..65c2fb4 --- /dev/null +++ b/plugins/wisdom/skills/commit/SKILL.md @@ -0,0 +1,38 @@ +--- +name: commit +description: Writes a conventional commit message for the staged change and commits it. Use when a finished change is ready to record in git. +license: MIT +metadata: + shortcut: "commit it" +--- + +# Commit + +Write the message for what is staged and commit it. Nothing else: no push, no tag. + +## Steps + +1. `git diff --cached --stat`, then the staged diff itself. Nothing staged: ask what to + stage — never `git add -A` on your own. +2. If the repo has a commit template (`git config commit.template`) or a visible convention + in `git log -10`, follow it. Otherwise use the format below. +3. Commit. If a hook fails, report its output and stop — never `--no-verify`, never amend a + commit that is not yours. +4. Report the short hash and subject. + +## Format + +```text +<type>(<scope>): <subject> + +<body> + +<footer> +``` + +- `type`: feat, fix, docs, test, refactor, perf, build, chore. +- `subject`: imperative, ≤ 72 characters, no trailing period. +- `body`: why the change was made and what it trades off, wrapped at 72. Skip it when the + subject says everything. +- `footer`: `Refs: <issue>` only when the work came from an issue; `Closes: <issue>` only + on the commit that finishes it. Never infer an issue from a branch name. diff --git a/plugins/wisdom/skills/compact/SKILL.md b/plugins/wisdom/skills/compact/SKILL.md new file mode 100644 index 0000000..9d1c891 --- /dev/null +++ b/plugins/wisdom/skills/compact/SKILL.md @@ -0,0 +1,39 @@ +--- +name: compact +description: Re-renders the previous answer as a dense, scannable table, dropping prose but keeping every data point. Use when an answer ran longer than it needed to. +license: MIT +metadata: + shortcut: "compact it" +--- + +# Compact + +Re-render one earlier result in its densest readable form. Reformat only: never add, drop +or reinterpret a data point, and never write files. + +## Steps + +1. **Source:** the most recent substantive answer, unless the user points at another. None + exists: say so and stop — an empty table reads as a finding. +2. **Shape** — the first that fits: + - repeating records → a table, one row per record + - a flat set of attributes → a two-column key / value table + - neither → a tight list, one fact per line +3. **Compress:** drop framing, filler and repeated labels; keep every number, name, status + and caveat. Shorten a long cell with `…`, but never drop a column that holds unique data. +4. **Print** the result inline, then one summary line if the source had a conclusion. + +## Example + +Before: "The build finished in 12.4 seconds and produced three artifacts: the main bundle at +240 KB, the vendor bundle at 880 KB, and the runtime at 4 KB." + +After: + +| Artifact | Size | +| -------- | ------ | +| main | 240 KB | +| vendor | 880 KB | +| runtime | 4 KB | + +Build: OK · 12.4 s · 3 artifacts diff --git a/plugins/wisdom/skills/design/SKILL.md b/plugins/wisdom/skills/design/SKILL.md new file mode 100644 index 0000000..d3dd0af --- /dev/null +++ b/plugins/wisdom/skills/design/SKILL.md @@ -0,0 +1,51 @@ +--- +name: design +description: Decides an architecture, API shape or technology choice by weighing the options and their trade-offs. Use before building, when how to build is still open. +license: MIT +metadata: + shortcut: "design it" +--- + +# Design + +Settle one design question and record the decision. Decide — do not write the code or the +full specification. + +## Steps + +1. **State the question** in one sentence, with the constraints that bind it: the purpose, + the existing stack and conventions (`PLAN.md` Context, `CLAUDE.md`), scale, and what must + stay compatible. +2. **List 2–4 real options.** Include the one the codebase already leans toward. An option + nobody would pick is padding — drop it. +3. **Compare** them on what the purpose needs: complexity, fit with the existing code, + reversibility, operational cost, new dependencies. Say which becomes hard to change later. +4. **Recommend one** and say why in two sentences. When the choice is hard to reverse + (public API, data model, dependency, file format) or the options are close, ask the user + to choose before recording it. +5. **Record** the decision (below). When `PLAN.md` exists, append a row to its Decisions + table as well. + +## Design rules + +- Design for the stated purpose only: no layer, option or abstraction for a need nobody + raised. Name what was deliberately left out. +- Prefer the boring choice the project already uses over a better one it would have to + learn. +- Define interfaces by what callers need: inputs, outputs, errors — not internals. + +## Output + +```markdown +## Decision: <question> + +| Option | Trade-off | Hard to change later | +| ------ | --------- | -------------------- | + +**Chosen:** <option> — <why> +**Interface:** <signatures, routes, schema or format, when the decision defines one> +**Left out:** <what was not designed, and why> +``` + +A picture helps: hand the structure to `wisdom:diagram`. A spec is needed: hand the +decision to `wisdom:spec`. diff --git a/plugins/wisdom/skills/diagram/SKILL.md b/plugins/wisdom/skills/diagram/SKILL.md new file mode 100644 index 0000000..bc76e36 --- /dev/null +++ b/plugins/wisdom/skills/diagram/SKILL.md @@ -0,0 +1,47 @@ +--- +name: diagram +description: Draws ASCII diagrams of architecture, flows, states and sequences. Use when a decided structure is easier to see than read, or must render in a terminal. +license: MIT +metadata: + shortcut: "draw a diagram" +--- + +# Diagram + +Draw a structure that is already decided. Deciding it is `wisdom:design`'s job; a missing +piece of the structure is a question to ask, not a box to invent. + +## Steps + +1. **Name the subject and the kind** — pick the one form that fits: + + | Kind | Shows | + | ------------ | ----------------------------------- | + | Architecture | components and who calls whom | + | Flow | data or control moving step to step | + | State | states and the events between them | + | Sequence | messages between actors over time | + | Tree | hierarchy — directories, ownership | + +2. **List the nodes and edges** from the source (the prompt, `PLAN.md`, the code) before + drawing. Only what the source states. +3. **Draw** in a ` ```text ` fence with the characters below. +4. **Check** every line is the same width where boxes stack, no edge crosses a label, and + the diagram fits in 100 columns. Past 12 nodes, split it into two diagrams. + +## Characters + +```text +Boxes ┌───┐ │ │ └───┘ Arrows ──> <── │ ▼ ▲ +Branches ├── └── ┬ ┴ ┼ Labels ──label──> on the edge +``` + +Use plain ASCII (`+ - | > v`) instead when the caller asks or the output target cannot +render box-drawing characters. + +## Rules + +- Flow reads left-to-right or top-to-bottom; never both in one diagram. +- One label per edge, three words at most. +- Same kind of thing, same shape of box. +- No legend unless a shape or line style carries a meaning the labels do not. diff --git a/plugins/wisdom/skills/docs/SKILL.md b/plugins/wisdom/skills/docs/SKILL.md new file mode 100644 index 0000000..d24099b --- /dev/null +++ b/plugins/wisdom/skills/docs/SKILL.md @@ -0,0 +1,36 @@ +--- +name: docs +description: Writes or updates user-facing documentation — READMEs, guides, API references — to match the code. Use when a change needs documenting or docs went stale. +license: MIT +metadata: + shortcut: "document it" +--- + +# Docs + +Make the documentation match the code. Write for the reader who will use the thing, not for +the one who built it. + +## Steps + +1. **Find the change.** The caller's scope, else `git diff main...HEAD`. List the + user-visible effects: new or changed commands, flags, APIs, config, behaviour, removals. +2. **Find the docs it affects:** README, `docs/`, API references, examples, help text, + CHANGELOG pointers. Grep for the old names — stale mentions hide outside the obvious file. +3. **Update in place,** following each file's existing structure, tone and language. When a + project ships the same doc in more than one language, update every copy. +4. **Verify** each example and command against the code: flags exist, outputs match, paths + resolve. Run a command when running it is safe and cheap. +5. **Report** the files changed, one line each, and anything you could not verify. + +## Writing rules + +- Lead with what the reader can do, then how. One idea per paragraph. +- Show a working example before explaining the options. +- Use the code's exact names; never paraphrase an identifier, flag or path. +- Document behaviour, not implementation — internals belong in code and commits. +- Delete what is no longer true rather than marking it deprecated, unless users still need + a migration path; then write that path. +- A breaking change gets a short migration note: before, after, and the steps between. + +Release notes are `wisdom:changelog`'s job; a design record is `wisdom:spec`'s. diff --git a/plugins/wisdom/skills/lingua/SKILL.md b/plugins/wisdom/skills/lingua/SKILL.md new file mode 100644 index 0000000..6cbd521 --- /dev/null +++ b/plugins/wisdom/skills/lingua/SKILL.md @@ -0,0 +1,50 @@ +--- +name: lingua +description: Answers in the user's chosen language whatever they write in, remembered per project. Use to set, change or show that preference; not for translating files. +license: MIT +allowed-tools: + - Read + - Write + - Edit +metadata: + shortcut: "reply in" +--- + +# Lingua + +Keep a per-project response-language preference and apply it. Output language only: it +never changes what is answered. + +## Config + +`~/.claude/projects/<project-path>/memory/lingua.md`, where `<project-path>` is the working +directory with `/` replaced by `-`. Never committed. + +```yaml +--- +respond_in: zh-TW # reply language; required +discuss_in: auto # the language the user writes in; auto = detect +refine_question: false # restate the question in one line before answering +keep_terms_in: en # code, identifiers and technical terms stay in this language +glossary: [] # term normalisations, e.g. "K8s → Kubernetes" +--- +``` + +The plugin's SessionStart hook loads this file into every new session, so a saved +preference needs no magic word afterwards. + +## Steps + +1. **Load** the config. Present: apply it (below). Missing: ask the user — reply language, + whether to restate questions, whether to keep technical terms untranslated — then write + the file and confirm in one line. Never guess a language from the one the user writes in. +2. **Apply** for the rest of the session: + - write every reply in `respond_in`; + - keep code, identifiers, commands, paths and technical terms verbatim in + `keep_terms_in`, applying `glossary`; + - with `refine_question: true`, open with a one-line restatement of the question in + correct terminology — skip it when the question is already precise. +3. **Change** on request ("reply in Japanese", "stop restating"): edit the file, confirm in + one line, apply at once. `lingua off` pauses the rules for this session without touching + the file. +4. **Show** when invoked with nothing to change: the active settings and the file path. diff --git a/plugins/wisdom/skills/ops/SKILL.md b/plugins/wisdom/skills/ops/SKILL.md new file mode 100644 index 0000000..806c05f --- /dev/null +++ b/plugins/wisdom/skills/ops/SKILL.md @@ -0,0 +1,46 @@ +--- +name: ops +description: Reviews code and infrastructure for operational readiness — observability, reliability, performance, rollback. Use before a release reaches production. +license: MIT +metadata: + shortcut: "ops review" +--- + +# Ops + +Judge whether a change is safe to run in production. Read-only: report, never fix. + +## Scope + +The caller's scope, else `git diff <last tag>...HEAD`, else the service as a whole. Read the +deploy config (Dockerfile, CI, manifests, IaC) alongside the code it ships. + +## Checks + +1. **Observability** — failures are logged with enough context to act on, without secrets; + new paths emit the metrics or traces the project already uses; health checks cover new + dependencies. +2. **Reliability** — every outbound call has a timeout; retries are bounded and backed off; + a failing dependency degrades the feature, not the service; resources are released on + every path. +3. **Performance** — no query or call inside a loop over unbounded data; no unbounded + memory growth; heavy work is off the request path. Measure with the project's benchmark + when one exists (the `test` skill), otherwise say the finding is unmeasured. +4. **Deploy and rollback** — migrations are backward compatible or ordered; config and + secrets come from the environment; the change can be rolled back, or is behind a flag. +5. **Capacity** — new limits, quotas and pool sizes are set and justified. + +Report only what you can point at with `file:line`, and skip a check the change cannot +affect. + +## Output + +| Sev | Area | Location | Finding | Fix | +| --- | ---- | -------- | ------- | --- | + +```text +OPS: READY|CONCERN|BLOCK — <one-line reason> +``` + +`BLOCK` when the change can take the service down or cannot be rolled back; `CONCERN` for +anything else found; `READY` when nothing is. diff --git a/plugins/wisdom/skills/plan/SKILL.md b/plugins/wisdom/skills/plan/SKILL.md new file mode 100644 index 0000000..85db6c1 --- /dev/null +++ b/plugins/wisdom/skills/plan/SKILL.md @@ -0,0 +1,59 @@ +--- +name: plan +description: Turns an idea into PLAN.md — context, units of work and decisions — for later skills to build from. Use before non-trivial work starts. +license: MIT +metadata: + shortcut: "plan it" +--- + +# Plan + +Write `PLAN.md` at the repo root: the one place later skills read instead of rediscovering +the project. Plan only — do not design, code or commit. + +## Steps + +1. **Read, cheapest first, and stop once the question is answered:** `CLAUDE.md` and + `README.md` → directory layout → declaration lines (grep) → the files the change touches. + Never read a file already in context. +2. **Capture the issue** when the work came from one (`#123`, a URL, a ticket ID). Never + invent one; with no issue the field is `—`. +3. **Ask before writing** when the idea has more than one reasonable reading, or a choice is + hard to undo (public API, data model, dependency, package name). Offer 2–4 options with + the trade-off, recommendation first. One question at a time. +4. **Split the work** into units small enough for one commit each, and mark which depend on + which — units with no dependency can run in parallel. +5. **Write `PLAN.md`** in the shape below, then show the user the goal and the unit list. + +## PLAN.md + +```markdown +# PLAN — <goal in one line> + +## Context + +| Field | Content | +| -------- | ------------------------------------------- | +| Stack | languages, frameworks, package manager | +| Commands | exact test / lint / build invocations | +| Baseline | test result before any change | +| Map | `path` → role, only files this work touches | +| Issue | ref, or — | + +## Decisions + +| # | Question | Options | Chosen | Why | + +## Units + +| # | Unit | Acceptance | Depends on | Status | +``` + +Keep Context under 30 lines. `Acceptance` is what `review` will check the unit against: one +testable sentence per unit. + +## Rules + +- `PLAN.md` is a working file: never commit it. +- Updating an existing `PLAN.md`: change the rows that moved, keep the rest. +- A unit that needs an interface decided first gets a `design` unit ahead of it. diff --git a/plugins/wisdom/skills/release/SKILL.md b/plugins/wisdom/skills/release/SKILL.md new file mode 100644 index 0000000..f2eb1a2 --- /dev/null +++ b/plugins/wisdom/skills/release/SKILL.md @@ -0,0 +1,35 @@ +--- +name: release +description: Bumps the version, tags and publishes a release once the user has asked for one. Use only when a finished change is to be shipped as a version. +license: MIT +metadata: + shortcut: "release it" +--- + +# Release + +Cut a version. Every step that leaves the machine — push, tag, publish — needs the user's +explicit yes in this conversation; a release is never inferred from finished work. + +## Steps + +1. **Gate.** On the release branch (usually `main`), clean worktree, tests green (the `test` + skill). Any failure: stop and report — diagnosing it is not this skill's job. +2. **Version.** Read the current one from the tag list and the version files the project + keeps (`package.json`, `pyproject.toml`, `Cargo.toml`, `plugin.json`, …). Propose the + next by semver from the commits since the last tag: breaking → major, `feat` → minor, + otherwise patch. Ask the user to confirm the number. +3. **Bump** every version location to the same number, and update the CHANGELOG with + `wisdom:changelog` if the project keeps one. Commit as `chore(release): v<version>`. +4. **Confirm, then tag.** Show the commit, the tag name and the remote; wait for a yes. + Then `git tag -a v<version> -m "v<version>"` and push the branch and the tag. +5. **Publish** only what the project already publishes (`gh release create`, a registry, an + image), with the changelog entries as notes. A deploy the project has no pipeline for is + out of scope — say so. +6. **Report** the version, tag, and every place it was published. + +## Rules + +- Never move or delete an existing tag, never force-push, never skip hooks. +- Push to the remote the user names; with several remotes and no name, ask. +- A failed step stops the release where it is. Report what was done and what was not. diff --git a/plugins/wisdom/skills/resolve/SKILL.md b/plugins/wisdom/skills/resolve/SKILL.md new file mode 100644 index 0000000..b5f02b0 --- /dev/null +++ b/plugins/wisdom/skills/resolve/SKILL.md @@ -0,0 +1,40 @@ +--- +name: resolve +description: Works through a pull request's review comments one at a time, test first when behaviour changes. Use when a PR has feedback to address. Never merges. +license: MIT +allowed-tools: + - Bash(gh pr view:*) + - Bash(gh pr diff:*) +metadata: + shortcut: "resolve pr" +--- + +# Resolve + +Address a PR's open review feedback, item by item. GitHub through `gh`. Never merge. + +## Steps + +1. **Find the PR:** the number in the prompt, else `gh pr view --json number,url` for the + current branch. None: stop and say so. +2. **Collect open items** from both sources, then number them: + - reviews and comments: `gh pr view <n> --json reviews,comments` + - inline threads: `gh api repos/{owner}/{repo}/pulls/<n>/comments` + Skip resolved threads, outdated ones already addressed, and approvals with no request. +3. **For each item, in order,** decide one of: + - **Fix** — behaviour changes: failing test first, then the fix, then green. + Wording, naming or docs: just change it. + - **Push back** — the request is wrong or out of the PR's scope: draft a reply giving + the reason, and offer a follow-up issue for out-of-scope work. + - **Ask** — the request is ambiguous: ask the user, not the reviewer. + Show the decision and the change for each item before moving on. +4. **Commit** each fix on its own (`wisdom:commit`), referencing the comment it answers. +5. **Reply and push** only after the user approves: post the replies + (`gh pr comment` or a thread reply) and push the branch. +6. **Report** a table: item, decision, commit or reply. + +## Rules + +- Every write to GitHub — a reply, a push — is a checkpoint. +- Never resolve a thread on the reviewer's behalf; replying is enough. +- Never `gh pr merge`. diff --git a/plugins/wisdom/skills/review/SKILL.md b/plugins/wisdom/skills/review/SKILL.md new file mode 100644 index 0000000..6389e99 --- /dev/null +++ b/plugins/wisdom/skills/review/SKILL.md @@ -0,0 +1,50 @@ +--- +name: review +description: Reviews a diff for correctness, quality and fit to its acceptance criteria, ending in a one-line verdict. Use before a change is committed or merged. +license: MIT +metadata: + shortcut: "review it" +--- + +# Review + +Review a change and return findings with a verdict. Read-only: never edit files. + +## Scope + +The caller's diff, else `git diff` plus `git diff --cached`, else `git diff main...HEAD`. +Nothing to review: `VERDICT: SKIP`. Judge the change against its purpose — the unit's +acceptance in `PLAN.md`, or the prompt — not against work nobody asked for. + +## Checks + +1. **Correctness** — logic errors, unhandled edge cases, broken error paths, races. +2. **Acceptance** — each criterion met; nothing outside the unit's scope slipped in. +3. **Tests** — the change is covered; a bug fix has a regression test. Use a result the + caller passed; otherwise run the `test` skill once. +4. **Security** — hardcoded secrets, unvalidated input at a boundary, injection, sensitive + data in logs. Flag here; a full audit is the `secure` skill's job. +5. **Quality** — duplication, needless complexity, dead code, comments that restate code, + drift from the project's conventions. + +Report only what you can point at with `file:line`. No style nits a formatter would fix. + +## Verdict + +- `FAIL` — a correctness bug, failing test, security finding or unmet acceptance criterion. +- `WARN` — quality findings only. +- `PASS` — nothing found. + +## Output + +One finding per row, most severe first, then the verdict as the last line: + +| Sev | Location | Finding | Fix | +| --- | -------- | ------- | --- | + +```text +VERDICT: PASS|WARN|FAIL|SKIP — <one-line reason> +``` + +Always end with the `VERDICT` line, even with zero findings: a caller reads its absence as +a review that never ran. diff --git a/plugins/wisdom/skills/secure/SKILL.md b/plugins/wisdom/skills/secure/SKILL.md new file mode 100644 index 0000000..6faabd6 --- /dev/null +++ b/plugins/wisdom/skills/secure/SKILL.md @@ -0,0 +1,56 @@ +--- +name: secure +description: Reviews source code for security vulnerabilities and maps each finding to a CWE. Use when security is the question — the whole project, or the scope given. +license: MIT +metadata: + shortcut: "sec review" +--- + +# Secure + +Find security flaws in source and report each with its CWE. Read-only: report, never fix. + +## Scope + +The caller's scope (a diff, a directory, a file), else the whole project. For a diff, also +read the code the diff calls into — a flaw is often at the boundary it crosses. Skip vendored +code, lockfiles and generated files; dependencies are `wisdom:audit`'s job. + +## Steps + +1. **Map the attack surface:** entry points (routes, handlers, CLI args, message consumers, + file and env input), trust boundaries, and where secrets and user data flow. +2. **Trace untrusted input** from each entry point to where it is used, and check each class + below along the way. +3. **Confirm** every candidate by reading the code path; drop what an existing guard already + handles. A finding you cannot trace end to end is `Low` with "unconfirmed" in its text. + +## Classes + +| Class | CWE | +| ------------------------------ | ------------ | +| SQL / command / code injection | 89 / 78 / 94 | +| Cross-site scripting | 79 | +| Path traversal | 22 | +| SSRF | 918 | +| Missing or broken authz | 862 / 863 | +| Broken authentication | 287 | +| Hardcoded secret | 798 | +| Weak or misused crypto | 327 / 330 | +| Unsafe deserialization | 502 | +| Sensitive data in logs | 532 | +| Missing input validation | 20 | + +Other flaws get their nearest CWE. + +## Output + +| Sev | CWE | Location | Finding | Fix | +| --- | --- | -------- | ------- | --- | + +Severity: `Critical` exploitable remotely without auth · `High` exploitable with some access +· `Medium` needs an unlikely precondition · `Low` hardening. Most severe first, then one line: + +```text +SECURITY: CLEAN|FINDINGS — <n> critical, <n> high, <n> medium, <n> low +``` diff --git a/plugins/wisdom/skills/shortcut/SKILL.md b/plugins/wisdom/skills/shortcut/SKILL.md new file mode 100644 index 0000000..9950f7b --- /dev/null +++ b/plugins/wisdom/skills/shortcut/SKILL.md @@ -0,0 +1,37 @@ +--- +name: shortcut +description: Dispatches the skill whose magic word appears in the prompt, or lists every magic word available. Use at the start of a turn that may contain one. +license: MIT +allowed-tools: + - Glob + - Grep +--- + +# Shortcut + +Find the magic word in the prompt and run the skill that declares it. + +## Sources + +A skill declares its words in frontmatter as `metadata.shortcut`, a comma-separated string. +Read only that line — Grep `^\s+shortcut:` — never the whole file. Search, highest priority +first: + +1. `~/.claude/skills/*/SKILL.md` — user +2. `.claude/skills/*/SKILL.md` — project +3. `../*/SKILL.md`, relative to this skill's base directory — the other `wisdom` skills + +## Dispatch + +1. Match each word against the prompt as a case-insensitive substring. +2. More than one match: take the highest-priority source, then the longest word. +3. Invoke the matched skill with the rest of the prompt as its arguments, and say in one + line which word triggered it. +4. No match: do nothing and say nothing. + +## Listing + +Invoked on its own, with nothing to dispatch, print every word found: + +| Magic word | Skill | Source | +| ---------- | ----- | ------ | diff --git a/plugins/wisdom/skills/smith/SKILL.md b/plugins/wisdom/skills/smith/SKILL.md new file mode 100644 index 0000000..7e3a9f2 --- /dev/null +++ b/plugins/wisdom/skills/smith/SKILL.md @@ -0,0 +1,108 @@ +--- +name: smith +description: Drives a piece of work from idea to merge — plans it, then calls the wisdom skills to design, build, review and commit it. Use for substantial work. +license: MIT +metadata: + shortcut: "smith" +--- + +# Smith + +Coordinate; do not do the work. Every step below belongs to another skill, and Smith's job +is to call it with the right input, read its result, and decide what happens next. + +## Ground rules + +- **Two checkpoints.** Stop for the user to approve the plan, and to approve the merge. + Also stop whenever a skill asks a question only the user can answer, or a choice is hard + to undo — autonomy is about pacing, never about deciding such a fork for the user. +- **`PLAN.md` is the memory.** Point every skill and subagent at it instead of restating + context in the prompt. Once a unit is merged, shrink its row to one line and drop its + reports from what you carry forward. +- **No missing input is filled in.** A skill that returns no result, or a review with no + `VERDICT` line, is a gap: retry it once, then stop and tell the user. A result Smith + writes for a silent skill is indistinguishable from a real one. +- **Language.** Talk to the user in their `lingua` language if one is set; keep prompts to + skills and subagents in English — they are read by a model, and they add up. +- **Never tag, release or push** unless the user asks in this conversation. + +## 1. Plan + +Run `wisdom:plan` on the idea. Then run `wisdom:challenge` on the resulting plan: + +- `GO` → note its top items as risks in `PLAN.md`. +- `PAUSE` → revise the named items, then challenge again once. +- `RECONSIDER` → bring the finding to the user before anything else. + +**Checkpoint 1:** show the goal, the units and the open risks. Wait for approval. + +## 2. Design + +Only when the plan adds a public interface (an exported API, a route, a CLI flag, a schema, +a file format) or a dependency: run `wisdom:design` for it, and `wisdom:spec` when the +design is large enough that the builder would otherwise have to guess. A unit that changes a +visual interface gets `frontend-design:frontend-design` if it is installed — say so when it +is not. Behind an unchanged interface, skip this step. + +## 3. Build + +Create the branch first: `git checkout -b feat/<three-word-slug>`. + +Order the units into batches by `Depends on`: a batch holds every unit whose dependencies +are already merged. For each batch: + +1. **Code.** One subagent per unit, via the `Agent` tool with `isolation: "worktree"` when + the batch has more than one unit. Its prompt: the unit's row number, "read `PLAN.md`", + and "run `wisdom:code`". Tightly coupled units run one at a time, no worktree. +2. **Review.** Run `wisdom:review` on each unit's diff, passing the unit's `Acceptance` + and the test result from the code report, so the suite is not run twice. +3. **Route the verdict:** + + | Verdict | Next | + | ------- | ----------------------------------------------------------------- | + | `PASS` | ready to merge | + | `WARN` | fix if cheap; otherwise accept and note it in `PLAN.md` | + | `FAIL` | back to `wisdom:code` with the findings, then review again | + | no line | re-run the review once; still none → stop, the unit is unreviewed | + + A finding that says the design is wrong goes to `wisdom:design`, not to `code`. After two + failed fix rounds on the same unit, stop and bring it to the user. + +4. **Merge** each passing worktree branch into the feature branch, one at a time; resolve a + conflict with a `wisdom:code` subagent, then review the result again. +5. **Commit** each unit with `wisdom:commit`, and mark it `done` in `PLAN.md`. + +## 4. Check + +Run only the checks the change calls for, in parallel: + +- `wisdom:docs` — the change is user-visible. +- `wisdom:secure` on the branch diff — it touches auth, input handling, secrets or crypto. +- `wisdom:audit` — a manifest or lockfile changed. +- `wisdom:ops` — it changes how a service runs or deploys. + +A `FAIL`, `FINDINGS` or `BLOCK` goes back through step 3 like a review failure. `INCOMPLETE` +or `CONCERN` is reported at the checkpoint, not silently accepted. + +## 5. Merge + +**Checkpoint 2:** show `git log --oneline main..HEAD`, the verdict of every unit and check, +and anything accepted with a warning. Wait for approval, then: + +```bash +git checkout main +git merge --no-ff feat/<slug> # message: what the branch delivers; Closes: <issue> if any +git branch -d feat/<slug> +rm PLAN.md +``` + +A merge conflict goes to a `wisdom:code` subagent, then `wisdom:review`. + +## 6. Release + +Only when the user asks: run `wisdom:release`. + +## Report + +End with at most five lines: what merged, what was deferred, and one thing the next run +should do differently — only if there is one. diff --git a/plugins/wisdom/skills/spec/SKILL.md b/plugins/wisdom/skills/spec/SKILL.md new file mode 100644 index 0000000..bf9a563 --- /dev/null +++ b/plugins/wisdom/skills/spec/SKILL.md @@ -0,0 +1,61 @@ +--- +name: spec +description: Writes a technical specification — requirements, interfaces, data model — for a design already decided. Use when a design must be recorded before it is built. +license: MIT +metadata: + shortcut: "write spec" +--- + +# Spec + +Write down a decided design so someone else can build it. Record — do not re-decide. An +open design question goes back to `wisdom:design`. + +## Steps + +1. **Collect the decision:** the prompt, `PLAN.md` Decisions, the output of `design`. Read + only the code the spec's interfaces touch. +2. **Ask** about any gap that would force the builder to guess — an unstated error case, a + missing field, an unclear limit. Do not fill it in yourself. +3. **Write** the spec in the shape below, to the path the user gives or + `docs/specs/<topic>.md`. Omit a section that does not apply rather than writing "N/A". + +## Shape + +```markdown +# <Topic> Specification + +## Goal + +One paragraph: the problem and who has it. + +## Non-goals + +What this deliberately does not do. + +## Requirements + +Numbered, each testable: "The API rejects a request without a token with 401." + +## Interfaces + +Signatures, routes, CLI flags or file formats — inputs, outputs, errors. + +## Data model + +Entities, fields, types, constraints. + +## Flow + +The main path step by step; a diagram when a picture is clearer (`wisdom:diagram`). + +## Open questions + +Anything still undecided, with who decides. +``` + +## Rules + +- Every requirement must be checkable by a test or a reviewer; rewrite vague ones. +- Use the project's own names for things. +- Keep it as short as the design allows — a spec is read before building, not admired. diff --git a/plugins/wisdom/skills/test/SKILL.md b/plugins/wisdom/skills/test/SKILL.md new file mode 100644 index 0000000..125e66c --- /dev/null +++ b/plugins/wisdom/skills/test/SKILL.md @@ -0,0 +1,33 @@ +--- +name: test +description: Detects the project's test framework, runs the suite and reports what passed and failed. Use to run tests; it does not review or fix code. +license: MIT +metadata: + shortcut: "run tests" +--- + +# Test + +Run the test suite and report the result. Never edit code or tests. + +## Steps + +1. **Find the command**, first match wins: `PLAN.md` Context → `Makefile` `test` target → + the manifest (`package.json` scripts, `pyproject.toml`, `go.mod`, `Cargo.toml`, + `Gemfile`) → the framework's default runner. +2. **Run it** once, with any path or filter the caller gave. Do not retry a failing suite. +3. **Report** in the format below. For each failure give the test, the assertion or error in + one line, and `file:line`. Do not guess a fix. + +## Report + +```text +RESULT: PASS|FAIL|ERROR +Command: <exact command> +Counts: <passed> passed, <failed> failed, <skipped> skipped +Failures: +- <test> — <message> (<file:line>) +``` + +`ERROR` means the suite could not run (no framework found, command missing, build broke); +say which. No framework found is `ERROR`, never `PASS`. diff --git a/scripts/check-install-drift b/scripts/check-install-drift index 8e44fc1..5760731 100755 --- a/scripts/check-install-drift +++ b/scripts/check-install-drift @@ -63,7 +63,7 @@ VERSION_RE = re.compile(r'^\s*version:\s*["\']?([^"\'\s]+)', re.M) def version_of(path): - """The skill's metadata.version, or '?' when it cannot be read.""" + """A SKILL.md's version (a v3 skill carries none, so its plugin's), or '?'.""" try: text = open(path, encoding="utf-8").read() except OSError: @@ -74,7 +74,12 @@ def version_of(path): mk = json.load(open(os.path.join(root, ".claude-plugin", "marketplace.json"))) -shipped = {p["name"] for p in mk["plugins"]} +# v3 ships many skills per plugin, so the roster is the skill directories. +shipped = {} +for p in mk["plugins"]: + src = p["source"][2:] if p["source"].startswith("./") else p["source"] + for path in glob.glob(os.path.join(root, src, "skills", "*", "SKILL.md")): + shipped[os.path.basename(os.path.dirname(path))] = path # The tiers that outrank an installed plugin, nearest first. Both may be absent # -- on a machine that never installed the marketplace, or in CI -- and an @@ -95,7 +100,7 @@ for tier, base in TIERS: if name not in shipped: continue # somebody else's skill; not this marketplace's business found = True - ours = os.path.join(root, "plugins", name, "skills", name, "SKILL.md") + ours = shipped[name] bad( f"{name}: also served from the {tier} tier at {path}" f" (that copy says version {version_of(path)}," diff --git a/scripts/check-skill-spec b/scripts/check-skill-spec index cf7b4ea..f2a1779 100755 --- a/scripts/check-skill-spec +++ b/scripts/check-skill-spec @@ -34,7 +34,7 @@ import sys root = sys.argv[1] -GREEN, RED, YELLOW, RESET = "\033[32m", "\033[31m", "\033[33m", "\033[0m" +GREEN, RED, RESET = "\033[32m", "\033[31m", "\033[0m" # Quiet by default; WISDOM_VERBOSE=1 restores the per-item PASS lines. Same # reasoning as scripts/test and scripts/validate. WISDOM_VERBOSE = os.environ.get("WISDOM_VERBOSE", "") not in ("", "0") @@ -52,12 +52,6 @@ def bad(msg): errors += 1 -def warn(msg): - # Always printed, unlike the PASS lines: a warning nobody reads is not a - # warning. It does not affect the exit status. - print(f" {YELLOW}WARN{RESET} {msg}") - - # ---------------------------------------------------------------- the policy # https://agentskills.io/specification -- the whole of it. @@ -91,48 +85,16 @@ NAME_RE = re.compile(r"^[a-z0-9]+(-[a-z0-9]+)*$") NAME_MAX = 64 # The standard's hard ceiling. DESCRIPTION_MAX = 1024 -# This repo's own ceiling. A description is also catalogue copy -- it shows in -# `/plugin` listings and in both READMEs -- so one written purely for trigger -# accuracy becomes unreadable long before it reaches the standard's limit. -# -# 400 was never reachable: the longest here was 356 and is now 284. Lowered to -# 320 rather than to 300, which would have left 16 characters of headroom above -# a value that is not going anywhere -- briefing sits at 284 because a shorter -# version measurably lost two trigger queries to compactor. A threshold that -# fails the repo on the day it lands gets raised back rather than obeyed. -DESCRIPTION_PREFERRED_MAX = 320 +# This repo's own ceiling. A description is loaded in every session, whether +# or not its skill fires, so v3 holds it to one short sentence. +DESCRIPTION_PREFERRED_MAX = 160 COMPATIBILITY_MAX = 500 -# https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices -BODY_MAX_LINES = 500 -# Splitting a skill is worth doing as it approaches the ceiling, not once it is -# over: a body that must be read in full every run saves nothing by moving to a -# second file, so the useful moment to split is while there is still a choice -# about which sections to move. This warns; it does not fail. -# -# 350 never fired. The longest body in the marketplace, agent-smith, sat at 346 -# -- four lines under the line meant to draw attention to it, and read in full -# on every dispatch. The threshold was measuring nothing. -# -# What the warning asks for is a judgement, not a split. Two axes decide it. -# Form: a list or table survives a move into references/ because each row is -# looked up on its own, while prose carries the conditions and tie-breaks that -# join them and is shortened in place instead. Condition: loading is -# just-in-time, so an unconditional procedure is read anyway one fetch later, -# and only a procedure some runs skip is genuinely saved by moving. -# -# 250 was raised to 300 once agent-smith had been through that judgement. -# Everything there that qualified on both axes moved -- Phase 5, which Partner -# mode skips outright -- and the body came out at 292. The remaining distance -# to 250 was a rewrite of the phase text, and rewriting instructions a -# coordinator executes, to satisfy a number that was itself picked to make the -# warning fire rather than measured, trades a real risk for a false precision. -# The observed ecosystem median body is ~2,000 tokens with a range to ~8,000; -# agent-smith at ~3,600 is above median, not an outlier. -# -# This leaves eight lines of headroom, which is deliberate for a warning rather -# than a failure: the next substantial addition to the largest body here should -# prompt the judgement again. -BODY_WARN_LINES = 300 +# A body is read in full each time its skill runs. v3 budgets it well under +# the standard's 500: one purpose fits in 100 lines, and the coordinator, +# which names every other skill, gets 150. What only some runs need moves to +# references/, where it is read only when the body says so. +BODY_MAX_LINES = 100 +BODY_MAX_LINES_FOR = {"smith": 150} # A reference file past this length gets previewed rather than read whole, so # it needs a contents list for the preview to still show its full scope. TOC_REQUIRED_OVER = 100 @@ -259,8 +221,8 @@ def check_description(label, fields): elif len(desc) > DESCRIPTION_PREFERRED_MAX: bad( f"{label}: description is {len(desc)} characters, over this repo's" - f" {DESCRIPTION_PREFERRED_MAX} limit -- it is catalogue copy as well as" - " a trigger, and stops being readable well before the standard's 1024" + f" {DESCRIPTION_PREFERRED_MAX} limit -- it is" + " loaded in every session, so it stays one short sentence" ) if XML_TAG_RE.search(desc): bad(f"{label}: description contains an XML tag, which the standard forbids") @@ -324,18 +286,11 @@ def check_shapes(label, fields): def check_body(label, path, body): - if len(body) > BODY_MAX_LINES: + limit = BODY_MAX_LINES_FOR.get(os.path.basename(os.path.dirname(path)), BODY_MAX_LINES) + if len(body) > limit: bad( - f"{label}: body is {len(body)} lines, over the {BODY_MAX_LINES} budget" - " -- move detail into references/ and link to it" - ) - elif len(body) > BODY_WARN_LINES: - warn( - f"{label}: body is {len(body)} lines, over the {BODY_WARN_LINES} line" - f" where a body is worth re-reading (the {BODY_MAX_LINES} budget is" - " the ceiling, not the target) -- move what a run merely consults" - " into references/, and shorten what it executes rather than" - " moving that too" + f"{label}: body is {len(body)} lines, over its {limit}-line budget" + " -- shorten it, or move what only some runs need into references/" ) skill_dir = os.path.dirname(path) @@ -375,8 +330,14 @@ def check_body(label, path, body): print("==> Checking SKILL.md against the Agent Skills standard") paths = sorted(glob.glob(os.path.join(root, "plugins", "*", "skills", "*", "SKILL.md"))) +# An empty glob is a layout the check no longer understands -- unless the +# marketplace registers no plugin at all, which is a repo with nothing to ship. if not paths: - bad("no SKILL.md found under plugins/*/skills/*/") + import json + with open(os.path.join(root, ".claude-plugin", "marketplace.json")) as f: + registered = json.load(f).get("plugins", []) + if registered: + bad("no SKILL.md found under plugins/*/skills/*/") for path in paths: label = rel(path) diff --git a/scripts/check-version-sync b/scripts/check-version-sync index 1f86c2d..e6cd300 100755 --- a/scripts/check-version-sync +++ b/scripts/check-version-sync @@ -1,8 +1,7 @@ #!/usr/bin/env bash # Version integrity checks for the marketplace: # 1. Every marketplace.json plugin version matches its plugin.json version. -# 2. Every plugin.json version matches its SKILL.md metadata.version. -# 3. The marketplace.json top-level version never lags the latest git tag +# 2. The marketplace.json top-level version never lags the latest git tag # (equal = released, ahead = next release in prep, behind = error). set -euo pipefail @@ -34,7 +33,6 @@ def bad(msg): errors += 1 -plugins = [] print("==> Checking marketplace.json <-> plugin.json version sync") for p in mk["plugins"]: @@ -46,55 +44,12 @@ for p in mk["plugins"]: bad(f"{name}: missing {os.path.relpath(pj_path, root)}") continue pj_ver = json.load(open(pj_path)).get("version", "") - plugins.append((name, src, pj_ver)) if mk_ver == pj_ver: ok(f"{name} {mk_ver}") else: bad(f"{name}: marketplace={mk_ver} != plugin.json={pj_ver}") -def skill_version(path): - """metadata.version from a SKILL.md YAML frontmatter, or (None, reason).""" - lines = open(path, encoding="utf-8").read().splitlines() - if not lines or lines[0].strip() != "---": - return None, "no YAML frontmatter" - # `.strip()`, matching scripts/validate's frontmatter(): an exact-match - # `lines.index("---", 1)` gave a leading-space ' ---' the opposite verdict - # from the other script reading the same file. - end = next((i for i, line in enumerate(lines[1:], start=1) if line.strip() == "---"), None) - if end is None: - return None, "unterminated YAML frontmatter" - in_metadata = False - for line in lines[1:end]: - if not line.strip(): - continue - if not in_metadata: - in_metadata = line.rstrip() == "metadata:" - continue - if line[0] not in " \t": - break # dedent: the metadata block ended - m = re.match(r"\s+version:\s*(\S+)", line) - if m: - return m.group(1).strip("\"'"), None - return None, "no metadata.version in YAML frontmatter" - - -print("==> Checking plugin.json <-> SKILL.md metadata.version sync") -for name, src, pj_ver in plugins: - sk_path = os.path.join(root, src, "skills", name, "SKILL.md") - rel = os.path.relpath(sk_path, root) - if not os.path.isfile(sk_path): - bad(f"{name}: missing {rel}") - continue - sk_ver, reason = skill_version(sk_path) - if sk_ver is None: - bad(f"{name}: {rel}: {reason}") - elif sk_ver == pj_ver: - ok(f"{name} {sk_ver}") - else: - bad(f"{name}: plugin.json={pj_ver} != {rel} metadata.version={sk_ver}") - - def semver(v): """Leading numeric components of a version/tag, e.g. 'v1.3.1' -> (1, 3, 1).""" out = [] diff --git a/scripts/validate b/scripts/validate index cd7a707..f7da675 100755 --- a/scripts/validate +++ b/scripts/validate @@ -1,24 +1,19 @@ #!/usr/bin/env bash # Semantic checks for the marketplace: -# 1. Cross-skill references (`<plugin>:<skill>`) resolve to a real skill of a -# marketplace plugin, or to a known external plugin. -# 2. Every SKILL.md has a closed YAML frontmatter block, and its 'model:' -# value (when present) is a known tier, 'inherit', or a full model ID. -# 3. Every plugin skill declares at least one magic (trigger) word in -# 'metadata.shortcut', its '## Shortcut' section spells each one out for -# human readers, and no word is claimed by two different plugins. -# 4. Every plugin README has the required sections, and its magic-word -# section documents exactly the trigger words the skill declares. -# 5. The top-level README lists every plugin the marketplace registers. -# 6. Each plugin's description reads the same in marketplace.json, its -# plugin.json and its SKILL.md frontmatter. -# 7. Every plugin carries evals/trigger-queries.json, labelled on both sides -# and split both ways. -# 8. A skill that emits a verdict block declares it in 'metadata.verdict', -# and every verdict another skill routes on is one some skill emits. +# 1. Each plugin's description reads the same in marketplace.json and its +# plugin.json, and the top-level README names every plugin in prose. +# 2. A skill's magic words ('metadata.shortcut', comma-separated) are unique +# across every skill the marketplace ships. +# 3. Both top-level READMEs list exactly the shipped skills in their +# '## Skills' tables, each with exactly the magic words it declares, and +# list no skill that is not shipped. +# 4. A '<plugin>:<skill>' reference to a plugin this marketplace ships +# resolves to one of its skills. +# 5. Code fences in skills and READMEs are balanced. # -# An optional first argument overrides the repo root, so the fixture -# harness can point the validator at a mutated copy of the repo. +# An optional first argument overrides the repo root, so the fixture harness +# can point the validator at a mutated copy of the repo. Quiet by default; +# WISDOM_VERBOSE=1 restores the per-item PASS lines. set -euo pipefail if [ $# -ge 1 ]; then @@ -37,11 +32,15 @@ import sys root = sys.argv[1] GREEN, RED, RESET = "\033[32m", "\033[31m", "\033[0m" -# Quiet by default; WISDOM_VERBOSE=1 restores the per-item PASS lines. See the same -# comment in scripts/test for why an environment variable and not a flag. WISDOM_VERBOSE = os.environ.get("WISDOM_VERBOSE", "") not in ("", "0") errors = 0 +READMES = ("README.md", "README.zh-TW.md") + +FENCE_RE = re.compile(r"^\s*(```|~~~)") +TICK_RE = re.compile(r"`([^`]+)`") +REF_RE = re.compile(r"`([a-z0-9-]+):([a-z0-9-]+)`") + def ok(msg): if WISDOM_VERBOSE: @@ -54,660 +53,120 @@ def bad(msg): errors += 1 -# Plugins shipped outside this marketplace (installed from elsewhere) that -# skills here may legitimately reference. Only the plugin half is checked for -# these: their skill directories do not exist in this repo. -EXTERNAL_PLUGINS = {"frontend-design"} - -# 'inherit' is documented by Claude Code as a value of 'model:', meaning "keep -# the active model". Omitting the field does the same thing, so rejecting it was -# never load-bearing -- but it rejected something the platform accepts. -MODEL_TIERS = {"fable", "opus", "sonnet", "haiku", "inherit"} -MODEL_ID_RE = re.compile(r"^claude-[a-z0-9.-]+$") -# A skill reference is a backtick span whose ENTIRE content is <plugin>:<skill>; -# substrings inside longer spans (shell commands, ini sections) must not match. -REF_RE = re.compile(r"`([a-z0-9-]+:[a-z0-9-]+)`") -BACKTICK_RE = re.compile(r"`([^`]+)`") -# A markdown table row: a '|' indented at most three spaces. At four the line -# is an indented code block, which fence_marker() rightly refuses to treat as a -# fence — so its content reaches prose_lines() and would otherwise count as -# real text. Requiring the row keeps such a block out of the roster. -TABLE_ROW_RE = re.compile(r"^ {0,3}\|") - -SHORTCUT_HEADING = "## Shortcut" -# Every plugin skill must declare its magic words. The shortcut plugin is the -# dispatcher rather than a dispatch target: nothing dispatches TO it, so it has -# no magic words of its own and needs no '## Shortcut' section. Its README -# documents how OTHER skills register words, and the `/shortcut` command that -# lists them — not trigger words of its own. -SHORTCUT_EXEMPT = {"shortcut"} -MAGIC_HEADING_RE = re.compile(r"magic word", re.IGNORECASE) -# A README may spell a trigger out with placeholders — `respond in <lang>` -# documents the declared `respond in`. EVERY `<...>` is stripped, wherever in -# the span it sits, and what is left must equal a declared word exactly — that -# exactness is what stops `lingua off` passing as `lingua`. Stripping mid-span -# is safe because the opposite direction independently requires the span to -# contain the declared word literally, so `compact <the> it` is still rejected. -PLACEHOLDER_RE = re.compile(r"\s*<[^>]*>") -# Where a skill declares its trigger words. Before v2.0.0 this was the prose of -# the '## Shortcut' section, which meant a collision check could not afford to -# miss a declaration and so read EVERY backtick span there as one — forcing an -# authoring rule that reserved backticks in that section. The declaration now -# lives in frontmatter, where it is unambiguous, and the section is checked for -# agreeing with it rather than parsed as the source of truth. -SHORTCUT_KEY = "shortcut" - -mk = json.load(open(os.path.join(root, ".claude-plugin", "marketplace.json"))) -plugin_names = {p["name"] for p in mk["plugins"]} -known_plugins = plugin_names | EXTERNAL_PLUGINS - -plugin_dirs = sorted(d for d in glob.glob(os.path.join(root, "plugins", "*")) if os.path.isdir(d)) -# Every README path this file reads, derived ONCE. The fence check used to -# build its own list from plugin_dirs alone, so the top-level README was never -# checked for balanced fences — an unterminated one there truncated the roster -# check below in silence, and the validator still exited 0. -plugin_readmes = [os.path.join(d, "README.md") for d in plugin_dirs] -top_readme = os.path.join(root, "README.md") -readme_files = plugin_readmes + [top_readme] -skill_files = sorted(glob.glob(os.path.join(root, "plugins", "*", "skills", "*", "SKILL.md"))) - - -def read_lines(path): - with open(path) as handle: - return handle.read().splitlines() - - -# The two line classifiers every section-bounding check shares. Getting -# either wrong moves a section boundary, and a section that ends too early -# drops declarations silently — the failure mode this file keeps hitting. -FENCE_RE = re.compile(r"^ {0,3}(```|~~~)") -HEADING_RE = re.compile(r"^(#{1,6})( |$)") - - -def readme_lead_quote(lines): - """The description blockquote a plugin README opens with: H1, blank, quote. - - Strict on position on purpose. This is the description's fourth copy, and it - is only comparable if it always sits in the same place -- a loose search for - the first blockquote finds whichever paragraph a README happens to quote. - Returns the unwrapped text, or None when that shape does not hold. - """ - if len(lines) < 3 or not lines[0].startswith("# "): - return None - if lines[1].strip() or not lines[2].startswith("> "): - return None - quoted = [] - for line in lines[2:]: - if not line.startswith("> "): - break - quoted.append(line[2:].strip()) - return " ".join(quoted) - - -def fence_marker(line): - """The code-fence marker `line` opens or closes with, or None. - - CommonMark allows up to three spaces of indent; at four the line is an - indented code block, not a fence, and must not toggle the fence state. - """ - match = FENCE_RE.match(line) - return match.group(1) if match else None - - -def heading_level(line): - """ATX heading level of `line`, or 0 when it is ordinary text. - - CommonMark needs one to six '#' followed by a space or the line end, so - '#1 rule of ...', '#!/usr/bin/env note' and '####### deep note' are - paragraphs. Treating them as headings would end a section early. - """ - match = HEADING_RE.match(line) - return len(match.group(1)) if match else 0 - - -def classify(lines): - """One (line, kind, level) triple per line — the file's ONLY fence walk. - - kind is 'fence' for a marker line, 'fenced' for a line a fence hides, and - 'prose' for everything else. A fence closes only on the marker that opened - it, so a ``` inside a ~~~ block does not end it early, and every 'fence' - line is therefore exactly one toggle. - - Marker lines are their own kind rather than part of 'fenced' on purpose: - BACKTICK_RE reads ```text as the span `text - `, which would misfire the - check that rejects a backtick span hidden in a fence. - - level is the ATX heading level and is 0 for everything that is not a prose - heading, so a '## ...' inside a fence bounds no section. - - Every section-bounding check reads this one function. Two of them used to - keep private fence toggles that had to agree forever, which is where this - file's recurring bug class — a boundary that moves in one place only — - came from. - """ - triples, fence = [], None - for line in lines: - marker = fence_marker(line) - if marker and fence in (None, marker): - fence = marker if fence is None else None - triples.append((line, "fence", 0)) - elif fence is not None: - triples.append((line, "fenced", 0)) - else: - triples.append((line, "prose", heading_level(line))) - return triples - - -def prose_lines(lines): - return [line for line, kind, _ in classify(lines) if kind == "prose"] - - -def unterminated_fence(lines): - """True when a fence is still open at EOF. - - prose_lines() silently drops everything after such a fence, which would - hide a trigger declaration from the collision check. - """ - return sum(1 for _, kind, _ in classify(lines) if kind == "fence") % 2 == 1 - - -def frontmatter(lines): - """Lines between the opening '---' pair, or None when there is no closed block.""" - if not lines or lines[0].strip() != "---": - return None - for i, line in enumerate(lines[1:], start=1): - if line.strip() == "---": - return lines[1:i] - return None - - -def frontmatter_field(front, key): - """Value of a top-level `key:` in a frontmatter block, or None when absent.""" - prefix = key + ":" - for line in front: - if line.startswith(prefix): - return line[len(prefix):].strip().strip("\"'") - return None - - -def frontmatter_metadata(front, key): - """Value of `key:` inside the frontmatter's `metadata:` mapping, or None. - - Only two levels deep and only in this repo's shape, which is all the - frontmatter here has ever been. A key outside a `metadata:` block is not - found, so a misplaced `shortcut:` fails as an absent one rather than - quietly working. - """ - inside, prefix = False, " " + key + ":" - for line in front: - if not line.startswith(" "): - inside = line.startswith("metadata:") - continue - if inside and line.startswith(prefix): - return line[len(prefix):].strip().strip("\"'") - return None - - -def declared_words(value): - """Split a `metadata.shortcut` string into its words, in declaration order.""" - seen, out = set(), [] - for word in value.split(","): - word = " ".join(word.split()) - if word and word not in seen: - seen.add(word) - out.append(word) - return out - - -def section_lines(lines, wanted): - """RAW body lines of EVERY heading `wanted` accepts, or None when there is none. - - A section ends only at a heading of the SAME OR HIGHER level, so a nested - '### Additional Triggers' stays part of its '## Shortcut' parent. Ending at - a heading of ANY level dropped everything below the first subheading and - said nothing about it — the silent-truncation failure this file exists to - prevent. A non-matching deeper heading is kept in the body for the same - reason: a word declared in a subheading is still a declaration. - - Headings inside fenced code blocks bound nothing, but the fences themselves - are kept, so a caller can still see — and reject — what they hide. A - repeated heading resumes collection rather than being ignored. - """ - body, active, found, level = [], False, False, 0 - for line, _, line_level in classify(lines): - # Only a prose heading carries a level, so a fence marker and anything - # it hides fall straight through and can never end a section. - if line_level: - if wanted(line.strip()): - active, found, level = True, True, line_level - continue - if active and line_level <= level: - active = False - continue - if active: - body.append(line) - return body if found else None +def rel(path): + return os.path.relpath(path, root) -def section_body(lines, wanted): - """Prose body lines of a section — its fenced code blocks stripped.""" - raw = section_lines(lines, wanted) - return None if raw is None else prose_lines(raw) +def read(path): + with open(path, encoding="utf-8") as handle: + return handle.read() -def shortcut_section(lines): - return section_lines(lines, lambda heading: heading == SHORTCUT_HEADING) +def unfenced(text): + """Lines outside code fences, or None when a fence is left open.""" + out, inside = [], False + for line in text.splitlines(): + if FENCE_RE.match(line): + inside = not inside + elif not inside: + out.append(line) + return None if inside else out -def backtick_spans(lines): - """Backtick spans in `lines`, with one wrapped across a line break rejoined. +def shortcut_of(path): + """The comma-separated metadata.shortcut words of a SKILL.md.""" + text = read(path) + head = text.split("\n---", 1)[0] if text.startswith("---") else "" + m = re.search(r"^\s+shortcut:\s*[\"']?([^\"'\n]*)", head, re.M) + return [w.strip() for w in m.group(1).split(",") if w.strip()] if m else [] - `compact\nit` is `compact it` once markdown renders it, so it must be - collected as that word rather than missed for sitting on two lines. - """ - text = " ".join(line.strip() for line in lines) - return [" ".join(span.split()) for span in BACKTICK_RE.findall(text)] +mk = json.load(open(os.path.join(root, ".claude-plugin", "marketplace.json"))) -print("==> Checking cross-skill references") -for path in skill_files: - rel = os.path.relpath(path, root) - prose = "\n".join(prose_lines(read_lines(path))) - refs = REF_RE.findall(prose) - if not refs: - continue - problems = [] - for ref in refs: - plugin, skill = ref.split(":") - if plugin not in known_plugins: - problems.append(f"unresolved reference `{ref}`: no plugin named '{plugin}'") - elif plugin in plugin_names and not os.path.isfile( - os.path.join(root, "plugins", plugin, "skills", skill, "SKILL.md") - ): - problems.append(f"unresolved reference `{ref}`: plugin '{plugin}' has no skill '{skill}'") - for problem in problems: - bad(f"{rel}: {problem}") - if not problems: - ok(f"{rel}: {len(refs)} reference(s) resolve") - -print("==> Checking code fences") -fenced_files = skill_files + [p for p in readme_files if os.path.isfile(p)] -before = errors -for path in fenced_files: - if unterminated_fence(read_lines(path)): - bad(f"{os.path.relpath(path, root)}: unterminated code fence hides everything after it") -if errors == before: - ok(f"{len(fenced_files)} file(s) have balanced code fences") - -print("==> Checking model declarations") -for path in skill_files: - rel = os.path.relpath(path, root) - front = frontmatter(read_lines(path)) - if front is None: - bad(f"{rel}: no closed YAML frontmatter block") - continue - model = frontmatter_field(front, "model") or "" - if not model: - ok(f"{rel}: no model (inherits session default)") - elif model in MODEL_TIERS or MODEL_ID_RE.match(model): - ok(f"{rel}: model {model}") - else: - bad(f"{rel}: invalid model '{model}'") - -print("==> Checking magic-word declarations and collisions") -# plugin -> the trigger words it declares. Three states, kept apart on purpose: -# a list of words, [] for a plugin that legitimately declares none, and -# UNCHECKED when a failure below stopped this check from reading its words at -# all. The README cross-check reads this dict, and reading "no entry" as -# "declares nothing" silently switched that cross-check off for exactly the -# plugin whose declaration had just failed here — the safety net disarming -# itself when its subject breaks. -UNCHECKED = object() -triggers = {} -before = errors -for path in skill_files: - rel = os.path.relpath(path, root) - plugin = os.path.relpath(path, os.path.join(root, "plugins")).split(os.sep)[0] - front = frontmatter(read_lines(path)) - raw = None if front is None else frontmatter_metadata(front, SHORTCUT_KEY) - words = [] if raw is None else declared_words(raw) - - if not words: - if plugin in SHORTCUT_EXEMPT: - triggers[plugin] = [] - else: - triggers[plugin] = UNCHECKED - bad( - f"{rel}: declares no trigger word in 'metadata.shortcut'" - " (a comma-separated string; a skill that never dispatches belongs" - " in SHORTCUT_EXEMPT in scripts/validate)" - ) - continue - triggers[plugin] = words - - # The section is documentation now, not the declaration, so this runs one - # way only: every declared word must appear there in backticks, and a - # backtick span that is not a trigger word is simply prose. That relaxation - # is the whole point of moving the declaration into frontmatter. - section = shortcut_section(read_lines(path)) - if section is None: - bad(f"{rel}: declares trigger words but has no '## Shortcut' section spelling them out") - continue - spans = backtick_spans(prose_lines(section)) - missing = [w for w in words if w not in spans] - if missing: - bad( - f"{rel}: '## Shortcut' does not spell out " - + ", ".join(f"`{w}`" for w in missing) - + " (declared in metadata.shortcut; a reader of the section would never see it)" - ) - -# The collision check is `triggers` read the other way round, so it is derived -# from it rather than accumulated beside it. Sorting the claimants also keeps -# the message independent of the order the skill files happened to be walked. -claims = {} # trigger word -> the plugins claiming it -for plugin, words in triggers.items(): - if words is UNCHECKED: - continue - for word in words: - claims.setdefault(word, set()).add(plugin) -for word in sorted(claims): - owners = sorted(claims[word]) - if len(owners) > 1: - bad(f"magic word `{word}` claimed by both {' and '.join(owners)}") -if errors == before: - declaring = [p for p, words in triggers.items() if words] - ok(f"{len(claims)} trigger word(s) across {len(declaring)} plugin(s), no collisions") - -print("==> Checking README sections") -for directory, readme in zip(plugin_dirs, plugin_readmes): - name = os.path.basename(directory) - rel = os.path.relpath(readme, root) - if not os.path.isfile(readme): - bad(f"{rel}: missing") - continue - headings = [l for l in prose_lines(read_lines(readme)) if heading_level(l)] - problems = [] - if not any(heading_level(h) == 1 for h in headings): - problems.append("no H1 title") - for section in ("Installation", "License"): - if not any(h.strip() == f"## {section}" for h in headings): - problems.append(f"no '## {section}' section") - declared = triggers.get(name, []) - if declared is UNCHECKED: - problems.append( - "its SKILL.md trigger declaration could not be read (see the failure above)," - " so what this README must document is unknown and was NOT cross-checked" - ) - elif declared: - documented = section_body(read_lines(readme), MAGIC_HEADING_RE.search) - if documented is None: - problems.append("declares trigger words but has no 'Magic Word' heading") - else: - spans = backtick_spans(documented) - for word in declared: - if not any(word in span for span in spans): - problems.append( - f"magic word `{word}` is declared in SKILL.md but undocumented here" - " (under a Magic Words heading, backticks are reserved for trigger words)" - ) - for span in spans: - if PLACEHOLDER_RE.sub("", span).strip() not in declared: - problems.append( - f"documents `{span}`, which the skill does not declare" - " (under a Magic Words heading, backticks are reserved for trigger words)" - ) - for problem in problems: - bad(f"{rel}: {problem}") - if not problems: - ok(f"{rel}: required sections present") - -print("==> Checking plugin descriptions agree across their sources") +print("==> Checking plugin descriptions and the README roster") +readme_prose = "\n".join(unfenced(read(os.path.join(root, "README.md"))) or []) +skills = {} # name -> SKILL.md path for entry in mk["plugins"]: name = entry["name"] src = entry["source"][2:] if entry["source"].startswith("./") else entry["source"] - # The one sentence a plugin repeats verbatim in four places, so the one - # piece of prose that is mechanically comparable. Bodies are not: they say - # the same thing at different lengths on purpose. - # - # The fourth is the README blockquote, and it was unchecked while this - # comment said three. It is line-wrapped, so an edit that rewrites the - # other three by exact string match leaves it behind and every check still - # passes -- which is how nineteen of them went stale in one commit. - sources = {".claude-plugin/marketplace.json": entry.get("description")} - pj_path = os.path.join(root, src, ".claude-plugin", "plugin.json") - if os.path.isfile(pj_path): - sources[os.path.relpath(pj_path, root)] = json.load(open(pj_path)).get("description") - sk_path = os.path.join(root, src, "skills", name, "SKILL.md") - if os.path.isfile(sk_path): - front = frontmatter(read_lines(sk_path)) or [] - sources[os.path.relpath(sk_path, root)] = frontmatter_field(front, "description") - rd_path = os.path.join(root, src, "README.md") - if os.path.isfile(rd_path): - rel_rd = os.path.relpath(rd_path, root) - quoted = readme_lead_quote(read_lines(rd_path)) - if quoted is None: - bad( - f"{rel_rd}: must open with its H1, a blank line, then the" - " description as a `> ` blockquote -- that position is what makes" - " the fourth copy comparable" - ) - else: - sources[rel_rd] = quoted - if len(set(sources.values())) == 1: - ok(f"{name}: description agrees across {len(sources)} source(s)") + pj = json.load(open(os.path.join(root, src, ".claude-plugin", "plugin.json"))) + if pj.get("description") == entry.get("description"): + ok(f"{name}: description agrees") else: - detail = "; ".join(f"{where} says {value!r}" for where, value in sorted(sources.items())) - bad(f"{name}: description differs between its sources ({detail})") - -print("==> Checking the top-level README lists every plugin") -if not os.path.isfile(top_readme): - bad("README.md: missing") -else: - # The roster is the one thing duplicated between marketplace.json and the - # top-level README, so it is the one thing mechanically comparable. The - # descriptions are prose and stay a matter of reading. - # - # Membership, not mere presence: a plugin counts as listed only when a - # ROSTER ROW names it — a table row, outside any code block, carrying the - # name as a whole backtick span. Searching the README text for the name - # instead let one passing mention stand in for a deleted row: strip every - # `tenth-man` row from the tables, leave the words - # `plugins/tenth-man/README.md` in a sentence, and the roster read as - # complete. - rows = [l for l in prose_lines(read_lines(top_readme)) if TABLE_ROW_RE.match(l)] - listed = {span for row in rows for span in backtick_spans([row])} - missing = [n for n in sorted(plugin_names) if n not in listed] - for name in missing: - bad(f"README.md: plugin '{name}' is registered in marketplace.json but not listed here") - if not missing: - ok(f"README.md lists all {len(plugin_names)} registered plugin(s)") - -# A verdict block is the one machine-facing thing these skills exchange: Ellis -# hands Smith a PASS/WARN/FAIL, Page hands it a READY/CONCERN/BLOCK. Until now -# the marker naming that block existed only in prose in both the skill that -# emits it and the skill that routes on it, so a rename on one side was a -# silent failure on the other -- the caller reads no verdict and proceeds as -# though there were no findings, which is the worst of the possible defaults. -# -# 'metadata.verdict' makes the emitting side declarable, and this check closes -# it from both ends: what is declared must be emitted, what is emitted must be -# declared, and what is routed on must exist somewhere. -VERDICT_KEY = "verdict" -# A marker alone on its own line inside a fenced block: the skill is showing -# the block's shape. The same token inside prose backticks is a mention -- the -# caller naming a verdict it acts on -- and mentions are checked separately, -# further down, against what the emitters declare. -VERDICT_MARKER_RE = re.compile(r"^__[A-Z][A-Z0-9_]*__$") -VERDICT_FIELD_RE = re.compile(r"^[A-Za-z][A-Za-z ]*:\s*\S") - -print("==> Checking verdict contracts") -declared_verdicts = {} -for path in skill_files: - shown = os.path.relpath(path, root) - lines = read_lines(path) - front = frontmatter(lines) or [] - declared = frontmatter_metadata(front, VERDICT_KEY) + bad(f"{name}: description differs between marketplace.json and plugin.json") + if re.search(rf"\b{re.escape(name)}\b", readme_prose): + ok(f"{name}: named in README.md") + else: + bad(f"{name}: registered in marketplace.json but never named in README.md prose") + for path in sorted(glob.glob(os.path.join(root, src, "skills", "*", "SKILL.md"))): + skill = os.path.basename(os.path.dirname(path)) + if skill in skills: + bad(f"{skill}: shipped by two plugins") + skills[skill] = path + +print("==> Checking magic words are unique") +owner = {} +for skill, path in skills.items(): + for word in shortcut_of(path): + if word in owner: + bad(f"magic word '{word}' is claimed by both {owner[word]} and {skill}") + else: + owner[word] = skill + ok(f"{skill}: '{word}'") - # Walk the body's fenced blocks, collecting markers that open one. - emitted, fence, block = [], None, [] +print("==> Checking the README skill tables") +for readme in READMES: + path = os.path.join(root, readme) + if not os.path.isfile(path): + bad(f"{readme} is missing") + continue + lines = unfenced(read(path)) + if lines is None: + bad(f"{readme}: unterminated code fence") + continue + listed, in_skills = {}, False for line in lines: - marker = fence_marker(line) - if fence is None: - if marker: - fence, block = marker, [] + if line.startswith("## "): + in_skills = line.strip() == "## Skills" + if not in_skills or not line.startswith("|"): continue - if marker == fence: - # Blank edges are formatting, not content: a blank first line must - # not turn a shown block into a missing one, or a whitespace edit - # reads as a renamed contract. - trimmed = block[:] - while trimmed and not trimmed[0].strip(): - trimmed.pop(0) - while trimmed and not trimmed[-1].strip(): - trimmed.pop() - if trimmed and VERDICT_MARKER_RE.match(trimmed[0].strip()): - emitted.append((trimmed[0].strip(), trimmed)) - fence = None - continue - block.append(line) - - problems = [] - if declared and not VERDICT_MARKER_RE.match(declared): - problems.append( - f"metadata.verdict is {declared!r}, which is not a __MARKER__ name" - ) - for marker, block in emitted: - if marker != declared: - problems.append( - f"emits a {marker} block but metadata.verdict is" - f" {declared or 'absent'}; a caller routing on it has nothing to read" - ) - continue - if block[-1].strip() != marker: - problems.append(f"the {marker} block does not close with {marker}") - if not any(VERDICT_FIELD_RE.match(l.strip()) for l in block[1:-1]): - problems.append( - f"the {marker} block carries no 'Field: value' line, so it" - " states a contract with no content" - ) - if declared and not emitted: - problems.append( - f"declares metadata.verdict {declared} but its body never shows" - f" the block, so nothing says what {declared} contains" - ) - # Recorded from the declaration alone. The routing half asks whether some - # skill claims this marker, which stays true while that skill's own block - # is being fixed -- otherwise one malformed block fails every caller too, - # and the real error is buried among its consequences. - if declared: - declared_verdicts[declared] = os.path.basename(os.path.dirname(path)) - for problem in problems: - bad(f"{shown}: {problem}") - if not problems and declared: - ok(f"{shown}: emits and declares {declared}") - -# The routing half. A skill that acts on someone else's verdict names it in -# prose; that name must belong to a skill that actually emits one. -for path in skill_files: - shown = os.path.relpath(path, root) - lines = read_lines(path) - own = frontmatter_metadata(frontmatter(lines) or [], VERDICT_KEY) - mentioned = set() - for line in prose_lines(lines): - for span in backtick_spans([line]): - if VERDICT_MARKER_RE.match(span): - mentioned.add(span) - for marker in sorted(mentioned - {own}): - if marker not in declared_verdicts: + cells = [c.strip() for c in line.strip().strip("|").split("|")] + m = re.fullmatch(r"`([a-z0-9-]+)`", cells[0]) + if m: + listed[m.group(1)] = TICK_RE.findall(cells[-1]) + for skill, path in skills.items(): + if skill not in listed: + bad(f"{readme}: skill '{skill}' is missing from the '## Skills' tables") + elif sorted(listed[skill]) != sorted(shortcut_of(path)): bad( - f"{shown}: routes on {marker}, which no skill in this" - " marketplace declares in metadata.verdict" + f"{readme}: '{skill}' lists magic words {listed[skill]}," + f" but its SKILL.md declares {shortcut_of(path)}" ) else: - ok(f"{shown}: routes on {marker}, emitted by {declared_verdicts[marker]}") - - -# Built by the magic-word census above: plugin -> the words it claims. -magic_words = {plugin: sorted(w) for plugin, w in triggers.items()} - -print("==> Checking trigger-eval coverage") -for directory in plugin_dirs: - name = os.path.basename(directory) - path = os.path.join(directory, "evals", "trigger-queries.json") - shown = os.path.relpath(path, root) - if not os.path.isfile(path): - bad( - f"{name}: no evals/trigger-queries.json." - " A description is the only part of a skill always in context, so it" - " is the part that decides whether the skill is ever reached;" - " an untested one is an untested router" - ) - continue - try: - doc = json.loads(open(path).read()) - except ValueError as exc: - bad(f"{shown}: not valid JSON ({exc})") - continue - problems = [] - if doc.get("skill") != name: - problems.append(f"names skill {doc.get('skill')!r}, but sits under plugins/{name}") - queries = doc.get("queries") - if not isinstance(queries, list) or not queries: - problems.append("has no 'queries' list") - queries = [] - texts = [q.get("query") for q in queries if isinstance(q, dict)] - if len(texts) != len(queries): - problems.append("has a query that is not an object") - elif len(set(texts)) != len(texts): - problems.append("repeats a query, which scores the same prompt twice") - labels = {q.get("should_trigger") for q in queries if isinstance(q, dict)} - if labels - {True, False}: - problems.append("has a query whose 'should_trigger' is not a boolean") - elif labels != {True, False}: - problems.append("labels every query the same way, so it cannot separate a hit from a miss") - splits = {q.get("split") for q in queries if isinstance(q, dict)} - if not {"train", "validation"} <= splits: - problems.append( - "does not split train/validation, so a description tuned on these" - " queries has nothing left to be judged against" - ) - # Not pinned to exactly half. The negatives are what the set is for -- a - # description that fires on everything passes a positives-only set -- but - # requiring a precise ratio would make this a formatting rule rather than a - # coverage one. - negatives = sum(1 for q in queries if isinstance(q, dict) and q.get("should_trigger") is False) - if queries and negatives * 3 < len(queries): - problems.append( - f"has {negatives} near-miss negative(s) among {len(queries)} queries;" - " a set that is nearly all positives cannot catch an over-eager description" - ) - # A negative that carries another plugin's magic word is the point of the - # set -- that is the near-miss. A POSITIVE that carries one is not a test - # at all: both skills are supposed to fire, so whichever wins, the run - # proves nothing about this description. - for query in queries: - if not isinstance(query, dict) or query.get("should_trigger") is not True: + ok(f"{readme}: {skill}") + for skill in listed: + if skill not in skills: + bad(f"{readme}: lists '{skill}', which no plugin ships") + +print("==> Checking skill references and code fences") +plugins = {e["name"] for e in mk["plugins"]} +for skill, path in skills.items(): + for doc in [path] + sorted(glob.glob(os.path.join(os.path.dirname(path), "references", "*.md"))): + lines = unfenced(read(doc)) + if lines is None: + bad(f"{rel(doc)}: unterminated code fence") continue - text = (query.get("query") or "").lower() - for owner, owned in sorted(magic_words.items()): - if owner == name: - continue - for word in owned: - if re.search(r"\b" + re.escape(word) + r"\b", text): - problems.append( - f"the positive {query['query']!r} contains {word!r}," - f" a magic word of {owner}, so both skills are meant to" - " fire and the run decides nothing" - ) - for problem in problems: - bad(f"{shown}: {problem}") - if not problems: - ok(f"{name}: {len(queries)} labelled trigger queries") - - + for plugin, target in REF_RE.findall("\n".join(lines)): + if plugin not in plugins: + continue # file:line, or another marketplace's plugin + if target in skills: + ok(f"{rel(doc)}: {plugin}:{target}") + else: + bad(f"{rel(doc)}: reference '{plugin}:{target}' resolves to no skill") + +print("") if errors: print(f"==> {errors} error(s) found") sys.exit(1) -print("==> All semantic checks passed") +print(f"==> All semantic checks passed ({len(skills)} skills)") PY diff --git a/scripts/validate-fixtures b/scripts/validate-fixtures index 108b2be..f09b9b5 100755 --- a/scripts/validate-fixtures +++ b/scripts/validate-fixtures @@ -1,771 +1,120 @@ #!/usr/bin/env bash -# Negative fixtures for scripts/validate: mutate a temp copy of the repo to -# break each semantic check in turn and assert the validator fails. A check -# that cannot fail proves nothing, so any un-failable check fails this harness. +# Negative fixtures for scripts/validate and scripts/check-skill-spec: break a +# temp copy of the repo one way at a time and assert the check fails with the +# message that names that break. A check that cannot fail proves nothing. # -# Every fixture asserts the SPECIFIC message the broken check emits — a -# validator that exits non-zero for an unrelated reason must not count as proof. -# -# Fixture bodies are literal markdown, so their backticks and $ are data, not -# shell syntax. That holds for every single-quoted string below. +# Fixture bodies are literal markdown, so their backticks are data. # shellcheck disable=SC2016 set -euo pipefail REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" -TMP_DIR="$(mktemp -d)" -# The fixtures assert on the validator's exact per-item lines, the magic-word -# census among them, and those lines are quiet by default. This harness is the -# one caller that wants every one of them, so it always runs it verbose. -export WISDOM_VERBOSE=1 -trap 'rm -rf "$TMP_DIR"' EXIT +# Every fixture mutates a shipped skill; with none shipped there is nothing to break. +if ! compgen -G "$REPO_ROOT/plugins/*/skills/*/SKILL.md" >/dev/null; then + echo "==> No skills to mutate -- skipping validator fixtures" + exit 0 +fi +TMP_DIR="$(mktemp -d)" +trap 'rm -rf "$TMP_DIR"' EXIT ERRORS=0 +SKILLS="plugins/wisdom/skills" +TARGET="$SKILLS/shortcut/SKILL.md" + pass() { printf " \033[32mPASS\033[0m %s\n" "$1"; } fail() { printf " \033[31mFAIL\033[0m %s\n" "$1" ERRORS=$((ERRORS + 1)) } -# Everything the validator reads, copied once. Fixtures mutate $TMP_DIR/repo -# and fresh_copy restores it from here; re-copying the whole subtree per -# fixture cost 1.9s of the harness's 4.6s runtime for no gain. -mkdir -p "$TMP_DIR/pristine" "$TMP_DIR/repo" -cp -R "$REPO_ROOT/.claude-plugin" "$REPO_ROOT/plugins" "$TMP_DIR/pristine/" -cp "$REPO_ROOT/README.md" "$TMP_DIR/pristine/" -cp -R "$TMP_DIR/pristine/." "$TMP_DIR/repo/" - -# Paths the current fixture has changed. mutate() and replace() record their -# own target; a fixture that writes to the copy directly records its own with -# dirty. Forgetting one would leak into every later fixture, which is what the -# check at the bottom of this file exists to catch. -DIRTY=() - -dirty() { DIRTY+=("$@"); } - -# Undo the current fixture, restoring only what it touched. A path absent from -# the pristine copy (plugins/ghost) is simply removed. fresh_copy() { - local path - for path in ${DIRTY[@]+"${DIRTY[@]}"}; do - rm -rf "${TMP_DIR:?}/repo/$path" - if [ -e "$TMP_DIR/pristine/$path" ]; then - cp -R "$TMP_DIR/pristine/$path" "$TMP_DIR/repo/$path" - fi - done - DIRTY=() -} - -# expect_pass <label> — the empty substring matches any non-empty file, and -# the validator always prints something. -expect_pass() { expect_pass_with "" "$1"; } - -# expect_pass_with <expected-message-substring> <label> -expect_pass_with() { - if ! bash "$REPO_ROOT/scripts/validate" "$TMP_DIR/repo" >"$TMP_DIR/out" 2>&1; then - fail "$2: validator failed on a copy it should accept" - sed 's/^/ /' "$TMP_DIR/out" - elif grep -qF "$1" "$TMP_DIR/out"; then - pass "$2" - else - fail "$2: validator passed, but without \"$1\"" - sed 's/^/ /' "$TMP_DIR/out" - fi + rm -rf "$TMP_DIR/repo" + mkdir -p "$TMP_DIR/repo" + cp -R "$REPO_ROOT/.claude-plugin" "$REPO_ROOT/plugins" "$REPO_ROOT/README.md" \ + "$REPO_ROOT/README.zh-TW.md" "$TMP_DIR/repo/" } -# expect_fail <expected-message-substring> <label> -expect_fail() { - if bash "$REPO_ROOT/scripts/validate" "$TMP_DIR/repo" >"$TMP_DIR/out" 2>&1; then - fail "$2: validator passed but should have failed" - elif grep -qF "$1" "$TMP_DIR/out"; then - pass "$2" - else - fail "$2: validator failed, but not with \"$1\"" - sed 's/^/ /' "$TMP_DIR/out" - fi -} - -# The same two expectations against scripts/check-skill-spec. It reads only -# plugins/*/skills/*/SKILL.md, so it reuses the copy the fixtures above mutate. - -# expect_spec_fail <expected-message-substring> <label> -expect_spec_fail() { - if bash "$REPO_ROOT/scripts/check-skill-spec" "$TMP_DIR/repo" >"$TMP_DIR/out" 2>&1; then - fail "$2: spec check passed but should have failed" - elif grep -qF "$1" "$TMP_DIR/out"; then - pass "$2" - else - fail "$2: spec check failed, but not with \"$1\"" - sed 's/^/ /' "$TMP_DIR/out" - fi +# ghost <name> [shortcut] -- a minimal extra skill in the copy. +ghost() { + mkdir -p "$TMP_DIR/repo/$SKILLS/$1" + { + printf -- '---\nname: %s\ndescription: Does one thing for the fixtures.\n' "$1" + [ -n "${2:-}" ] && printf 'metadata:\n shortcut: "%s"\n' "$2" + printf -- '---\n\n# Ghost\n' + } >"$TMP_DIR/repo/$SKILLS/$1/SKILL.md" } -# expect_spec_warn <expected-message-substring> <label> — the check must still -# pass, but must have said something on the way. -expect_spec_warn() { - if ! bash "$REPO_ROOT/scripts/check-skill-spec" "$TMP_DIR/repo" >"$TMP_DIR/out" 2>&1; then - fail "$2: spec check failed on a copy it should only warn about" - sed 's/^/ /' "$TMP_DIR/out" - elif grep -qF "$1" "$TMP_DIR/out"; then - pass "$2" +# expect <script> <pass|substring> <label> +expect() { + local out="$TMP_DIR/out" + if bash "$REPO_ROOT/scripts/$1" "$TMP_DIR/repo" >"$out" 2>&1; then + if [ "$2" = pass ]; then pass "$3"; else fail "$3: $1 passed but should have failed"; fi + elif [ "$2" = pass ]; then + fail "$3: $1 failed on a copy it should accept" + sed 's/^/ /' "$out" + elif grep -qF "$2" "$out"; then + pass "$3" else - fail "$2: spec check passed, but without warning \"$1\"" - sed 's/^/ /' "$TMP_DIR/out" + fail "$3: $1 failed, but without \"$2\"" + sed 's/^/ /' "$out" fi + fresh_copy } -expect_spec_pass() { - if bash "$REPO_ROOT/scripts/check-skill-spec" "$TMP_DIR/repo" >"$TMP_DIR/out" 2>&1; then - pass "$1" - else - fail "$1: spec check failed on a copy it should accept" - sed 's/^/ /' "$TMP_DIR/out" - fi -} - -# In-place sed that works with both BSD and GNU sed. -mutate() { - local expr="$1" file="$2" - dirty "$file" - sed -i.bak "$expr" "$TMP_DIR/repo/$file" - rm "$TMP_DIR/repo/$file.bak" -} - -# Replace an exact multi-line block; sed cannot do this portably. -replace() { - dirty "$1" - python3 - "$TMP_DIR/repo/$1" "$2" "$3" <<'PY' -import sys - -path, old, new = sys.argv[1], sys.argv[2], sys.argv[3] -with open(path) as handle: - text = handle.read() -assert old in text, f"fixture target not found in {path}: {old!r}" -with open(path, "w") as handle: - handle.write(text.replace(old, new)) -PY -} - -# The sentence tenth-man declares its trigger words with. Most fixtures work by -# swapping it for something else, so it is written out once, here. -TRIGGER_SENTENCE='This skill is triggered when the user'"'"'s prompt contains `challenge this` or `tenth man`.' - -# retrigger <new-body> — swap that sentence in tenth-man's SKILL.md. -retrigger() { - replace plugins/tenth-man/skills/tenth-man/SKILL.md "$TRIGGER_SENTENCE" "$1" -} - -echo "==> Baseline: unmutated copy" -fresh_copy -expect_pass "clean copy passes" -# The magic-word census, read off the clean copy rather than hardcoded. The -# fixtures below assert it to prove a section was not truncated; pinning the -# numbers instead made adding one plugin break three fixtures that were never -# about the count — and the hook that runs this file is gated on ^scripts/, so -# a content-only commit would not even surface the breakage. -CENSUS="$(grep -o '[0-9]* trigger word(s) across [0-9]* plugin(s)' "$TMP_DIR/out" || true)" -if [ -n "$CENSUS" ]; then - pass "census reported: $CENSUS" -else - fail "baseline: the validator printed no magic-word census at all" -fi - -echo "==> Fixture: unresolvable cross-skill reference" -fresh_copy -dirty plugins/compactor/skills/compactor/SKILL.md -echo 'See `nope:nope` for details.' >>"$TMP_DIR/repo/plugins/compactor/skills/compactor/SKILL.md" -expect_fail "no plugin named 'nope'" "unresolved \`nope:nope\` reference is caught" - -echo "==> Fixture: reference to a skill the plugin does not have" -fresh_copy -dirty plugins/compactor/skills/compactor/SKILL.md -echo 'See `agent-hale:agent-typo` for details.' >>"$TMP_DIR/repo/plugins/compactor/skills/compactor/SKILL.md" -expect_fail "has no skill 'agent-typo'" "\`agent-hale:agent-typo\` (real plugin, unknown skill) is caught" - -echo "==> Fixture: <plugin>:<skill>-shaped token inside a fenced code block" -fresh_copy -dirty plugins/compactor/skills/compactor/SKILL.md -printf '\n```sh\ndocker run `docker-run:latest`\n```\n' \ - >>"$TMP_DIR/repo/plugins/compactor/skills/compactor/SKILL.md" -expect_pass "fenced \`docker-run:latest\` is not mistaken for a skill reference" - -echo "==> Fixture: invalid model value" -fresh_copy -mutate 's/^model: haiku$/model: gpt-4/' plugins/lingua/skills/lingua/SKILL.md -expect_fail "invalid model 'gpt-4'" "invalid 'model: gpt-4' is caught" - -echo "==> Fixture: SKILL.md with no YAML frontmatter" -fresh_copy -mutate '1,/^---$/d;1,/^---$/d' plugins/compactor/skills/compactor/SKILL.md -expect_fail "no closed YAML frontmatter block" "missing frontmatter is caught" - -# --------------------------------------------------------------------------- -# Magic words. The declaration lives in `metadata.shortcut`; the '## Shortcut' -# section spells it out for human readers and is checked one way only, which is -# what lets a backtick there mean nothing in particular. -# --------------------------------------------------------------------------- - -# A literal single quote, for splicing into the single-quoted fixture bodies -# below. Same trick as TRIGGER_SENTENCE above, named so the bodies stay legible. -Q="'" - -# spell_out <plugin> <old-word> <new-word> — keep the '## Shortcut' section in -# step with a changed declaration, so a fixture about one thing does not also -# trip the spell-out check. -spell_out() { - mutate "s/\`$2\`/\`$3\`/" "plugins/$1/skills/$1/SKILL.md" -} - -# declare_words <plugin> <comma-separated> — rewrite metadata.shortcut. -declare_words() { - mutate "s/^ shortcut: .*/ shortcut: \"$2\"/" "plugins/$1/skills/$1/SKILL.md" -} - -echo "==> Fixture: magic word claimed by two plugins" -fresh_copy -declare_words tenth-man "compact it, tenth man" -spell_out tenth-man "challenge this" "compact it" -expect_fail "claimed by both compactor and tenth-man" \ - "duplicated magic word \`compact it\` is caught" - -echo "==> Fixture: a plugin skill declaring no magic word" -fresh_copy -mutate '/^ shortcut: /d' plugins/compactor/skills/compactor/SKILL.md -expect_fail "declares no trigger word in 'metadata.shortcut'" \ - "an absent declaration is a failure, not a silent pass" - -echo "==> Fixture: an empty declaration" -fresh_copy -declare_words compactor "" -expect_fail "declares no trigger word in 'metadata.shortcut'" \ - "an empty declaration is caught" - -echo "==> Fixture: a declaration of nothing but separators" -fresh_copy -declare_words compactor " , , " -expect_fail "declares no trigger word in 'metadata.shortcut'" \ - "a declaration that splits into no words is caught" - -echo "==> Fixture: shortcut declared outside the metadata block" -fresh_copy -mutate '/^ shortcut: /d' plugins/compactor/skills/compactor/SKILL.md -mutate 's/^license: MIT$/license: MIT\nshortcut: "compact it"/' plugins/compactor/skills/compactor/SKILL.md -expect_fail "declares no trigger word in 'metadata.shortcut'" \ - "a top-level shortcut key does not quietly stand in for the metadata one" - -echo "==> Fixture: a declared word the Shortcut section never spells out" -fresh_copy -declare_words compactor "compact it, squash it" -expect_fail "does not spell out \`squash it\`" \ - "a word only frontmatter knows about is caught, since no reader would see it" - -echo "==> Fixture: a declaring skill with no '## Shortcut' section at all" -fresh_copy -mutate 's/^## Shortcut$/## Triggers/' plugins/compactor/skills/compactor/SKILL.md -expect_fail "has no '## Shortcut' section spelling them out" \ - "renaming the heading is caught, not silently ignored" - -echo "==> Fixture: the spelled-out word hidden in a fenced block" -fresh_copy -replace plugins/compactor/skills/compactor/SKILL.md \ - 'This skill is triggered when the user'"$Q"'s prompt contains `compact it`.' \ - 'This skill is triggered as follows: - -```text -`compact it` -```' -expect_fail "does not spell out \`compact it\`" \ - "a fence still hides text from a reader skimming the section" - -echo "==> Fixture: the spelled-out word under a '###' subheading" -fresh_copy -replace plugins/compactor/skills/compactor/SKILL.md \ - 'This skill is triggered when the user'"$Q"'s prompt contains `compact it`.' \ - '### Triggers - -This skill is triggered when the user'"$Q"'s prompt contains `compact it`.' -expect_pass_with "$CENSUS" \ - "a '###' subsection does not end its '## Shortcut' parent" - -echo "==> Fixture: the spelled-out word after a same-level heading" -fresh_copy -replace plugins/compactor/skills/compactor/SKILL.md \ - 'This skill is triggered when the user'"$Q"'s prompt contains `compact it`.' \ - '## Elsewhere - -This skill is triggered when the user'"$Q"'s prompt contains `compact it`.' -expect_fail "does not spell out \`compact it\`" \ - "a same-level heading still ends the Shortcut section" - -echo "==> Fixture: a backtick span split across a line break" -fresh_copy -replace plugins/compactor/skills/compactor/SKILL.md \ - 'prompt contains `compact it`.' \ - 'prompt contains `compact -it`.' -expect_pass_with "$CENSUS" \ - "a backtick span split across a line break is rejoined" - -echo "==> Fixture: an extra backtick span beside the declared word" -fresh_copy -replace plugins/compactor/skills/compactor/SKILL.md \ - 'This skill is triggered when the user'"$Q"'s prompt contains `compact it`.' \ - 'This skill is triggered when the user'"$Q"'s prompt contains `compact it`. - -Reads nothing but the previous result; see `scripts/validate` and `compactor:compactor`.' -expect_pass_with "$CENSUS" \ - "a backtick span that is not a trigger word is ordinary prose now" - -echo "==> Fixture: README missing Installation section" -fresh_copy -mutate 's/^## Installation$/## Setup/' plugins/compactor/README.md -expect_fail "no '## Installation' section" "missing '## Installation' section is caught" - -echo "==> Fixture: README missing License section" -fresh_copy -mutate 's/^## License$/## Licence/' plugins/compactor/README.md -expect_fail "no '## License' section" "missing '## License' section is caught" - -echo "==> Fixture: README with no H1 title" -fresh_copy -mutate 's/^# Compactor Plugin$/## Compactor Plugin/' plugins/compactor/README.md -expect_fail "no H1 title" "missing H1 title is caught" - -echo "==> Fixture: README of a trigger-declaring plugin with no Magic Word heading" -fresh_copy -mutate 's/^### Magic Words$/### Triggers/' plugins/compactor/README.md -expect_fail "no 'Magic Word' heading" "undocumented magic words are caught" - -echo "==> Fixture: README documenting a magic word the skill never declares" -fresh_copy -replace plugins/lingua/README.md \ - '| `reply in <lang>` | Same as above |' \ - '| `reply in <lang>` | Same as above | -| `lingua off` | Suspend for the current session |' -expect_fail 'documents `lingua off`, which the skill does not declare' \ - "a README magic word with no SKILL.md declaration is caught" - -echo "==> Fixture: SKILL.md trigger word missing from the README" -fresh_copy -# Declared and spelled out, so the only thing left wrong is the README. -declare_words compactor "compact it, squash it" -mutate 's/`compact it`./`compact it` or `squash it`./' plugins/compactor/skills/compactor/SKILL.md -expect_fail 'magic word `squash it` is declared in SKILL.md but undocumented here' \ - "a declared trigger word absent from the README is caught" - -echo "==> Fixture: README cross-check is not disarmed by an unreadable declaration" -fresh_copy -# Deleting metadata.shortcut stops the check above from learning compactor's -# words. The README cross-check must say so rather than read "no words -# collected" as "this plugin declares none" and print a green tick over the -# bogus row added here. -mutate '/^ shortcut: /d' plugins/compactor/skills/compactor/SKILL.md -replace plugins/compactor/README.md '- `compact it` → Compact the previous result' '- `compact it` → Compact the previous result -- `totally-bogus-word` → nothing at all' -expect_fail "could not be read (see the failure above)" "a plugin whose trigger declaration failed is not silently skipped by the README check" - -echo "==> Fixture: README spelling a trigger word with a placeholder" -fresh_copy -mutate 's/`compact it` →/`compact it <target>` →/' plugins/compactor/README.md -expect_pass "\`compact it <target>\` documents the declared \`compact it\`" - -echo "==> Fixture: unterminated code fence in a README" -fresh_copy -dirty plugins/compactor/README.md -printf '\n```text\nunclosed\n' >>"$TMP_DIR/repo/plugins/compactor/README.md" -expect_fail "plugins/compactor/README.md: unterminated code fence" \ - "an unterminated fence in a README is an error, not a quiet truncation" - -echo "==> Fixture: unterminated code fence in the top-level README" -fresh_copy -dirty README.md -printf '\n```text\nunclosed\n' >>"$TMP_DIR/repo/README.md" -expect_fail "README.md: unterminated code fence" \ - "an unterminated fence in the TOP-LEVEL README is an error, not a quiet truncation" - -echo "==> Fixture: plugin directory absent from marketplace.json" -fresh_copy -dirty plugins/ghost -mkdir -p "$TMP_DIR/repo/plugins/ghost" -echo '# Ghost Plugin' >"$TMP_DIR/repo/plugins/ghost/README.md" -expect_fail "plugins/ghost/README.md: no '## Installation' section" \ - "README of an unregistered plugin directory is still checked" - -echo "==> Fixture: SKILL.md description drifting from the manifests" -fresh_copy -# Matched by shape, not by content: pinning the wording made this fixture -# break every time the description was edited, for a reason that was never -# about drift. -mutate 's/^description: .*/description: Something else entirely./' \ - plugins/compactor/skills/compactor/SKILL.md -expect_fail "compactor: description differs between its sources" \ - "a SKILL.md description that drifts from plugin.json and marketplace.json is caught" - -echo "==> Fixture: plugin.json description drifting from the other two" -fresh_copy -mutate 's/"description": ".*"/"description": "Something else entirely."/' \ - plugins/compactor/.claude-plugin/plugin.json -expect_fail "compactor: description differs between its sources" \ - "a plugin.json description that drifts from SKILL.md and marketplace.json is caught" - -echo "==> Fixture: README blockquote drifting from the manifests" -fresh_copy -# The fourth copy. It is line-wrapped, so an edit that rewrites the other three -# by exact string match leaves this one behind -- which is exactly what happened -# to nineteen of them while this check only read three sources. -mutate '3s/.*/> Something else entirely./' plugins/compactor/README.md -expect_fail "compactor: description differs between its sources" \ - "a plugin README blockquote that drifts from the three manifests is caught" - -echo "==> Fixture: README description blockquote in the wrong place" -fresh_copy -# Position is the whole point: a loose search for the first blockquote would -# compare whichever paragraph a README happens to quote. -mutate '2s/.*/Some prose before the quote./' plugins/compactor/README.md -expect_fail "plugins/compactor/README.md: must open with its H1, a blank line, then the" \ - "a description blockquote not sitting directly under the H1 is caught" - -echo "==> Fixture: plugin missing from the top-level README" -fresh_copy -mutate 's/compactor//g' README.md -expect_fail "plugin 'compactor' is registered in marketplace.json but not listed here" \ - "a plugin the top-level README does not list is caught" - -echo "==> Fixture: roster row deleted, a prose mention left behind" -fresh_copy -# Drop every table row naming the plugin. `tenth-man` still appears in the -# Model Tiers prose and in the fenced workflow diagram, so a substring search -# over the README would still find it. -mutate '/^|.*tenth-man/d' README.md -expect_fail "plugin 'tenth-man' is registered in marketplace.json but not listed here" \ - "a prose mention does not substitute for a deleted roster row" - -echo "==> Fixture: roster row hidden in a four-space-indented code block" -fresh_copy -mutate '/^|.*`compactor`/d' README.md -printf '\n | `compactor` | Re-renders the previous result |\n' >>"$TMP_DIR/repo/README.md" -expect_fail "plugin 'compactor' is registered in marketplace.json but not listed here" \ - "an indented code block is not a roster row" - -echo "==> Fixture: top-level README naming a plugin only inside a code fence" -fresh_copy -mutate 's/compactor//g' README.md -printf '\n```text\ncompactor\n```\n' >>"$TMP_DIR/repo/README.md" -expect_fail "plugin 'compactor' is registered in marketplace.json but not listed here" \ - "a plugin named only inside a code fence does not count as listed" - -# --------------------------------------------------------------------------- -# scripts/check-skill-spec — one fixture per rule. A rule that cannot be made -# to fail is a rule that proves nothing, which is the whole point of this file. -# compactor is the target throughout: it is the smallest skill, so a mutation -# there is the cheapest one that still exercises the reader. -# --------------------------------------------------------------------------- -SPEC_SKILL=plugins/compactor/skills/compactor/SKILL.md - -echo "==> Baseline: unmutated copy against the standard" -fresh_copy -expect_spec_pass "clean copy follows the standard" - -echo "==> Fixture: a frontmatter key outside both allowed sets" -fresh_copy -mutate 's/^license: MIT$/license: MIT\nargument-hint: "[x]"/' "$SPEC_SKILL" -expect_spec_fail "unknown frontmatter key 'argument-hint'" \ - "a Claude Code field this repo has not adopted is rejected" - -echo "==> Fixture: a name outside the standard's grammar" -fresh_copy -mutate 's/^name: compactor$/name: Compactor/' "$SPEC_SKILL" -expect_spec_fail "must be lowercase letters, numbers and single" \ - "an uppercase name is rejected" - -echo "==> Fixture: a reserved word in the name" -fresh_copy -mutate 's/^name: compactor$/name: claude-compactor/' "$SPEC_SKILL" -expect_spec_fail "contains the reserved word 'claude'" \ - "a reserved word in the name is rejected" - -echo "==> Fixture: a name that does not match its directory" -fresh_copy -mutate 's/^name: compactor$/name: compact-or/' "$SPEC_SKILL" -expect_spec_fail "does not match its directory 'compactor'" \ - "a name drifting from its directory is rejected" - -echo "==> Fixture: a description written in the first person" -fresh_copy -mutate 's/^description: .*/description: I can help you compact things./' "$SPEC_SKILL" -expect_spec_fail "description must be third person" \ - "a first-person description is rejected" - -echo "==> Fixture: an XML tag in the description" -fresh_copy -mutate 's|^description: .*|description: <b>Compacts</b> results.|' "$SPEC_SKILL" -expect_spec_fail "description contains an XML tag" \ - "a tag in the description is rejected" - -echo "==> Fixture: a description past this repo's length limit" -fresh_copy -dirty "$SPEC_SKILL" -python3 - "$TMP_DIR/repo/$SPEC_SKILL" <<'INNER' -import re -import sys - -path = sys.argv[1] -with open(path) as handle: - text = handle.read() -with open(path, "w") as handle: - handle.write(re.sub(r"(?m)^description: .*$", "description: " + "Compacts results. " * 30, text)) -INNER -# Matched by shape, not by value: pinning the number made this fixture fail the -# moment the threshold moved, for a reason that was never about the check. -expect_spec_fail "characters, over this repo's" \ - "a description written only for triggering, unreadable as catalogue copy, is rejected" - -echo "==> Fixture: allowed-tools written as a string" -fresh_copy -replace "$SPEC_SKILL" 'allowed-tools: - - Read - - Glob - - Grep' 'allowed-tools: Read, Glob, Grep' -expect_spec_fail "allowed-tools must be a YAML list, not a string" \ - "a string, which a spec-strict reader would split on spaces into nonsense, is rejected" - -echo "==> Fixture: a metadata key with no value" -fresh_copy -mutate 's/^ version: .*/ version:/' "$SPEC_SKILL" -expect_spec_fail "metadata.version must hold a string value" \ - "a valueless metadata key is rejected" - -echo "==> Fixture: compatibility past its limit" fresh_copy -dirty "$SPEC_SKILL" -python3 - "$TMP_DIR/repo/$SPEC_SKILL" <<'INNER' -import sys +echo "==> scripts/validate" +expect validate pass "the repo as it stands is accepted" -path = sys.argv[1] -with open(path) as handle: - text = handle.read() -with open(path, "w") as handle: - handle.write(text.replace("license: MIT", "license: MIT\ncompatibility: " + "x" * 501, 1)) -INNER -expect_spec_fail "over the 500 limit" "an over-long compatibility string is rejected" +sed -i.bak 's/"description": "/"description": "Changed. /' "$TMP_DIR/repo/plugins/wisdom/.claude-plugin/plugin.json" +expect validate "description differs" "a plugin.json description drifting from marketplace.json is caught" -echo "==> Fixture: a body past the progressive-disclosure budget" -fresh_copy -dirty "$SPEC_SKILL" -for _ in $(seq 1 520); do echo "filler" >>"$TMP_DIR/repo/$SPEC_SKILL"; done -expect_spec_fail "over the 500 budget" "a body that should have been split is rejected" +sed -i.bak 's/wisdom/sagesse/g' "$TMP_DIR/repo/README.md" +expect validate "never named in README.md prose" "a plugin missing from the README prose is caught" -echo "==> Fixture: a body approaching, but not over, the budget" -fresh_copy -dirty "$SPEC_SKILL" -for _ in $(seq 1 380); do echo "filler" >>"$TMP_DIR/repo/$SPEC_SKILL"; done -# Matched by shape, not by value: a fixture that pins the threshold fails when -# the threshold moves, for a reason that was never about the check. -expect_spec_warn "line where a body is worth re-reading" \ - "a body nearing the ceiling warns without failing" +ghost ghost-a "boo" +ghost ghost-b "boo" +expect validate "magic word 'boo' is claimed by both" "a magic word claimed twice is caught" -echo "==> Fixture: a reference to a file that is not bundled" -fresh_copy -dirty "$SPEC_SKILL" -printf '\nSee [the guide](references/gone.md).\n' >>"$TMP_DIR/repo/$SPEC_SKILL" -expect_spec_fail "does not resolve to a bundled file" "a dangling reference is rejected" +ghost ghost +expect validate "skill 'ghost' is missing from the '## Skills' tables" "a skill missing from a README is caught" -echo "==> Fixture: a Windows-style path" -fresh_copy -dirty "$SPEC_SKILL" -printf '\nSee [the script](scripts\\helper.py).\n' >>"$TMP_DIR/repo/$SPEC_SKILL" -expect_spec_fail "use forward slashes everywhere" "a backslash path is rejected" +rm -rf "$TMP_DIR/repo/$SKILLS/compact" +expect validate "lists 'compact', which no plugin ships" "a README row for an unshipped skill is caught" -echo "==> Fixture: a reference chain two levels deep" -fresh_copy -dirty "$SPEC_SKILL" plugins/compactor/skills/compactor/references -mkdir -p "$TMP_DIR/repo/plugins/compactor/skills/compactor/references" -printf '# A\n\nSee [b](b.md).\n' >"$TMP_DIR/repo/plugins/compactor/skills/compactor/references/a.md" -printf '# B\n' >"$TMP_DIR/repo/plugins/compactor/skills/compactor/references/b.md" -printf '\nSee [a](references/a.md).\n' >>"$TMP_DIR/repo/$SPEC_SKILL" -expect_spec_fail "Keep every reference" "a second level of indirection is rejected" +sed -i.bak 's/^description: .*/&\nmetadata:\n shortcut: "dispatch it"/' "$TMP_DIR/repo/$TARGET" +expect validate "but its SKILL.md declares" "a magic word the README does not list is caught" -echo "==> Fixture: a long reference file with no contents list" -fresh_copy -dirty "$SPEC_SKILL" plugins/compactor/skills/compactor/references -mkdir -p "$TMP_DIR/repo/plugins/compactor/skills/compactor/references" -{ - echo "# Long" - for _ in $(seq 1 120); do echo "line"; done -} >"$TMP_DIR/repo/plugins/compactor/skills/compactor/references/long.md" -printf '\nSee [long](references/long.md).\n' >>"$TMP_DIR/repo/$SPEC_SKILL" -expect_spec_fail "needs a" "a long reference file with no contents list is rejected" +echo 'Hand off to `wisdom:nope`.' >>"$TMP_DIR/repo/$TARGET" +expect validate "reference 'wisdom:nope' resolves to no skill" "an unresolved skill reference is caught" -echo "==> Fixture: frontmatter with no closing marker" -fresh_copy -dirty "$SPEC_SKILL" -python3 - "$TMP_DIR/repo/$SPEC_SKILL" <<'INNER' -import sys +printf '\n```text\nopen\n' >>"$TMP_DIR/repo/$TARGET" +expect validate "unterminated code fence" "an unclosed fence in a skill is caught" -path = sys.argv[1] -with open(path) as handle: - text = handle.read() -with open(path, "w") as handle: - handle.write(text.replace("---", "", 1)) -INNER -expect_spec_fail "closing '---' is absent" "unterminated frontmatter is rejected" +printf '\n```text\nopen\n' >>"$TMP_DIR/repo/README.zh-TW.md" +expect validate "README.zh-TW.md: unterminated code fence" "an unclosed fence in a README is caught" -echo "==> Fixture: an emitted verdict block that nothing declares" -fresh_copy -mutate '/^ verdict: /d' "plugins/agent-ellis/skills/agent-ellis/SKILL.md" -expect_fail "but metadata.verdict is absent" \ - "a verdict block with no declaration is rejected" +echo "==> scripts/check-skill-spec" +expect check-skill-spec pass "the repo as it stands is accepted" -echo "==> Fixture: a declared verdict the body never shows" -fresh_copy -dirty "plugins/agent-ellis/skills/agent-ellis/SKILL.md" -python3 - "$TMP_DIR/repo/plugins/agent-ellis/skills/agent-ellis/SKILL.md" <<'INNER' -import re -import sys +sed -i.bak 's/^license: MIT$/license: MIT\nversion: 1/' "$TMP_DIR/repo/$TARGET" +expect check-skill-spec "unknown frontmatter key 'version'" "an unknown frontmatter key is caught" -path = sys.argv[1] -with open(path) as handle: - text = handle.read() -# Drop the fenced block whole -- fence markers included, so the fence check -# downstream still sees a balanced file. -text = re.sub( - r"```txt\n__REVIEW_VERDICT__\n.*?```\n", - "", - text, - count=1, - flags=re.S, -) -with open(path, "w") as handle: - handle.write(text) -INNER -expect_fail "its body never shows the block" \ - "a declaration with no block is rejected" +sed -i.bak "s/^description: .*/description: $(printf 'x%.0s' $(seq 1 161))/" "$TMP_DIR/repo/$TARGET" +expect check-skill-spec "over this repo's 160 limit" "a description over 160 characters is caught" -echo "==> Fixture: a verdict block with no fields in it" -fresh_copy -python3 - "$TMP_DIR/repo/plugins/agent-ellis/skills/agent-ellis/SKILL.md" <<'INNER' -import re -import sys +sed -i.bak 's/^description: .*/description: I dispatch skills./' "$TMP_DIR/repo/$TARGET" +expect check-skill-spec "must be third person" "a first-person description is caught" -path = sys.argv[1] -with open(path) as handle: - text = handle.read() -# Keep the fence and both markers, drop the 'Field: value' lines between them. -text = re.sub( - r"(__REVIEW_VERDICT__\n).*?(__REVIEW_VERDICT__\n)", - r"\1\2", - text, - count=1, - flags=re.S, -) -with open(path, "w") as handle: - handle.write(text) -INNER -dirty "plugins/agent-ellis/skills/agent-ellis/SKILL.md" -expect_fail "carries no 'Field: value' line" "an empty verdict block is rejected" +sed -i.bak 's/^name: shortcut$/name: shortcuts/' "$TMP_DIR/repo/$TARGET" +expect check-skill-spec "does not match its directory" "a name that differs from its directory is caught" -echo "==> Fixture: a verdict block renamed on one side only" -fresh_copy -dirty "plugins/agent-ellis/skills/agent-ellis/SKILL.md" -printf '\n```txt\n__EXTRA_VERDICT__\nStatus: OK\n__EXTRA_VERDICT__\n```\n' \ - >>"$TMP_DIR/repo/plugins/agent-ellis/skills/agent-ellis/SKILL.md" -expect_fail "but metadata.verdict is __REVIEW_VERDICT__" \ - "a block whose marker is not the declared one is rejected" - -echo "==> Fixture: a blank line inside a verdict block is formatting, not a rename" -fresh_copy -dirty "plugins/agent-ellis/skills/agent-ellis/SKILL.md" -python3 - "$TMP_DIR/repo/plugins/agent-ellis/skills/agent-ellis/SKILL.md" <<'INNER' -import sys - -path = sys.argv[1] -with open(path) as handle: - text = handle.read() -with open(path, "w") as handle: - handle.write(text.replace("```txt\n__REVIEW_VERDICT__\n", "```txt\n\n__REVIEW_VERDICT__\n", 1)) -INNER -expect_pass_with "emits and declares __REVIEW_VERDICT__" \ - "a blank first line does not read as a missing block" - -echo "==> Fixture: routing on a verdict no skill emits" -fresh_copy -mutate 's/`__OPS_VERDICT__`/`__OPERATIONS_VERDICT__`/' \ - "plugins/agent-smith/skills/agent-smith/SKILL.md" -expect_fail "which no skill in this marketplace declares" \ - "a caller routing on an unknown verdict is rejected" - -echo "==> Fixture: a plugin with no trigger evals" -fresh_copy -dirty "plugins/compactor/evals" -rm -rf "$TMP_DIR/repo/plugins/compactor/evals" -expect_fail "no evals/trigger-queries.json" "a plugin without trigger evals is rejected" - -echo "==> Fixture: trigger evals with every query labelled the same way" -fresh_copy -dirty "plugins/compactor/evals" -python3 - "$TMP_DIR/repo/plugins/compactor/evals/trigger-queries.json" <<'INNER' -import json -import sys - -path = sys.argv[1] -with open(path) as handle: - doc = json.load(handle) -for query in doc["queries"]: - query["should_trigger"] = True -with open(path, "w") as handle: - json.dump(doc, handle, indent=2) -INNER -expect_fail "labels every query the same way" "a positives-only eval set is rejected" - -echo "==> Fixture: trigger evals that never split off a validation set" -fresh_copy -dirty "plugins/compactor/evals" -python3 - "$TMP_DIR/repo/plugins/compactor/evals/trigger-queries.json" <<'INNER' -import json -import sys - -path = sys.argv[1] -with open(path) as handle: - doc = json.load(handle) -for query in doc["queries"]: - query["split"] = "train" -with open(path, "w") as handle: - json.dump(doc, handle, indent=2) -INNER -expect_fail "does not split train/validation" "an eval set with no validation half is rejected" - -echo "==> Fixture: a positive query carrying another plugin's magic word" -fresh_copy -dirty "plugins/agent-twain/evals" -mutate 's/"our readme still documents the old flags"/"the readme is out of date, fix it"/' \ - "plugins/agent-twain/evals/trigger-queries.json" -expect_fail "a magic word of agent-smith" \ - "an ambiguous positive query is rejected" - -echo "==> Fixture: trigger evals naming a skill that is not their own" -fresh_copy -dirty "plugins/compactor/evals" -mutate 's/"skill": "compactor"/"skill": "spec-writer"/' \ - "plugins/compactor/evals/trigger-queries.json" -expect_fail "but sits under plugins/compactor" "an eval file naming the wrong skill is rejected" - -# fresh_copy restores only what a fixture declared, so an undeclared mutation -# would silently poison every fixture after it. Restore, then prove the work -# copy is the pristine one again. -echo "==> Checking every fixture declared what it mutated" -fresh_copy -if diff -r "$TMP_DIR/pristine" "$TMP_DIR/repo" >"$TMP_DIR/drift" 2>&1; then - pass "no fixture leaked a mutation into the ones after it" -else - fail "a fixture changed a path it never passed to dirty, so it leaked into later fixtures" - sed 's/^/ /' "$TMP_DIR/drift" -fi +seq 1 101 >>"$TMP_DIR/repo/$TARGET" +expect check-skill-spec "over its 100-line budget" "a body over its line budget is caught" echo "" -if [ "$ERRORS" -gt 0 ]; then - echo "==> $ERRORS error(s) found" +if [ "$ERRORS" -ne 0 ]; then + echo "==> $ERRORS fixture(s) FAILED" exit 1 -else - echo "==> All fixtures behaved as expected" fi +echo "==> All fixtures passed"