For coding agents
Two skills ship in the repo, so a session that has never seen scruff drives it correctly the first time. What is in them, what they refuse to do, and how to install them.
scruff is a CLI with a frozen JSON contract and six exit codes that each mean a
different recovery, which is already a shape an agent drives well. The gap is
knowledge: a session on a stranger's machine has never heard of scruff park,
so when their human says "stash this" it reaches for git stash and pops
somebody else's work into a tree that never asked for it.
Two skills close that gap. Both live in the repo and both are ≤150 lines, because a skill nobody loads is a skill nobody has.
| teaches | |
|---|---|
ai/SKILL.md | the lifecycle: the verbs, the six exit codes, the --json fields, and when the right answer is to do nothing |
ai/handoff/SKILL.md | the one thing with no verb: how to write a brief a cold session can act on, ending on the clipboard or in scruff spawn --prompt-file |
What the lifecycle skill is actually for
Most of it is not a command list. scruff --help is the command list. The skill
spends its length on the three things an agent gets wrong:
- Never
git stashin a repo the user owns. The stash stack is shared across every worktree of a repo, so parallel agents pop each other's entries. The skill's owndescriptionsays this out loud, precisely so it loads on the word "stash". - Exit 2 is scruff working, not scruff failing. An agent that reads refused
for safety as an error and reaches for
git worktree removehas defeated invariant 2 from the outside. The skill says so twice. - The
--jsonpayload's traps.stateis a closed set,landed.verdict'sfreshdoes not meanyes,occupiedanddirtyare nullable withnullmeaning undetermined, andwarningsis the only channel a degraded run has. The JSON API is the long form.
It also carries the one instruction an agent on a Mac needs most: when you have to see a desktop change work, boot a lane's own headless macOS and drive that, rather than asking to take the screen its user is sitting at.
What handoff does, and where it stops
The lane it opens is scruff's unit and --prompt is scruff's flag; the brief is
that flag's argument, and an argument nobody knows how to write is a flag nobody
uses well. So the skill teaches the brief, and stops: no scheduling, no
supervision, no opinion about what the receiving agent then does.
It is the one skill here a person invokes by name (/handoff), and its
default ending is the harmless one: the clipboard. Spawning costs a branch,
a window and another agent's context, so it takes an explicit word. A skill that
spawned on an ambiguous ask would be the wrong kind of surprise.
Installing them
On Nix, the skills are their own derivation, so a machine can take them with no Go toolchain and no binary:
inputs.scruff.packages.${system}.scruff-skillIt lays out $out/scruff/SKILL.md and $out/handoff/SKILL.md, one directory
per skill, which is the family's own layout: link the directory somewhere your
client reads skills from and it is already called the right thing. Otherwise
copy the two files. They are plain markdown with YAML frontmatter, and every
skill-reading client (Claude Code, Codex, OpenCode) can load them as they are.
On a haus machine both are already installed, along with every other skill in the family.
The bar they are held to
Both are bound by the family's agent surface
standard:
at most 150 lines, no flag dumps, and a description that names the phrases a
user says rather than the features the tool has. A description written as a
feature summary is true, well written, and never loads.
The build enforces the mechanical half: it fails if the frontmatter is missing
or unterminated, if name: disagrees with the directory, or if the file passes
150 lines. Each of those produces a skill that installs, lists, and is never
loaded.
And every claim in them has to be runnable. The skills quote two of scruff's
four frozen contracts, --json output and exit codes, plus the command names
and flags, so a verb or a field that changes changes the skill in the same pull
request. They are not documentation that drifted; they are downstream consumers
of the freeze.