diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 81468cc..d68b3dd 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 and /visualize commands.", + "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.", "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 and /visualize commands. Pair with the npx installer for the always-on guidelines.", + "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.", "source": "./", "category": "productivity" } diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index ddf4a6e..317afa8 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 and /visualize commands.", + "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.", "author": { "name": "Clawnify", "url": "https://github.com/clawnify" diff --git a/README.md b/README.md index 4a69eb6..14a1377 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 three commands — [`/pressure-test`](#the-pressure-test-command), the decision test, [`/sidenote`](#the-sidenote-command), park-a-thought, and [`/visualize`](#the-visualize-command), draw-the-real-shape — 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 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. ## The Problems @@ -192,9 +192,9 @@ And the **practice skills** those two produce — procedures captured with `skil They're standard [Claude Code Agent Skills](https://code.claude.com/docs/en/skills) (portable to Cursor, Codex, OpenClaw). Install and usage: [`skills/README.md`](./skills/README.md). -## The three commands +## The four commands -Greybeard's slash commands are **`/pressure-test`**, **`/sidenote`** and **`/visualize`** — one guards the *quality* of a decision, one guards your *focus* while you make it, and one makes sure what you're shown is the code that's actually there. The skills and always-on guidelines back them up, but these are the three you'll reach for 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. ## The `/pressure-test` command @@ -238,6 +238,20 @@ cp commands/visualize.md ~/.claude/commands/ # personal, all projects Then `/visualize `, or a bare `/visualize` to draw whatever's currently on the table. +## The `/wrap` command + +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. + +```bash +mkdir -p ~/.claude/commands +cp commands/wrap.md ~/.claude/commands/ # personal, all projects +# or: .claude/commands/ for one project +``` + +Then 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. + ## Install **One command — every agent on your machine:** @@ -246,7 +260,7 @@ Then `/visualize `, or a bare `/visualize` to draw whatever's curr 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 `skillify` / `check-resolvable` / `verify-responsive` skills, the `/pressure-test`, `/sidenote` and `/visualize` commands, 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 `skillify` / `check-resolvable` / `verify-responsive` skills, the `/pressure-test`, `/sidenote`, `/visualize` and `/wrap` commands, 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 diff --git a/bin/install.js b/bin/install.js index 05d0298..2dc1d20 100644 --- a/bin/install.js +++ b/bin/install.js @@ -5,7 +5,7 @@ // // Detects the AI coding agents on your machine / in this project and installs // the Karpathy-inspired guidelines (+ Claude Code skills and the /pressure-test, -// /sidenote and /visualize commands) into each one's rule location. Pure Node +// /sidenote, /visualize and /wrap commands) into each one's rule location. Pure Node // stdlib, zero runtime deps. // // npx @clawnify/greybeard # install for every detected agent @@ -148,6 +148,8 @@ function rel(p) { return p.startsWith(HOME) ? '~' + p.slice(HOME.length) : path. 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']; +// Slash commands shipped to every provider that reads commands. Add a new one here only. +const COMMANDS = ['pressure-test', 'sidenote', 'visualize', 'wrap']; // ── Per-provider install / uninstall ──────────────────────────────────────── // The OpenCode plugin serves both `opencode` (V1) and `opencode2` (V2 beta): @@ -164,17 +166,13 @@ function installClaude(dir, un) { removeFenceFrom(path.join(dir, 'CLAUDE.md')); for (const s of SKILLS) removePath(path.join(dir, 'skills', s)); removePath(path.join(dir, 'commands', 'scalable.md')); // legacy name, pre-rename - removePath(path.join(dir, 'commands', 'pressure-test.md')); - removePath(path.join(dir, 'commands', 'sidenote.md')); - removePath(path.join(dir, 'commands', 'visualize.md')); + for (const c of COMMANDS) removePath(path.join(dir, 'commands', `${c}.md`)); return; } fenceInto(path.join(dir, 'CLAUDE.md'), PRINCIPLES); for (const s of SKILLS) copyDir(path.join(PKG, 'skills', s), path.join(dir, 'skills', s)); removePath(path.join(dir, 'commands', 'scalable.md')); // clean up the pre-rename command from prior installs - writeFile(path.join(dir, 'commands', 'pressure-test.md'), fs.readFileSync(path.join(PKG, 'commands', 'pressure-test.md'), 'utf8')); - writeFile(path.join(dir, 'commands', 'sidenote.md'), fs.readFileSync(path.join(PKG, 'commands', 'sidenote.md'), 'utf8')); - writeFile(path.join(dir, 'commands', 'visualize.md'), fs.readFileSync(path.join(PKG, 'commands', 'visualize.md'), 'utf8')); + for (const c of COMMANDS) writeFile(path.join(dir, 'commands', `${c}.md`), fs.readFileSync(path.join(PKG, 'commands', `${c}.md`), 'utf8')); } function applyProvider(p, un) { diff --git a/commands/wrap.md b/commands/wrap.md new file mode 100644 index 0000000..d66f87a --- /dev/null +++ b/commands/wrap.md @@ -0,0 +1,70 @@ +--- +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. +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?** + +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. + +**The test is not "is this important" — it's "what dies when the worktree dies, and can I afford to lose it?"** A worktree is a checkout. It is cheap to recreate and carries nothing by itself. Everything load-bearing either lives somewhere outside it or is about to be deleted. + +## First: is there a hard stop? + +Four things override every other consideration. If any holds, the ruling is **finish now** — no artifact substitutes, and "I'll open an issue for it" is how it ships broken. + +- **The world outside the repo is mid-change.** A migration ran against a shared database, a flag got flipped, a deploy started, a resource or credential was created or rotated, a backfill is half-applied. A ticket in a backlog does not un-break a shared system. Finish it *or revert it* — both close the loop; walking away closes neither. +- **You left the trunk worse than you found it.** Pushed something broken, merged half a revert, left CI red on `main`. That cost lands on whoever starts next, who has none of your context. +- **What's left is minutes of work.** A handoff has a fixed re-entry cost — rebuilding the context, re-reading the files, re-deriving the options you already rejected — and it is rarely under half an hour. If that exceeds the work remaining, wrapping is the *more* expensive choice. "It needs another session" is usually a pre-AI estimate (§5): price the real thing before you park it. +- **You can't write the brief.** If you can't say in a paragraph what's left and how the next agent would know it's done, you don't understand the state well enough to hand it off — and they will understand it less. Work until it's describable, then wrap. + +## Then: inventory what's actually here + +Look, don't recall. Run the checks and report what they said: + +- `git status --porcelain` — uncommitted edits *and* untracked files. Untracked is where the new file you never `git add`ed is hiding. +- `git log --oneline @{upstream}..HEAD` — commits that exist only on this machine. `fatal: no upstream configured for branch` is not a failure, it's the answer: the branch has never been pushed, so **all** of it is local — `git log --oneline --not --remotes` lists it. +- `git stash list` — the stack is shared across worktrees; an entry pushed from here outlives the worktree but loses the only person who knew what it was. +- Scratch files, notes, or outputs you wrote outside the repo. +- Anything still running that this session started. + +Then the item that never shows up in any of those, and is the reason most handoffs are useless: **the context.** What you tried that didn't work, why the obvious approach is wrong, the reproduction that took twenty minutes to find, the file you ruled out. The diff survives; that dies with the session. It is the most expensive thing in the worktree and the only one with no automatic record. + +## The ladder — pick the cheapest form that actually carries it + +One artifact, not three. Match the form to what has to survive: + +| What's here | Where it goes | +|---|---| +| Nothing — merged, clean, no unpushed commits | Nowhere. Say so and close. | +| A lead or a hunch. No code, no decision | A `/sidenote` entry — it already lives in git's common dir, outside every worktree. | +| A decision, a design, knowledge the next change needs | A doc in the repo, committed **and pushed**. Memory is an index, not an archive (§7). | +| A defined next task, nothing written yet | A **GitHub issue**: title + the brief below. | +| Code exists and is incomplete | Commit it on the branch, **push it**, open a **draft PR** whose body is the brief. | + +Two notes on that last pair. A pull request needs at least one commit — there is no PR with an empty diff, so "a PR with just a description" is either an *issue*, or a PR whose diff **is** the brief committed as a doc. And once the branch is pushed, the branch is the artifact: deleting the worktree costs you nothing. Never delete a worktree whose branch is unpushed and unmerged — that is the one deletion that actually loses work. + +## The brief — the part the diff can't carry + +Whichever form you picked, the body is the same five lines, written for someone who was not here: + +``` +Goal — what this is for, in one line. +Done — what works now, and the check you actually ran to know it. +Left — the exact next step. Not "continue the refactor". +Rejected — approaches that don't work, and why. This is the part that dies with the context. +Verify — the command or check that says it's finished. +``` + +Anchor it: the `file:line` where the next agent starts reading. And keep it honest — if you never ran the test, "tests not run" goes in the brief. A caveat about your own work is an unmet success criterion (§4), not a footnote to bury; the next agent will trust this document instead of checking, exactly as you would. + +## Execute, verify, then answer the question + +1. **Show me the ruling and the artifact before you create it** — the form, the title, the body. Issues, PRs and pushes are outward-facing and awkward to take back; one confirmation, then go. +2. **Confirm it landed outside the worktree.** The push shows the branch on the remote; `gh issue create --title "…" --body-file …` and `gh pr create --draft --title "…" --body-file …` each print a URL — quote it. A commit that was never pushed is not a handoff, it is the same work in a smaller box (§4: it compiles is not it works). +3. **Don't run the deletion.** You are standing in the worktree; removing it from inside is how a session ends mid-sentence. Hand me the command — `git worktree remove `, run from another checkout — and say plainly if it needs `-f`, because a dirty tree means step 2 didn't finish. +4. **Close with the verdict on its own line**, because it's the question I asked: + - `Safe to close — carries it.` + - `Not yet — has to close here first.` + +**Where this sits next to `/sidenote`:** a sidenote parks a *thought* so the current task keeps its pace; `/wrap` rules on the *session*. An open sidenote never blocks a wrap — but if this branch was the only context that made one legible, fold it into the brief before the worktree goes. diff --git a/package.json b/package.json index f716c34..9ca6b64 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@clawnify/greybeard", "version": "0.3.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 and /visualize commands, installable across every AI coding agent.", + "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.", "license": "MIT", "homepage": "https://github.com/clawnify/greybeard", "repository": {