From 8a5b710f6e2ac754c76c058029d20a591a8b1e19 Mon Sep 17 00:00:00 2001 From: pallaoro Date: Fri, 11 Sep 2026 13:29:04 +0200 Subject: [PATCH] feat(wrap): /wrap rules on whether a session can close, or hands it off MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The end-of-session question — can I close this and delete the worktree? — gets answered by feel, and both failure modes cost: closing on an unpushed branch or an hour of dead ends that only lived in the context, or leaving half-finished worktrees nobody dares delete. /wrap forces one of two rulings: finish it now, or wrap it into something durable and say it's safe to delete. The test is what dies when the worktree dies, not what feels important. Four hard stops force finishing (the world outside the repo is mid-change, the trunk is worse than you found it, what's left is minutes of work, or you can't write the brief). Otherwise it picks the cheapest durable form that carries the work — sidenote, committed doc, issue, or pushed branch plus draft PR — writes a five-line brief including the approaches already rejected, confirms the artifact landed outside the worktree, and ends on a verdict line. A PR needs at least one commit, so "a PR with only a description" is either an issue or a PR whose diff is the brief committed as a doc; the ladder routes accordingly. Installer: the three hardcoded command copies become a COMMANDS array, mirroring SKILLS, so the next command is a one-word edit. --- .claude-plugin/marketplace.json | 4 +- .claude-plugin/plugin.json | 2 +- README.md | 22 +++++++++-- bin/install.js | 12 +++--- commands/wrap.md | 70 +++++++++++++++++++++++++++++++++ package.json | 2 +- 6 files changed, 97 insertions(+), 15 deletions(-) create mode 100644 commands/wrap.md 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": {