agentleFS
mfraunhofermfraunhofer/claude-skills/auto-wave/SKILL.md

auto-wave

Skill0 starsChanged 3 months agoMITView on GitHub

Sequential wave runner. Drives a queue of "waves" automatically, one after another, each wave as a FRESH headless `claude -p` process (empty context, so nothing piles up), branch isolated so nothing auto-deploys, with an exception stop: it holds only when a wave is not green or a real product decision comes up. A wave counts as green ONLY with proof (executed_tests > 0, no skips, a real proof artefact; a non-empty caveat is a stop signal), self-attestation counts as red. After a green run the end-of-run hook does everything UP TO the merge: push, open the PR, post a fresh code review, write a deploy handoff, notify, report. It NEVER merges and NEVER deploys. Use when the user says "/auto-wave", "run the waves", "start auto-wave", "work through the queue", "start the wave runner", "build the waves automatically". Mode "full" chains waves, pre-deploy and deploy behind one word, with a fixed abort list as the gate. NOT for planning a single wave, building a single issue, reviewing, or deploying on its own.

  • Commits and pushes

The file

Show its rules and text

We split this skill into the rules it gives an agent

17 rules. About 0 are common, 5 are distinctive, and 12 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈5

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 12

    Very specific

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

  • Common
  • Distinctive
  • Very specific
  • could be automatic: a setting could enforce it
  1. Distinctive:

    Hard reset: Every wave is a new claude process with an empty conversation.

    line 34
  2. Very specific:

    Proof of green instead of self-attestation: Every claude -p wave has to PROVE its green: executed_tests > 0, skipped_tests == 0, and proof …

    line 52
  3. Very specific:

    Research before blocked: Before a wave writes itself off as blocked (a self-fix fizzled, the same failure repeats, the fix goes in …

    line 65
  4. Very specific:

    The status file is the truth, but green needs proof: Every wave writes a wave-NN.status.json as its last action (green / blocked / …

    line 70
  5. Distinctive:

    Instead of build waves only, the queue can hold mixed, typed tasks: work that needs an exclusive resource, ops and infrastructure fixes, …

    line 96
  6. Very specific:

    Every entry is ## <id> plus fields:

    line 101
  7. Very specific:

    Frontend review (release chain step 2): If the diff touches UI paths (frontend_review_globs), a SECOND throwaway process goes at the …

    line 153
  8. Very specific:

    Staging instead of a deploy prompt: If deploy_queue_script is configured, the hook enters the run into that queue and ends there.

    line 177
  9. Very specific:

    Best-effort contract: if push, gh, a review or the handoff fails, that does NOT crash the run.

    line 183
  10. Very specific:

    Straight to --run, no dry run, no question: No plan preview for confirmation, no "say go" gate.

    line 257
  11. Very specific:

    Start the run in the background (long runtime, hours are possible).

    line 270
  12. Very specific:

    If the run stops (exit 2), relay the reason in plain language.

    line 273
  13. Distinctive:

    If all waves are through, the end-of-run hook has already pushed, opened the PR, posted the review comments, written the deploy handoff and …

    line 278
  14. Very specific:

    If push or PR failed (best-effort), name the branch and the log.

    line 281
  15. Distinctive:

    The abort list: Every hit stops the chain BEFORE the next production mutation and sends a push with the reason in plain language:

    line 311
  16. Distinctive:

    Anti-scope of the mode: no building, fixing or reviewing in the conductor chat itself (all of it in spawns), no scope beyond what was …

    line 351
  17. Very specific:

    When the call, the status protocol or the safety contract changes, update this SKILL.md and the README in the same pass.

    line 368

≈ “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

auto-wave

A queue of waves, driven sequentially and automatically. Every wave runs as its own, freshly started claude -p process. The runner itself is a deterministic Python script, no LLM in the driver: the intelligence sits in the per-wave processes it spawns.

It replaces the manual loop of "open a new chat after every wave and paste the next one in". auto-wave : wave-planning behaves like a loop runner to a single build step, one level above building, at wave granularity rather than issue granularity.

Why a fresh process per wave

This is the whole point: context resets at every wave and does not pile up over N waves. Wave 10 is as sharp as wave 1. Four layers, all enforced in the wave prompt:

  1. Hard reset. Every wave is a new claude process with an empty conversation. At the start it reads only what is curated: its issue specs, the project plan, the relevant rules files, the project context file, the previous wave's handover.
  2. Heavy reading in throwaway sub-agents. Searching, reading many files, reviewing all happen in Explore / general-purpose / code-reviewer sub-agents; only their conclusion comes back.
  3. A one-page handover instead of a conversation history. The baton between waves lies on disk (handover file plus your project's living documents), not in a chat.
  4. Keep waves small. Queue discipline: one to two days of work per slice.

Safety contract (not negotiable)

  • Branch isolation and the merge stop line. The runner creates <branch_prefix>/<run-id> off the base branch and builds ONLY there. Never merge into the base branch. Never push to it. Never deploy. ALLOWED: pushing the feature branch to origin and opening a PR, because neither triggers a production deploy in the usual setup where only a merge into the default branch deploys. For the runner itself the rule stays: never gh pr merge.
  • Proof of green instead of self-attestation. Every claude -p wave has to PROVE its green: executed_tests > 0, skipped_tests == 0, and proof pointing at an existing, non-empty artefact (real test runner output, wave-NN.proof.txt). The runner (enforce_green_proof in run.py) demotes green without proof to blocked (exception stop) and PERSISTS that demotion into the status file, so a resume does not count the wave as green either. A non-empty caveat field is a stop signal, not prose, on every path including typed tasks. The origin is measured, not theoretical: a wave once wrote green with 0 executed tests and an honest caveat in the JSON that no parser read.
  • Exception stop. The run goes through on its own and holds by itself only when: a wave does not turn green despite self-fixing (blocked), OR a real product, design or strategy decision comes up (needs-decision, because a human decides product calls, never the AI), OR the state is unclear (no status file, timeout). On a stop it names the branch and the run log and exits 2.
  • Research before blocked. Before a wave writes itself off as blocked (a self-fix fizzled, the same failure repeats, the fix goes in circles), the prompt tells it to STOP rather than guess the next fix: put an adversarial research sub-agent on an ALTERNATIVE cause first ("do NOT confirm my assumption"), work the finding in, and only then, if it still does not hold, write blocked.
  • The status file is the truth, but green needs proof. Every wave writes a wave-NN.status.json as its last action (green / blocked / needs-decision). Missing means stop, never drive on blind. The status file is the truth about what the wave CLAIMS; the proof check is the truth about whether that counts. After a green wave the runner additionally attaches the commit hash as a commit field (for the PR body and the report); the wave does not write that field itself.
  • Sequential, one worktree. Waves run one after another on ONE branch. That is a deliberate choice against parallel worktrees: a shared checkout has one HEAD, and a second build stealing it mid-wave is a failure mode that costs more than the concurrency wins.

The queue

One ## <slug> section per wave, in build order. Template: queue.example.md.

## backend-add-service-form
goal: Backend form to add and edit a service          # MANDATORY, one sentence
specs: .scratch/phase-2/                              # optional, path to the issue specs
review: code-review                                   # optional, default from config.json

A wave with specs builds noticeably more precisely than one working off a goal sentence, so plan the issues first where you can.

Typed queue (solo / ops / gate + needs)

Instead of build waves only, the queue can hold mixed, typed tasks: work that needs an exclusive resource, ops and infrastructure fixes, and steps held for a human word, with ordering dependencies. One run drives all of it. The runner detects the mode automatically by the lane: field. Template: queue.typed.example.md.

Every entry is ## <id> plus fields:

  • lane: (mandatory) solo | ops | gate.
    • solo strictly serial, for tasks that need an exclusive resource (one shared test database, one device, one licence seat), so never two at once. Before each one the runner brings the shared checkout onto a clean base best-effort; uncommitted tracked work on a foreign branch stops the run instead of being clobbered.
    • ops a headless claude -p that reads and executes the spawn file. Serial by default, which is the safe answer. Concurrent only opt-in (parallel: true) and only when ops_parallel_isolated is on in config.json. Reason: a shared checkout has one HEAD. The win of this runner is hands-off, not concurrency; do not over-promise it.
    • gate never runs automatically. The runner holds, pushes a notification "ready for your word: <note>" and writes a report. Gates are deferred to the end of the run (after all solo and ops work) and reported as "ready" or "needs still open". The deploy is the typical one.
  • spawn: mandatory for solo and ops (absolute or project-relative path to the spawn file, which has to exist, otherwise the run stops hard BEFORE it starts). Optional for a gate.
  • needs: optional. The id of another task; this one runs only once that one is green (a needs DAG, topologically resolved and enforced). A non-gate entry may not depend on a gate: gates never run, so it would block forever, and validation refuses it.
  • parallel: optional (ops only). See ops_parallel_isolated.
  • note: optional free text, mostly for a gate: what your word triggers here.

Validation BEFORE the run (a hard stop on any violation): known lane, existing spawn file for solo and ops, needs pointing at an existing id, no self-needs and no gate-needs, no duplicate ids, no needs cycle, parallel on ops only.

Runner behaviour: resolve the needs order, drive solo and ops in plan order, and every task writes ITS own report (from its spawn file) plus a task-<id>.status.json as its last action. The runner adds a collected report, RUN.md, PROGRESS.md and a notification. Exception stop unchanged. A typed run deliberately does not create a shared branch and does not open a collected PR: every task manages its own git and PR through its spawn file, and the gate entry refers to the PRs that are already open.

End-of-run hook (everything UP TO the merge, never the merge itself)

Runs only when ALL waves are green (a full run or a resume to the end; not for --only single-wave tests, not after a stop).

  1. Commit check. Does the branch have commits ahead of the base? At 0 (every wave a no-op) there is no push and no PR; the log and the report note "no changes, nothing to merge".
  2. Push: git push origin <branch_prefix>/<id>, only the feature branch, never the base.
  3. PR: gh pr create, title auto-wave <id>: <N> waves, body one line per wave out of its status.json (summary plus commit hash), ending in the do-not-merge warning. If the PR already exists (a resume), it is reused instead of duplicated. If BOARD_CARD is set, the resolved card reference goes into the body as an anchor (see "Board card" below).
  4. Fresh review (release chain step 1). The WHOLE PR diff goes to ONE throwaway claude -p process with a fresh context, deliberately NOT the build context. Findings with a [HIGH] / [MEDIUM] / [LOW] prefix are posted as a PR comment; high findings are marked separately in the comment, the notification and the report.
  5. Frontend review (release chain step 2). If the diff touches UI paths (frontend_review_globs), a SECOND throwaway process goes at the running stack: boot the app, click the touched surfaces for real. This is the class of check that catches a dead first-run path which green unit tests walk straight past. Findings go up as their own PR comment and high findings count like review highs. No UI in the diff means the step is skipped as n/a. Mobile is mandatory, not a bonus: the same surfaces are checked at the widths in frontend_review_widths (default 390, 375, 430 CSS pixels; the narrowest is your supported floor, anything below is out of scope). Four measured things instead of a feeling: no horizontal overflow when a LONG name is used instead of a short one · tap targets do not vanish under a dialog, a footer or the keyboard · sticky headers stay visible while scrolling · text is not squeezed into a few pixels. Screenshots land in the run's state directory. A pre-existing defect that also reproduces on the base branch is named AND marked as pre-existing, so it does not block the release by mistake.
  6. Deploy handoff. Once the PR is open the hook writes a finished, deterministic (no LLM) handoff to state/<id>/SPAWN-deploy.md: a start line, the release-chain gate (mandatory before the merge: code-review comment present · frontend-review comment present or n/a · every [HIGH] fixed and RE-reviewed · key-function tests really executed with proof artefacts), the scope detected from the PR diff through deploy_handoff.scope_globs, and the forced order (backup, ONE human go, schema and server functions, merge = frontend LAST, verify), stop at any deviation, plus a mandatory closing report. This is a briefing, nothing else. auto-wave still merges and deploys NOTHING. On a stop or a no-op run, no handoff is written, because there is nothing to deploy.
  7. Staging instead of a deploy prompt. If deploy_queue_script is configured, the hook enters the run into that queue and ends there. Push, PR and both reviews stay unchanged (a PR is not a deploy, and without a PR there would be no review comments). What falls away is the "reply deploy, it goes live" line. Reason: collecting several finished runs into ONE review round and ONE deploy beats deciding once per run.

Best-effort contract: if push, gh, a review or the handoff fails, that does NOT crash the run. Errors land in state/<id>/end-of-run.log and in the report, and the branch stays usable locally.

A report at EVERY end of a run (green OR stop, including --only): <project_root>/.scratch/pm-inbox/<YYYY-MM-DD-HHMM>-auto-wave-<run-id>.md with front matter (topic / issue / pr / status: done|blocked / worktree) and, per wave, ✅ or ✋ plus the summary, the branch, the PR number and link, whether the review found anything high. That is the same inbox the pm skill reads.

Teardown at EVERY end (green, stop, crash; it hangs on atexit, not on the success path): teardown_local_stack() stops the containers matched by teardown_docker_filter again. docker stop, never docker rm, so no data loss. What a run brings up does not keep running afterwards. Switch it off with "teardown_after_run": false.

Board card (optional adapter)

The runner knows nothing about any board. If the env var BOARD_CARD is set, it looks for an executable adapter at <project_root>/scripts/board-card and calls it best-effort:

scripts/board-card find "<query>"                      -> prints ONE card reference
scripts/board-card built "<card>" --pr <n> --url <u> --branch <b>

find resolves whatever you put in BOARD_CARD (an id, a short link, a title query) to the stable reference that goes into the PR body. That anchor matters: a board watch can only couple a card to a PR through a reference in the title, the body or the branch name, because that is the only coupling that is a measurement rather than an interpretation. built moves the card to whatever "built, waiting to be tested" means on that board. Board id, credentials, column names and label vocabulary all live in the adapter, where the board lives. A project without an adapter gets one line and is done. That is not an error: a board being down is not a build failure and must never cost a green run. (Same cut as the board watch in the pm skill.)

Preconditions (before every run)

  • claude CLI on PATH and logged in.
  • The repository is on the base branch and has no uncommitted tracked changes (untracked is fine). The runner refuses otherwise.
  • The queue file exists. Templates: queue.example.md, queue.typed.example.md.
  • config.json points project_root at your project. Everything else has a working default.

Calls

python3 ~/.claude/skills/auto-wave/scripts/run.py --status     # queue plus last run
python3 ~/.claude/skills/auto-wave/scripts/run.py --dry-run    # plan, branch, wave-1 prompt, do NOTHING
python3 ~/.claude/skills/auto-wave/scripts/run.py --run        # real run (create the branch, drive the waves)
python3 ~/.claude/skills/auto-wave/scripts/run.py --run --name <id> --from <N>   # resume after a stop, from wave N
python3 ~/.claude/skills/auto-wave/scripts/run.py --run --only <N>               # wave N only (no push, no PR)

--config <path> loads an alternative config file, which is what a sandbox test uses.

Progress: notifications plus PROGRESS.md (wave level)

The runner reports at every wave boundary, deliberately at wave granularity only, with no sub-wave steps (anything finer is spam):

  • A notification through notify(title, message): a desktop banner (macOS osascript, fallback terminal-notifier) and, if ntfy_topic is configured, a phone push. Both fire independently and best-effort, so they NEVER crash the run. Exactly ONE notification per boundary: a wave turning green, the run finishing (with the PR number and the handoff path, or a warning when the review found something high, or "no changes, nothing to merge"), and, most important, the run stopping with the reason in the text.
  • A live checklist at <state_dir>/<id>/PROGRESS.md, rewritten at every boundary: one line per wave, done - [x] … ✅ green (HH:MM), running ▶ running (since HH:MM), stopped ✋ stopped: <reason>, upcoming without a suffix. On a resume (--from N), waves with a green status file from the earlier partial run count as done. It is readable from any other chat, because it lives on disk.

How YOU (Claude) drive a run

  1. Straight to --run, no dry run, no question. No plan preview for confirmation, no "say go" gate. The only hard gate is the preconditions the runner checks itself (on the base branch, clean tree, queue not empty); it refuses with a clear message when something is missing, and only then do you relay to the user instead of building blind. --dry-run and --status stay available as manual tools when they are explicitly asked for, never as the default. The exception is BUILDING the queue: whoever assembles the queue asks which worker model the waves should run on, as multiple choice with a recommendation, and the recommendation depends on the work rather than defaulting to the strongest model everywhere. Heavy or risky waves (schema, permissions, anything close to production) deserve the strongest one; simpler waves (UI, content, docs) do not. The answer goes into config.json as "model" and applies to the WHOLE run, so a mixed queue is better split into two runs. The start itself stays question-free.
  2. Start the run in the background (long runtime, hours are possible). Tee it into a durable log: the state on disk (<state_dir>/<id>/RUN.md) is readable at any time through --status, including from another chat.
  3. If the run stops (exit 2), relay the reason in plain language. For needs-decision, put the question to the user as a multiple-choice question with a recommendation, work the answer into the wave (or extend the specs) and continue with --from N. The runner has already dropped a status: blocked report in the inbox, and there is no push and no PR after a stop.
  4. If all waves are through, the end-of-run hook has already pushed, opened the PR, posted the review comments, written the deploy handoff and filed the report. You relay: the PR number and link, whether the review found anything high, and the handoff path. If push or PR failed (best-effort), name the branch and the log; the branch is usable locally. Never merge (gh pr merge) and never deploy yourself.

Mode "full": the whole chain behind one word

No new runner. The mode chains what already exists: an auto-wave run (this skill), then a pre-deploy step as its own spawn, then your deploy skill. The green path without "full" is byte-unchanged; new are this section and scripts/full-lock.sh.

Trigger: the user says "full auto-wave" in a fresh chat.

The contract

  1. The invocation IS the deploy go, given in advance and conditioned on the abort list below. The ONE human go your deploy procedure demands before the first production mutation counts as given by the invocation, AS LONG AS nothing on the abort list hit. Outside a full run, your normal per-deploy go stays exactly as it was.
  2. Conductor principle. The chat never works inline: waves run as fresh headless processes anyway, pre-deploy runs as its own spawn, and the deploy runs through your deploy skill as another spawn. Handovers happen only through files (queue, handoff, inbox). The conductor reads end reports, never diffs or logs in full, which is what keeps its context from filling up.
  3. Scope per run, measured rather than guessed. A preflight measures the real state: open queue waves (run.py --status) plus every merge-ready staged PR (gh pr list, gh pr checks). Everything green that is not blocked, parked or needs-decision comes along. What cannot come this time stays staged and joins the next run automatically.
  4. Review findings are a hard gate. Fix in the PR branch first, re-run the gates with proof, re-verify the finding in the same medium, then continue. Not autonomously fixable (a product decision, a production-data touch, a guardrail) means a needs-decision stop. It is NEVER deployed around an open finding.
  5. The abort list. Every hit stops the chain BEFORE the next production mutation and sends a push with the reason in plain language:
    • a gate that is not green with proof (executed > 0, 0 skipped); self-attestation is red
    • needs-decision, or a product decision of any kind
    • a schema change or a function deploy that is not in the handoff
    • a smoke test after the deploy that is not green: roll back, then stop
    • a test-infrastructure-only PR (no deploy artefact): merge only, never deploy
  6. Every end is reported: a push in plain language (on a stop, the question itself, not just "stopped"), a PM inbox report, board cards pulled forward best-effort. Nothing is left running, and the lock is ALWAYS released, including on a stop or a crash.
  7. Never two full runs at once. Lock through scripts/full-lock.sh acquire (atomic mkdir; the lock path comes from AUTO_WAVE_LOCK). A fresh lock holding means stop with a message instead of a second run; a lock older than 24 hours is reported as stale and may be taken over after checking that nothing is really running. Same rule as "never two deploys of the same target".

Conductor protocol

  1. Lock: bash ~/.claude/skills/auto-wave/scripts/full-lock.sh acquire. Refused means stop, with the lock age in the message. From here on, releasing the lock belongs to EVERY ending.
  2. Preflight (contract point 3): measure the scope, write it down as a run note (what comes along, what stays behind and WHY). If the user is away from the machine, keep the machine awake for the duration of the run.
  3. Step A, waves: queue not empty means run.py --run in the background (the section above applies unchanged, including the end-of-run hook). Queue empty means the step is skipped. A stop of the runner is an abort-list hit, so the chain ends there: no pre-deploy, no deploy.
  4. Step B, pre-deploy as its own spawn: a fresh headless process runs the pre-deploy convention over the COMPLETE staged batch (including the fresh auto-wave PR): preflight against the forge, ONE collected review, the findings gate (point 4), the deploy handoff, board and inbox. The conductor then reads ONLY the handoff and the report.
  5. Step C, deploy: your deploy skill with the most recent handoff, as its own spawn. The human go is given in advance by the invocation (point 1) and the spawn is told so explicitly. ONLY what is in the handoff gets deployed; the smoke test afterwards is mandatory, and red means roll back and stop.
  6. The end (point 6): push in plain language, the conductor's own report (waves ✅/✋, pre-deploy ✅/✋, deploy ✅/✋/skipped, PRs, what went live), board cards, teardown, and full-lock.sh release.

Anti-scope of the mode: no building, fixing or reviewing in the conductor chat itself (all of it in spawns), no scope beyond what was measured, no deploy around the abort list, no second full run next to a running one.

Anti-scope (what the runner does NOT do)

It does not merge into the base branch (never gh pr merge), does not push to it, does not deploy, does not make a product decision, and does not skip a wave when things are unclear. (Pushing the feature branch, opening the PR, posting the review comments and writing the handoff IS the end-of-run hook's job, and that is allowed, see the safety contract. The handoff is a briefing, not a deploy.) The per-wave review (review: field) is done by the wave itself; the end-of-run fresh review is an ADDITIONAL independent instance with fresh eyes. Planning the waves is a different job: a wave without specs plans minimal issues for itself at the start, but well-specified specs give noticeably better results.

Self-maintenance

When the call, the status protocol or the safety contract changes, update this SKILL.md and the README in the same pass. Findings from real runs (what breaks, what the user corrects) get appended here.

Learnings from real runs

  • Collision with a parallel build in the same checkout. The runner owns git_repo_subdir exclusively (one HEAD, one working tree). If ANOTHER build runs in the same checkout at the same time, its git checkout or rebase tears HEAD away and the running wave builds on the wrong branch or commits into foreign work. Symptom: after --run, git branch --show-current shows a FOREIGN branch instead of the wave branch. Fix: give the run its own worktree instead of the shared checkout (git worktree add, symlink the dependency directory, and a custom config with "git_repo_subdir" pointing at it plus --config <path> --run). Both builds then share only the .git objects, never HEAD. Numbers that have to be unique across branches (migration numbers, for instance) must be coordinated by hand across the parallel branches, because each branch only sees the remote base and both would otherwise grab the same next number.
  • A background run can die silently. A run started in the background was killed externally while it blocked on its wave-1 worker: NO timeout (the wave timeout was hours away), NO exit status to the caller, NO RUN.md or status.json written. Symptom: no process, PROGRESS.md still says "wave 1 running", the branch exists with 0 commits, but the wave-1 files sit in the working tree as uncommitted tracked changes, because the killed worker had already edited and never committed. Diagnose first: smoke-test a headless claude -p separately, so you know whether the nested worker is the cause at all. Recovery is a fresh start, not a resume (0 commits means there is nothing to resume): check out the base branch, discard the half-finished, unreviewed worker diff (a diff out of a killed process has not earned any trust, and the value of this runner is the verified, reviewed, committed result), delete the 0-commit orphan branch, verify a clean tree and start again. On the restart, tee into a durable log, because a harness's temporary output can be cleaned up when it dies.
  • A queue can be older than the repository. A wave once found that its issue had already been merged and verified that instead of blindly rebuilding it. Good behaviour, keep it. The consequence is for whoever WRITES the queue: check every issue against the repository state first (git log --all --grep=<ref>, gh pr list --state merged), because a status file can lag behind.

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.