agentleFS
WarshoowWarshoow/afk.sh/skills/afk-spec/SKILL.md

afk-spec

Skill3 starsChanged 44 days agoMITView on GitHub

Turns an app idea into a repo afk can work on alone: stack, docs/spec.md with a proving command per criterion, skeleton, CI, .afk.env, milestones. Once, before the first wave.

  • Reads credentials
  • Commits and pushes

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    After that, /afk-wave and /afk-merge loop with nobody watching.

    line 11
  2. Very specific:

    Before mattpocock-skills 1.3, the first writes docs/agents/triage-labels.md without always creating the labels on GitHub, and /afk-wave's …

    line 135

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

/afk-spec

An idea is not executable. This skill makes it executable: a repo that starts, a gate that passes, and a list of criteria where each one names the command that proves it. After that, /afk-wave and /afk-merge loop with nobody watching.

It is the only step of the loop worth reviewing awake: it picks the stack for everything else, and it writes the only judge the loop will ever have.

The rule that holds up all the rest

docs/spec.md is written here and never changes again. The later waves are only allowed to check boxes — not to add, not to reword, not to remove a criterion. If the spec turns out wrong after the tag, a human fixes it, re-tags, and says so.

Otherwise the loop declares itself the winner all by itself: whoever writes the criteria and whoever fills them are the same model. It is the only failure mode that shows up nowhere in the summary.

1 — The idea, and what it excludes

One sentence for what the app does. Then, explicitly, what it will not do: anything not in the spec will never be built, and that is deliberate — the agent will not catch an omission, it will invent.

Too big for a spec ("a Notion", "a CRM") → say so and propose the first slice that stands on its own. A loop over fifty criteria spends its nights piling up code nobody reviews.

2 — The stack

The most boring one that holds. Two constraints, in this order:

  • the gate needs no service already running. Each ticket runs in a throwaway worktree: a Postgres or a Redis started by hand, and every ticket dies red for a reason that is not its own. File-backed SQLite, in-memory server, fake client, or a service the gate starts itself (docker compose run --rm) — it is a wave-0 decision, not a detail.
  • the model knows it without looking things up. A niche stack costs one documentation session per ticket, every night.

One line of justification per choice, in the README.md. Nobody will reread it before six months.

3 — The criteria

The heart of the skill. A criterion is written like this:

- [ ] **A3** — `POST /tasks` with a title returns 201 and the created id.
      `pnpm vitest run tests/api/tasks.spec.ts -t "creation"`

Three parts: a stable number, the sentence, and the command that returns 0 when it is true. The test file does not exist yet: the path is an instruction for the ticket that will take this criterion.

The test, before writing anything: which command returns 0 if it is true, and non-0 otherwise? No answer → it is not a criterion, it is a wish. Rewrite it or drop it.

WishCriterion
"the user can create a task"POST /tasks returns 201, and the task shows up in GET /tasks
"the interface is pleasant"(not a criterion — see below)
"it is fast"GET /tasks over 1000 rows answers in under 200 ms
"errors are handled"POST /tasks without a title returns 400 and an {error} body

What no command judges — a layout, an animation, a tone — does not go in the spec. It gets handled later, by hand, outside the loop. A taste criterion in the spec blocks the loop forever or gets checked off blind.

Two traps in that command, both met on a real repo:

  • It runs from the repo root, on the host. /afk-merge runs it exactly as written, there. A stack whose tests only run in a container (or in a subfolder) needs a wrapper at the root — ./in-app npx jest … — or no box is ever checked and the loop stalls.
  • A name filter that matches nothing exits 0. jest -t, node --test-name-pattern, pytest -k: no test found, return code 0, the box gets checked with nothing behind it. Wrap the criterion so it fails unless at least one test ran and passed (./prove <file> "<name>", for example), and check the wrapper on a pattern that matches nothing before trusting it.

The first criterion is always the same: A0 — the app starts, with the command that proves it. It is the one that catches "every ticket is green and nothing runs".

Aim for 10 to 30 criteria. Below that, the spec does not describe an app; above it, slice the idea.

4 — The milestones

Group the criteria into ordered milestones, each one a thing that stands on its own ("the API answers", "you can log in", "the list screen"). A milestone is done when all its criteria are checked. /afk-wave never works two milestones at once.

A milestone only depends on the previous ones. If two milestones claim each other, it is one milestone.

## Milestone 1 — The API answers
- [ ] **A0** — …
- [ ] **A1** — …

## Milestone 2 — Persistence
- [ ] **A4** — …

5 — The skeleton

The minimum for A0 to pass and nothing else. No empty screen "for later", no utils/ folder with nothing in it: every file that exists here is a file an agent will believe it has to respect.

<A0's command>; echo "rc=$?"

rc=0 or the skeleton is not done.

6 — The rest of the apparatus

In this order, each one a prerequisite for the next:

/mattpocock-skills:setup-matt-pocock-skills   # docs/agents/issue-tracker.md, the labels
/afk-setup                                     # .afk.env, the proven gate

Without the first, afk.sh refuses to start. Without the second, the gate will be a pnpm monorepo's.

Before mattpocock-skills 1.3, the first writes docs/agents/triage-labels.md without always creating the labels on GitHub, and /afk-wave's gh issue create -l ready-for-agent fails on a missing label. Create those the repo lacks, whatever the version:

for l in needs-triage needs-info ready-for-agent ready-for-human wontfix; do gh label create "$l" 2>/dev/null; done

Then a CI that runs the same gate as VERIFY_CMD — it is what will verify the PRs, and /afk-merge merges nothing without it.

7 — Setting the markers

echo 'BASE_BRANCH="${BASE_BRANCH:-dev}"   # the loop lands on dev, never on master' >> .afk.env
git add -A && git commit -m "chore: spec, skeleton and gate"   # -a would skip the new files
git tag afk-spec                     # the spec's reference version
git branch dev && git push -u origin dev

BASE_BRANCH is not optional: without it the worktrees start from master and the PRs target it — every ticket would then ignore everything the previous waves delivered.

The tag is the guard: /afk-wave and /afk-merge compare docs/spec.md with git show afk-spec:docs/spec.md and refuse to run if anything other than boxes moved.

dev is the landing branch. Another name works (develop, …): an existing branch, named in BASE_BRANCH — afk.sh, afk-app.sh, /afk-wave and /afk-merge all read it there. master is never touched by the loop — you merge the landing branch yourself, awake.

Finally, one GitHub milestone per milestone, in order:

gh api repos/{owner}/{repo}/milestones -f title="Milestone 1 — The API answers"

That is where /afk-wave will hang its tickets. No extra state file: the spec carries the criteria, GitHub carries the tickets and the milestones, git carries the rest.

8 — Show, then wait

Show the spec and the stack, wait for approval. It is the only stopping point of the whole loop — after it, nobody reviews anything before you wake up.

What matters in that review: does the list of criteria, once all checked, describe the app you wanted? If not, it is now, not in three waves. Once approved, the next step is /afk-wave.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.