diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index d68b3dd..8e8aa23 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1,7 +1,7 @@ { "$schema": "https://anthropic.com/claude-code/marketplace.schema.json", "name": "greybeard", - "description": "Greybeard \u2014 Karpathy-inspired coding-agent guidelines, the skillify / check-resolvable meta-skills, the verify-responsive practice skill, and the /pressure-test, /sidenote, /visualize and /wrap commands.", + "description": "Karpathy-inspired coding-agent guidelines and seven portable skills: skillify, check-resolvable, verify-responsive, pressure-test, sidenote, visualize, and wrap.", "owner": { "name": "Clawnify", "url": "https://github.com/clawnify" @@ -9,7 +9,7 @@ "plugins": [ { "name": "greybeard", - "description": "skillify + check-resolvable + verify-responsive skills and the /pressure-test, /sidenote, /visualize and /wrap commands. Pair with the npx installer for the always-on guidelines.", + "description": "Karpathy-inspired coding-agent guidelines and seven portable skills: skillify, check-resolvable, verify-responsive, pressure-test, sidenote, visualize, and wrap.", "source": "./", "category": "productivity" } diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 317afa8..9a2f387 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "greybeard", - "description": "Karpathy-inspired coding-agent skills: skillify (capture repeated work), check-resolvable (keep skills DRY + MECE), verify-responsive (render a UI at real viewport widths), and the /pressure-test, /sidenote, /visualize and /wrap commands.", + "description": "Karpathy-inspired coding-agent guidelines and seven portable skills: skillify, check-resolvable, verify-responsive, pressure-test, sidenote, visualize, and wrap.", "author": { "name": "Clawnify", "url": "https://github.com/clawnify" diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml index 7ced935..eb311e4 100644 --- a/.github/workflows/sync.yml +++ b/.github/workflows/sync.yml @@ -15,6 +15,7 @@ jobs: node-version: '20' # Fail if any harness rule copy drifted from CLAUDE.md (the single source). - run: node scripts/build-rules.js --check + - run: npm test # Smoke-test the installer: it must list agents and dry-run without crashing. - run: node bin/install.js --list - run: node bin/install.js --all --dry-run diff --git a/README.md b/README.md index 1ee7c2f..fe59196 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ > Built and maintained by [Clawnify](https://clawnify.com) — a managed platform that provisions AI agents with WhatsApp / Telegram / Email and browser capabilities for non-technical users. -A single `CLAUDE.md` file to improve AI coding-agent behavior, derived from [Andrej Karpathy's observations](https://x.com/karpathy/status/2015883857489522876) on LLM coding pitfalls, plus three sections we added for the AI-assisted-coding era. Ships with three runnable [skills](#skills-skillify-dry--mece-resolvers), its four commands — [`/pressure-test`](#the-pressure-test-command), the decision test, [`/sidenote`](#the-sidenote-command), park-a-thought, [`/visualize`](#the-visualize-command), draw-the-real-shape, and [`/wrap`](#the-wrap-command), can-I-close-this — and a [one-command installer](#install) that fans it all out to every AI coding agent you use. +A single `CLAUDE.md` file to improve AI coding-agent behavior, derived from [Andrej Karpathy's observations](https://x.com/karpathy/status/2015883857489522876) on LLM coding pitfalls, plus three sections we added for the AI-assisted-coding era. Ships with seven portable [skills](#skills-skillify-dry--mece-resolvers), including four on-demand workflows — [`/pressure-test`](#the-pressure-test-command), the decision test, [`/sidenote`](#the-sidenote-command), park-a-thought, [`/visualize`](#the-visualize-command), draw-the-real-shape, and [`/wrap`](#the-wrap-command), can-I-close-this — and a [one-command installer](#install) for the guidelines and agent-specific integrations described below. ## The Problems @@ -194,21 +194,17 @@ They're standard [Claude Code Agent Skills](https://code.claude.com/docs/en/skil ## The four commands -Greybeard's slash commands are **`/pressure-test`**, **`/sidenote`**, **`/visualize`** and **`/wrap`** — one guards the *quality* of a decision, one guards your *focus* while you make it, one makes sure what you're shown is the code that's actually there, and one decides whether the session can end. The skills and always-on guidelines back them up, but these are the four you'll reach for by hand. +These four workflows are portable skills, each maintained once in `skills//SKILL.md`. Claude Code also exposes them as slash commands; Codex discovers them through its skill catalog. -**Getting them.** The commands ship inside the greybeard plugin, so Claude Code installs and updates them through its own plugin manager — `npx @clawnify/greybeard` does it for you, or do it by hand: +Greybeard's slash commands are **`/pressure-test`**, **`/sidenote`**, **`/visualize`** and **`/wrap`** — one guards the *quality* of a decision, one guards your *focus* while you make it, one makes sure what you're shown is the code that's actually there, and one decides whether the session can end. The skills and always-on guidelines back them up, but these are the four you'll reach for by hand. -```bash -claude plugin marketplace add clawnify/greybeard -claude plugin install greybeard@greybeard -claude plugin update greybeard@greybeard # later, to pull new commands -``` +**Getting them.** Install the greybeard plugin with your client's plugin manager; see [installation and updates](#install). In Claude Code, use `/greybeard:pressure-test`, `/greybeard:sidenote`, `/greybeard:visualize`, and `/greybeard:wrap`. The bare names below apply when installed as standalone skills. In Codex, select the skill with `$` (for example `$greybeard:pressure-test`) or ask “Pressure-test this approach.” Optional input comes from the invoking message; a bare invocation keeps each workflow's no-input behavior. -Don't also copy the files into `~/.claude/commands/`: you'd have two copies of every command in the resolver, drifting apart the moment one side updates. Plugin commands are namespaced — `/greybeard:pressure-test`, `/greybeard:wrap` — so the bare names used below are how they read in a harness where you drop the file in yourself. +Don't also copy the same workflows into a local skills or commands directory: that creates duplicate resolver entries. There are no separate `commands/` wrappers to install or update. ## The `/pressure-test` command -[`commands/pressure-test.md`](./commands/pressure-test.md) is a Claude Code slash command that runs the §5 decision test on demand: pressure-test the approach on the table against **scalable / long-term / efficient** — *whatever is scalable, long term, and cannot be done in a more efficient way* — and get one decisive recommendation, with stale-time-budget shortcuts called out. The main context runs the test and owns the ruling; subagents are scoped instruments, spawned only where a check benefits from being outside the session — challenging a belief the conversation already holds (a fresh context can't inherit its anchoring), or online research and docs verification that parallelize while the main agent keeps reasoning. Never the test wholesale: a main agent that only orchestrates stops being the main brain. Every ruling ships with a claims ledger: each load-bearing claim — one per plan item at minimum, every size-word counts — cited to the `file:line` actually opened, or tagged **ASSUMED**; no estimate may attach to an assumed claim. +[`skills/pressure-test/SKILL.md`](./skills/pressure-test/SKILL.md) is a portable skill that runs the §5 decision test on demand: pressure-test the approach on the table against **scalable / long-term / efficient** — *whatever is scalable, long term, and cannot be done in a more efficient way* — and get one decisive recommendation, with stale-time-budget shortcuts called out. The main context runs the test and owns the ruling; subagents are scoped instruments, spawned only where a check benefits from being outside the session — challenging a belief the conversation already holds (a fresh context can't inherit its anchoring), or online research and docs verification that parallelize while the main agent keeps reasoning. Never the test wholesale: a main agent that only orchestrates stops being the main brain. Every ruling ships with a claims ledger: each load-bearing claim — one per plan item at minimum, every size-word counts — cited to the `file:line` actually opened, or tagged **ASSUMED**; no estimate may attach to an assumed claim. Use `/pressure-test ` to test one call in depth, or bare `/pressure-test` to sweep every solution the session proposed — an inventory with a verdict on each (the holds stated as plainly as the fails), plus the section only the sweep produces: the decisions that were never examined at all. @@ -216,17 +212,17 @@ Use `/pressure-test ` to test one call in depth, or bare `/ You're mid-way through a big task and a passing thought hits — *"the retry logic probably has the same bug", "remind me to check the pricing later"* — something you don't want to forget. Drop it in the chat as-is and the agent reads it as a new request: it rushes the current task to "get to" your note, and the big task pays for it. -[`commands/sidenote.md`](./commands/sidenote.md) reframes that thought as a **parked later-task, not a now-task**. The agent logs it verbatim to a parking file (durable across compaction, session end, and worktree removal) — with a one-line anchor (task in progress, the file it points at, branch) so it still makes sense when another session or agent reads it cold — gives a one-line ack, and resumes *exactly* where it was — same scope, same pace, no cutting corners to reach the note. A bare `/sidenote` flushes the open list back to you. +[`skills/sidenote/SKILL.md`](./skills/sidenote/SKILL.md) reframes that thought as a **parked later-task, not a now-task**. The agent logs it verbatim to a parking file (durable across compaction, session end, and worktree removal) — with a one-line anchor (task in progress, the file it points at, branch) so it still makes sense when another session or agent reads it cold — gives a one-line ack, and resumes *exactly* where it was — same scope, same pace, no cutting corners to reach the note. A bare `/sidenote` flushes the open list back to you. Use `/sidenote ` to park one, or `/sidenote` to see what's parked. The notes land in `$(git rev-parse --path-format=absolute --git-common-dir)/info/sidenotes.md` — inside `.git/`, so they are personal per-repo scratch that no ignore rule has to protect and no `git add -A` can sweep into a PR, shared across all worktrees of the repo. Outside a git repo the fallback is `.claude/sidenotes.md` at the project root. -> **No slash commands?** For agents that read a rule file but have no `/` commands (Cursor, Codex, Copilot…), the same contract works as a plain-text convention: prefix the message with `SIDENOTE:` and the agent parks it instead of acting. Add one line to your rule file so it's honored reliably — see [`commands/sidenote.md`](./commands/sidenote.md) for the exact contract. +> **Plain-text invocation:** With the sidenote skill installed, ask to park a thought or prefix it with `SIDENOTE:`. Clients that only read rule files need an explicit rule for this convention; the standalone guidelines alone do not install the skill. ## The `/visualize` command Ask an agent to explain how something works and you get paragraphs. Ask it to *draw* the thing and you get comprehension — a call tree, a component tree, a sequence diagram. But a diagram is also the easiest place in the world to launder a guess: prose hedges out loud (*"it probably calls…"*), while boxes and arrows just assert. An architecture diagram drawn from priors reads as **verified**, and people build on it for weeks. -[`commands/visualize.md`](./commands/visualize.md) is the §7 rule applied to pictures. It gives the agent a menu of visual forms — pseudocode, call tree, component tree, file tree, text sequence diagrams, shaped `diff`s, or one focused HTML file — and tells it to pick the *smallest* one that makes the point, **matched to the surface it lands on**: a terminal has no diagram renderer, so a `mermaid` fence there just prints its own source; the text forms are the picture already. Mermaid is reserved for surfaces that actually render it. Then the Greybeard part: **read the code before drawing it** (the actual files, this session — if the diagram has five nodes, you opened five things), **anchor every node** to a real `file:line`, **trace the current shape with the real input** (an anchor proves the node exists, not that the arrow fires — if the concrete key dead-ends in the registry, the dead end is the picture), and **tag anything unread as ASSUMED** with the check that would settle it. A diagram that's 90% verified and 10% quietly invented is 100% untrustworthy. +[`skills/visualize/SKILL.md`](./skills/visualize/SKILL.md) is the §7 rule applied to pictures. It gives the agent a menu of visual forms — pseudocode, call tree, component tree, file tree, text sequence diagrams, shaped `diff`s, or one focused HTML file — and tells it to pick the *smallest* one that makes the point, **matched to the surface it lands on**: a terminal has no diagram renderer, so a `mermaid` fence there just prints its own source; the text forms are the picture already. Mermaid is reserved for surfaces that actually render it. Then the Greybeard part: **read the code before drawing it** (the actual files, this session — if the diagram has five nodes, you opened five things), **anchor every node** to a real `file:line`, **trace the current shape with the real input** (an anchor proves the node exists, not that the arrow fires — if the concrete key dead-ends in the registry, the dead end is the picture), and **tag anything unread as ASSUMED** with the check that would settle it. A diagram that's 90% verified and 10% quietly invented is 100% untrustworthy. Use `/visualize `, or a bare `/visualize` to draw whatever's currently on the table. @@ -234,7 +230,7 @@ Use `/visualize `, or a bare `/visualize` to draw whatever's curre The question at the end of every session: *can I close this and delete the worktree?* Get it wrong one way and you lose work — an unpushed branch, or the hour of dead ends that only ever existed in the context. Get it wrong the other way and sessions pile up, half-finished, each one a tab nobody dares close. -[`commands/wrap.md`](./commands/wrap.md) makes the agent rule on it, and there are only two rulings: **finish it now**, or **wrap it** — turn what's here into something durable and say it's safe to delete. The test isn't *is this important*, it's **what dies when the worktree dies**: uncommitted edits, untracked files, commits that never left the machine, and the part no diff carries — what you tried, what you rejected, and why. Four hard stops force *finish now* (the world outside the repo is mid-change; the trunk is worse than you found it; what's left is minutes of work — §5's pre-AI estimate again; or you can't write the brief, which means you don't understand the state well enough to hand it off). Otherwise it picks the cheapest durable form that actually carries the work — a `/sidenote` entry, a committed doc, a GitHub issue, or the branch pushed with a draft PR — writes the five-line brief (goal / done / left / **rejected** / verify, anchored to `file:line`), shows you the artifact before creating it, and confirms it landed *outside* the worktree before answering. An unpushed commit is not a handoff. +[`skills/wrap/SKILL.md`](./skills/wrap/SKILL.md) makes the agent rule on it, and there are only two rulings: **finish it now**, or **wrap it** — turn what's here into something durable and say it's safe to delete. The test isn't *is this important*, it's **what dies when the worktree dies**: uncommitted edits, untracked files, commits that never left the machine, and the part no diff carries — what you tried, what you rejected, and why. Four hard stops force *finish now* (the world outside the repo is mid-change; the trunk is worse than you found it; what's left is minutes of work — §5's pre-AI estimate again; or you can't write the brief, which means you don't understand the state well enough to hand it off). Otherwise it picks the cheapest durable form that actually carries the work — a `/sidenote` entry, a committed doc, a GitHub issue, or the branch pushed with a draft PR — writes the five-line brief (goal / done / left / **rejected** / verify, anchored to `file:line`), shows you the artifact before creating it, and confirms it landed *outside* the worktree before answering. An unpushed commit is not a handoff. Reach for a bare `/wrap` at the point you'd otherwise close the tab. It ends on the verdict line — `Safe to close — carries it.` or `Not yet — has to close here first.` — and hands you the `git worktree remove` command rather than running it, since it's standing in the worktree it would delete. @@ -246,7 +242,7 @@ Reach for a bare `/wrap` at the point you'd otherwise close the tab. It ends on npx @clawnify/greybeard ``` -It detects the AI coding agents you actually use and installs the right files for each, at two tiers: what's **installed on your system** (Claude Code, OpenCode, OpenClaw) gets its global files once — the guidelines into `~/.claude/CLAUDE.md`, the greybeard plugin installed (or updated) through Claude Code's own `claude plugin` CLI, which is where its skills and commands live, the `skillify` / `check-resolvable` / `verify-responsive` skills for OpenClaw, and the OpenCode guidelines plugin; what's **used in this repo** (its rule file or directory exists here — `AGENTS.md`, `GEMINI.md`, `copilot-instructions.md`, `.cursor/`, `.windsurf/`, `.clinerules/`) gets the seven guidelines in the format it reads. Having an agent installed on your machine never sprinkles rule files into repos that don't use it — adopt one there with `--all` or `--only `. Shared files are edited between markers, so re-running is a safe no-op and your own content is preserved. +It detects the AI coding agents you actually use and installs the right files for each, at two tiers: what's **installed on your system** (Claude Code, OpenCode, OpenClaw) gets its global files once — the guidelines into `~/.claude/CLAUDE.md`, the greybeard plugin installed (or updated) through Claude Code's own `claude plugin` CLI, which is where its skills and commands live, all seven skills for OpenClaw, and the OpenCode guidelines plugin; what's **used in this repo** (its rule file or directory exists here — `AGENTS.md`, `GEMINI.md`, `copilot-instructions.md`, `.cursor/`, `.windsurf/`, `.clinerules/`) gets the seven guidelines in the format it reads. Having an agent installed on your machine never sprinkles rule files into repos that don't use it — adopt one there with `--all` or `--only `. Shared files are edited between markers, so re-running is a safe no-op and your own content is preserved. ```bash npx @clawnify/greybeard --list # show detected agents @@ -258,11 +254,22 @@ npx @clawnify/greybeard --uninstall # remove what it added Supported: **Claude Code, OpenCode, Cursor, Windsurf, Cline, GitHub Copilot, Codex, Gemini CLI, OpenClaw** — and any agent that reads `CLAUDE.md` / `AGENTS.md`. -**Claude Code plugin marketplace** (the skills + the three commands + always-on guidelines): +**The standalone installer and the plugin provide different things.** `npx @clawnify/greybeard --only codex` appends the guidelines to this project's `AGENTS.md`; it does **not** install Codex skills or a Codex plugin. Install the plugin separately to get the seven workflows. The installer manages the Claude Code plugin through `claude plugin`, and copies skills for OpenClaw; the other rule-file integrations supply guidelines. + +**Codex plugin marketplace** (all seven skills): + +```bash +codex plugin marketplace add clawnify/greybeard +codex plugin add greybeard@greybeard +``` + +Start a fresh session after installation or updating. In the skill selector, confirm `greybeard:pressure-test`, `greybeard:sidenote`, `greybeard:visualize`, `greybeard:wrap`, `greybeard:skillify`, `greybeard:check-resolvable`, and `greybeard:verify-responsive` each appear once. An “installed, enabled” plugin listing alone does not verify skill discovery. If the catalog is stale, restart Codex. + +**Claude Code plugin marketplace** (all seven skills, slash invocations, and the session hook): ``` /plugin marketplace add clawnify/greybeard -/plugin install greybeard +/plugin install greybeard@greybeard ``` The plugin ships a `SessionStart` / `SubagentStart` hook that injects the three-pillars decision test (scalable / long term / efficient — the core of `/pressure-test`) into every session automatically — installing the plugin is enough, no per-project `npx` run needed. It's careful not to double up: if the full guidelines are already in your `~/.claude/CLAUDE.md` or a project's `CLAUDE.md` / `AGENTS.md` (via the npx installer or a hand-merge), the hook detects them and stays silent. To turn injection off without uninstalling, set `GREYBEARD=off` in your environment. @@ -284,17 +291,24 @@ curl https://raw.githubusercontent.com/clawnify/greybeard/main/CLAUDE.md >> CLAU npx @clawnify/greybeard@latest ``` -- **Claude Code plugin** — there's no `/plugin update`; refresh the marketplace, then reinstall (third-party marketplaces don't auto-update by default). You can flip on auto-update in `/plugin` → **Marketplaces**: +- **Codex plugin** — refresh the marketplace snapshot and install the refreshed plugin, then start a fresh session: + ```bash + codex plugin marketplace upgrade greybeard + codex plugin add greybeard@greybeard ``` - /plugin marketplace update greybeard - /plugin uninstall greybeard@greybeard - /plugin install greybeard@greybeard - /reload-plugins + +- **Claude Code plugin** — refresh the marketplace and update the installed plugin, then restart Claude Code: + + ```bash + claude plugin marketplace update greybeard + claude plugin update greybeard@greybeard ``` - **Manual (curl)** — re-run the `-o` form; it overwrites `CLAUDE.md` with the latest (the `>>` append form would duplicate). +The migration keeps the existing Claude Code names and optional arguments. Updating replaces the old command-only package with the seven-skill package; no manual command copies are needed. If you previously copied workflows into personal directories yourself, remove those old copies when adopting the plugin so each capability appears once. + > The per-agent rule files are generated from `CLAUDE.md` (the single source) by `scripts/build-rules.js`. Contributors: edit `CLAUDE.md`, run `npm run build`, commit. CI (`npm run check-sync`) fails if a copy drifts. > **Releasing** (maintainers): bump `version` in `package.json`, then cut a GitHub Release tagged `v` (`gh release create v0.2.0 --generate-notes`). The [`Publish to npm`](.github/workflows/publish.yml) workflow publishes `@clawnify/greybeard` on release (with npm provenance), using the `NPM_TOKEN` repo secret. diff --git a/bin/install.js b/bin/install.js index c359ccf..c9fec74 100644 --- a/bin/install.js +++ b/bin/install.js @@ -149,11 +149,11 @@ function rel(p) { return p.startsWith(HOME) ? '~' + p.slice(HOME.length) : path. // The canonical principles payload for fenced installs = the generated AGENTS.md. const PRINCIPLES = fs.readFileSync(path.join(PKG, 'AGENTS.md'), 'utf8'); // Skill directories shipped to every provider that reads skills. Add a new one here only. -const SKILLS = ['skillify', 'check-resolvable', 'verify-responsive']; +const SKILLS = ['skillify', 'check-resolvable', 'verify-responsive', 'pressure-test', 'sidenote', 'visualize', 'wrap']; // Command files earlier versions copied into ~/.claude/commands (plus 'scalable', // the pre-rename name of pressure-test). The plugin ships these now; this list // exists only to clear the copies off machines that still carry them. Nothing to -// add here for a new command — the plugin picks it up from commands/. +// add here for a new command — the plugin picks it up from skills/. const LEGACY_COMMAND_COPIES = ['pressure-test', 'sidenote', 'visualize', 'wrap', 'scalable']; // ── Per-provider install / uninstall ──────────────────────────────────────── diff --git a/hooks/greybeard-activate.js b/hooks/greybeard-activate.js index f9f34b5..64adb1b 100644 --- a/hooks/greybeard-activate.js +++ b/hooks/greybeard-activate.js @@ -48,8 +48,8 @@ function alreadyLoaded(cwd) { return false; } -// The condensed behavioral core: the three pillars (from commands/ -// pressure-test.md) plus the highest-frequency stances from CLAUDE.md +// The condensed behavioral core: the three pillars (from +// skills/pressure-test/SKILL.md) plus the highest-frequency stances from CLAUDE.md // (opinionated tradeoffs, symptom-vs-diagnosis, stale time budgets). Keep // wording in sync with those files — and keep this block small: it is paid // as context in every session and subagent, so a rule earns a paragraph diff --git a/hooks/greybeard-opencode.js b/hooks/greybeard-opencode.js index 816628a..aab6278 100644 --- a/hooks/greybeard-opencode.js +++ b/hooks/greybeard-opencode.js @@ -24,8 +24,8 @@ // Either string marks a file as already carrying the guidelines. const MARKERS = ['', '## 1. Think Before Coding']; -// The condensed behavioral core: the three pillars (from commands/ -// pressure-test.md) plus the highest-frequency stances from CLAUDE.md +// The condensed behavioral core: the three pillars (from +// skills/pressure-test/SKILL.md) plus the highest-frequency stances from CLAUDE.md // (opinionated tradeoffs, symptom-vs-diagnosis, stale time budgets). Keep // wording in sync with hooks/greybeard-activate.js — and keep this block // small: it is paid as context in every session, so a rule earns a paragraph diff --git a/package.json b/package.json index c7429ba..5819abd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@clawnify/greybeard", "version": "0.4.0", - "description": "Greybeard \u2014 Karpathy-inspired guardrails that make your AI coding agent behave like a principled senior engineer. Guidelines + the skillify / check-resolvable / verify-responsive skills + the /pressure-test, /sidenote, /visualize and /wrap commands, installable across every AI coding agent.", + "description": "Greybeard — Karpathy-inspired coding-agent guidelines and seven portable skills: skillify, check-resolvable, verify-responsive, pressure-test, sidenote, visualize, and wrap.", "license": "MIT", "homepage": "https://github.com/clawnify/greybeard", "repository": { @@ -19,6 +19,7 @@ }, "scripts": { "build": "node scripts/build-rules.js", + "test": "node scripts/check-skills.js", "check-sync": "node scripts/build-rules.js --check" }, "files": [ @@ -26,7 +27,6 @@ "bin/", "scripts/", "skills/", - "commands/", "hooks/", "CLAUDE.md", "AGENTS.md", diff --git a/scripts/check-skills.js b/scripts/check-skills.js new file mode 100644 index 0000000..2ae9297 --- /dev/null +++ b/scripts/check-skills.js @@ -0,0 +1,43 @@ +#!/usr/bin/env node +'use strict'; + +// Package-level regression for #43. Native client discovery is checked separately +// using the procedure in skills/README.md. +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const os = require('node:os'); +const path = require('node:path'); +const { execFileSync } = require('node:child_process'); + +const root = path.resolve(__dirname, '..'); +const skills = ['check-resolvable', 'pressure-test', 'sidenote', 'skillify', 'verify-responsive', 'visualize', 'wrap']; +const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'greybeard-package-')); + +try { + const [pkg] = JSON.parse(execFileSync('npm', [ + 'pack', '--dry-run', '--json', '--ignore-scripts', '--cache', temp, + ], { cwd: root, encoding: 'utf8' })); + const files = new Set(pkg.files.map(file => file.path)); + const entries = skills.map(name => `skills/${name}/SKILL.md`); + assert.deepEqual([...files].filter(file => /^skills\/[^/]+\/SKILL\.md$/.test(file)).sort(), entries); + assert.equal([...files].some(file => file.startsWith('commands/')), false, 'Duplicate command entrypoints in package'); + const commands = path.join(root, 'commands'); + assert.ok(!fs.existsSync(commands) || fs.readdirSync(commands).length === 0, 'Plugin would still discover command entrypoints'); + + for (const [index, entry] of entries.entries()) { + const text = fs.readFileSync(path.join(root, entry), 'utf8'); + assert.equal(text.match(/^name: (.+)$/m)?.[1], skills[index], `${entry}: discovery name`); + assert.match(text, /^description: .+/m, `${entry}: discovery description`); + // Ignore code examples and external/anchor links. Sibling skill references + // must survive distribution, without depending on the source checkout. + const prose = text.replace(/^```[^\n]*\n[\s\S]*?^```/gm, ''); + for (const [, target] of prose.matchAll(/\[[^\]]*\]\(([^)]+)\)/g)) { + if (/^(?:[a-z]+:|#)/i.test(target)) continue; + const resolved = path.posix.normalize(path.posix.join(path.posix.dirname(entry), target.split('#')[0])); + assert.ok(files.has(resolved), `${entry}: unpackaged reference ${target}`); + } + } + console.log('Seven portable skill entrypoints; no duplicate commands; all skill references packaged.'); +} finally { + fs.rmSync(temp, { recursive: true, force: true }); +} diff --git a/skills/README.md b/skills/README.md index e4030a1..8d10af5 100644 --- a/skills/README.md +++ b/skills/README.md @@ -15,6 +15,17 @@ Procedures captured with `skillify`. Each one exists because reasoning about the |-------|--------------| | [`verify-responsive`](./verify-responsive/SKILL.md) | Render the real page at real viewport widths in fixed-width iframes, then drive and assert it from the parent. | +## On-demand workflows + +| Skill | Use when | +|-------|----------| +| [`pressure-test`](./pressure-test/SKILL.md) | Pressure-test a decision, or audit every approach proposed in the session when no target is supplied. | +| [`sidenote`](./sidenote/SKILL.md) | Park a thought without acting on it, or list open notes when no thought is supplied. | +| [`visualize`](./visualize/SKILL.md) | Draw the verified structure of code or a flow; no input means the current topic. | +| [`wrap`](./wrap/SKILL.md) | Decide whether a session can end and prepare a durable handoff; no input means the whole session. | + +These are the canonical instruction sources. Claude Code exposes them as slash commands directly, so there are no duplicate command wrappers. Inputs come from the invoking message in any client; the substantive procedures and authorization boundaries are the same. + ## The decision test Behind every choice these skills make — *should I skillify this? generalize how far? merge or keep separate?* — is one question: @@ -36,22 +47,21 @@ The library is only as valuable as the resolver is clean: ## Install -These are standard [Claude Code Agent Skills](https://code.claude.com/docs/en/skills) — a directory with a `SKILL.md`. The `name` + `description` frontmatter is portable to any harness that reads skills (Cursor, Codex, OpenClaw). +Use the plugin manager for [Claude Code or Codex](../README.md#install). Both discover all seven skills from this directory. Claude Code also exposes `/greybeard:`; Codex offers `$greybeard:` through its skill selector and can match plain-language requests. Restart the client after a plugin update and verify each capability appears once in a fresh session. + +The standalone installer writes guidelines for Codex, manages the Claude Code plugin, and copies all seven skills for OpenClaw. Writing `AGENTS.md` alone does not install skills. See the [installation and update instructions](../README.md#install) for the distinction. -**Claude Code** installs them as part of the greybeard plugin, through its own plugin manager — no copying, and `claude plugin update` keeps them current: +For a **manual, project-local Codex installation**, run this from the Greybeard checkout, replacing the destination with your project path: ```bash -claude plugin marketplace add clawnify/greybeard -claude plugin install greybeard@greybeard +mkdir -p /path/to/project/.agents/skills +cp -R skills/skillify skills/check-resolvable skills/verify-responsive \ + skills/pressure-test skills/sidenote skills/visualize skills/wrap \ + /path/to/project/.agents/skills/ ``` -(`npx @clawnify/greybeard` runs those two for you.) Don't also copy the directories into `~/.claude/skills/` — that puts two copies of every skill in the resolver, which is the exact thing `check-resolvable` exists to catch. +Copy all seven sibling folders together so relative skill links keep working after installation. Other clients need their own documented skill directory. Use either a manual copy or the plugin for a given client, not both. In clients without automatic skill indexing, add one entry per skill to the project's resolver, pointing to its installed `SKILL.md`. -**Any other harness** reads skills from a directory, so copy them in: - -```bash -mkdir -p ~/.claude/skills -cp -R skillify check-resolvable verify-responsive ~/.claude/skills/ # or .claude/skills/ for one project -``` +## Verify discovery after changing the package -Then add a one-line entry for each to your project's resolver (`AGENTS.md` / `CLAUDE.md`) so the agent — and your teammates — can find them. After that, just say *"skillify this"* when you finish something worth keeping. +Check a fresh install and an update from the previous revision using each client's plugin manager. Repeating the install must not add another entry. In Codex, query the app server's `skills/list` for a clean project and verify the seven enabled `greybeard:*` entries point into the installed plugin cache. In Claude Code, `claude plugin details greybeard@greybeard` must list seven skills once each; also check slash invocation with and without input. Inspect installed relative links, then run `check-resolvable` across the seven descriptions and procedures. Source frontmatter validation alone does not prove discovery. diff --git a/commands/pressure-test.md b/skills/pressure-test/SKILL.md similarity index 96% rename from commands/pressure-test.md rename to skills/pressure-test/SKILL.md index 735bb19..eeb32f8 100644 --- a/commands/pressure-test.md +++ b/skills/pressure-test/SKILL.md @@ -1,9 +1,12 @@ --- -description: Pressure-test the current approach against scalability, long-term, and efficiency, then recommend the best option. +name: pressure-test +description: "Pressure-test the current approach against scalability, long-term, and efficiency, then recommend the best option. Use when the user asks to pressure-test a decision or audit the session's approaches." argument-hint: [decision or approach to test — optional] --- -Run the decision test on **$ARGUMENTS** — or, if that's empty, on every solution this conversation has proposed. +The optional input is the text supplied with this skill invocation, through a slash command or a plain-language request. If none was supplied, follow the no-input behavior below. + +Run the decision test on **the supplied input** — or, if that's empty, on every solution this conversation has proposed. **With no argument, sweep — don't zoom.** The targeted form asks *is this the right call?* about one decision; the no-argument form asks *did we miss anything?* about all of them. Same evidence standard, same ledger — a wider surface, not a softer test. diff --git a/commands/sidenote.md b/skills/sidenote/SKILL.md similarity index 83% rename from commands/sidenote.md rename to skills/sidenote/SKILL.md index 16b4c39..deba093 100644 --- a/commands/sidenote.md +++ b/skills/sidenote/SKILL.md @@ -1,9 +1,12 @@ --- -description: Park a passing thought as a later-task without derailing the current one — logged, not acted on. +name: sidenote +description: "Park a passing thought as a later-task without derailing the current one — logged, not acted on. Use when the user asks to park a thought, sends SIDENOTE:, or wants to list parked notes." argument-hint: [thought to park — optional] --- -Park this thought — **$ARGUMENTS** — as a sidenote. A sidenote is a *later-task*, not a *now-task*. Your job is to record it and keep going, nothing more. +The optional input is the text supplied with this skill invocation, through a slash command or a plain-language request. If none was supplied, follow the no-input behavior below. + +Park this thought — **the supplied input** — as a sidenote. A sidenote is a *later-task*, not a *now-task*. Your job is to record it and keep going, nothing more. **The contract — hold it exactly:** @@ -28,4 +31,4 @@ Park this thought — **$ARGUMENTS** — as a sidenote. A sidenote is a *later-t Then: **one-line acknowledgement** (e.g. `Parked in the sidenotes file — continuing.`) and **resume exactly where you left off**, as if the note had never arrived. -**If `$ARGUMENTS` is empty** (a bare `/sidenote`), there's nothing to park — treat it as a *flush*: read the parking file (same location as above; if a legacy `.claude/sidenotes.md` also exists at the project root, read that too and say so, so its entries can be moved) and list the **open** entries back to me so I can decide what to pick up. Open means *not checked off* — every entry except the ones marked done (`- [x]`), so older bullets without a checkbox still count. Change nothing, act on nothing, then resume. (Checking an item off to `- [x]` happens when it's actually handled — not part of parking or flushing.) +**If no input was supplied** (a bare `/sidenote`), there's nothing to park — treat it as a *flush*: read the parking file (same location as above; if a legacy `.claude/sidenotes.md` also exists at the project root, read that too and say so, so its entries can be moved) and list the **open** entries back to me so I can decide what to pick up. Open means *not checked off* — every entry except the ones marked done (`- [x]`), so older bullets without a checkbox still count. Change nothing, act on nothing, then resume. (Checking an item off to `- [x]` happens when it's actually handled — not part of parking or flushing.) diff --git a/skills/verify-responsive/SKILL.md b/skills/verify-responsive/SKILL.md index 986e5f5..9ce5e62 100644 --- a/skills/verify-responsive/SKILL.md +++ b/skills/verify-responsive/SKILL.md @@ -71,4 +71,4 @@ So a layout that branches on width is covered honestly. One that branches on `@m ## Related -- [`/visualize`](../../commands/visualize.md) draws the *structure* of the code. This renders the *running UI*. Use this one when the question is "what does it actually look like at this width." +- [`/visualize`](../visualize/SKILL.md) draws the *structure* of the code. This renders the *running UI*. Use this one when the question is "what does it actually look like at this width." diff --git a/commands/visualize.md b/skills/visualize/SKILL.md similarity index 90% rename from commands/visualize.md rename to skills/visualize/SKILL.md index 8f07123..ca49e91 100644 --- a/commands/visualize.md +++ b/skills/visualize/SKILL.md @@ -1,9 +1,12 @@ --- -description: Draw the thing under discussion — the real shape, from the real code, anchored to file:line. +name: visualize +description: "Draw the thing under discussion — the real shape, from the real code, anchored to file:line. Use when the user asks to visualize code, architecture, or a flow; use verify-responsive to check a running UI at a viewport width." argument-hint: [what to visualize — optional] --- -Show me **$ARGUMENTS** visually — or, if that's empty, whatever is currently on the table in this conversation. Skip the preamble, keep the prose short, and pick the *smallest* view that makes the point. +The optional input is the text supplied with this skill invocation, through a slash command or a plain-language request. If none was supplied, follow the no-input behavior below. + +Show me **the supplied input** visually — or, if that's empty, whatever is currently on the table in this conversation. Skip the preamble, keep the prose short, and pick the *smallest* view that makes the point. **Draw what's there, not what you'd expect to be there.** A diagram launders a guess better than prose ever could: boxes and arrows read as *verified* even when nobody opened the file. Prose hedges out loud ("it probably calls…"); a flowchart just asserts. That makes an ungrounded visual the most expensive thing you can hand someone — they'll build on it for weeks. diff --git a/commands/wrap.md b/skills/wrap/SKILL.md similarity index 91% rename from commands/wrap.md rename to skills/wrap/SKILL.md index d66f87a..045b3db 100644 --- a/commands/wrap.md +++ b/skills/wrap/SKILL.md @@ -1,9 +1,12 @@ --- -description: Rule on whether this session can end here — finish the loop now, or make the work durable enough that another agent can pick it up. +name: wrap +description: "Rule on whether this session can end here — finish the loop now, or make the work durable enough that another agent can pick it up. Use when the user asks to wrap up, hand off, or decide whether this session or worktree can be closed." argument-hint: [what to wrap — optional] --- -Answer one question about **$ARGUMENTS** — or, if that's empty, about this whole session: **can I close this and delete the worktree?** +The optional input is the text supplied with this skill invocation, through a slash command or a plain-language request. If none was supplied, follow the no-input behavior below. + +Answer one question about **the supplied input** — or, if that's empty, about this whole session: **can I close this and delete the worktree?** There are two rulings, and you owe me exactly one of them: **finish it now**, or **wrap it** — turn what's here into something durable and tell me it's safe to delete. "Mostly done, maybe keep it around" is not a ruling — it is the third outcome, the one you get by declining to choose, and it is the most expensive of the three: a worktree nobody will reopen and nobody dares delete.