create-agent-rig 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +134 -0
- package/README.md +57 -9
- package/package.json +9 -2
- package/packages/cli/dist/lib/summary.js +19 -5
- package/templates/agent-os/stack/aws-cdk/.claude/rules/aws-cdk.md +46 -0
- package/templates/agent-os/stack/aws-cdk/.claude/skills/ro-debug/SKILL.md +117 -0
- package/templates/agent-os/universal/.claude/hooks/block-no-verify.mjs +12 -2
- package/templates/agent-os/universal/.claude/hooks/guard-bash.mjs +808 -0
- package/templates/agent-os/universal/.claude/queue.json +3 -0
- package/templates/agent-os/universal/.claude/rules/autonomy.md +43 -0
- package/templates/agent-os/universal/.claude/rules/invariants.md +169 -0
- package/templates/agent-os/universal/.claude/scripts/detect-missed-gate.mjs +489 -0
- package/templates/agent-os/universal/.claude/scripts/preflight.mjs +161 -0
- package/templates/agent-os/universal/.claude/scripts/queue/core.mjs +305 -0
- package/templates/agent-os/universal/.claude/scripts/queue/github-issues.mjs +231 -0
- package/templates/agent-os/universal/.claude/scripts/queue/index.mjs +175 -0
- package/templates/agent-os/universal/.claude/scripts/queue/jira.mjs +345 -0
- package/templates/agent-os/universal/.claude/scripts/queue/plan-md.mjs +239 -0
- package/templates/agent-os/universal/.claude/scripts/reconcile-external-prs.mjs +280 -0
- package/templates/agent-os/universal/.claude/scripts/stop-flag.mjs +62 -0
- package/templates/agent-os/universal/.claude/settings.json +4 -0
- package/templates/agent-os/universal/.claude/skills/loop/SKILL.md +297 -40
- package/templates/agent-os/universal/.claude/skills/new-invariant/SKILL.md +102 -0
- package/templates/agent-os/universal/.claude/skills/new-invariant/guard-invariant.example.mjs +78 -0
- package/templates/agent-os/universal/.claude/skills/new-invariant/guard-invariant.example.test.mjs +89 -0
- package/templates/agent-os/universal/.claude/skills/worktree-task/SKILL.md +73 -0
- package/templates/agent-os/universal/CLAUDE.md +57 -7
- package/templates/agent-os/universal/PLAN.md +28 -2
- package/templates/agent-os/universal/layers.json +20 -1
- package/templates/skeleton/aws-serverless/.github/workflows/ci.yml +6 -1
- package/templates/skeleton/aws-serverless/gitignore +8 -0
- package/templates/skeleton/node-service/.github/workflows/ci.yml +6 -1
- package/templates/skeleton/node-service/gitignore +8 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: worktree-task
|
|
3
|
+
description: Start and finish a task in its own git worktree — creation off the remote default branch, and the full cleanup after the merge. Use at the start of every implementation task and after every merge, and whenever two sessions might touch this repo at once.
|
|
4
|
+
allowed-tools: Bash, Read
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Worktree task lifecycle
|
|
8
|
+
|
|
9
|
+
`.claude/rules/workflow.md` says **one task, one branch**. A worktree is how
|
|
10
|
+
that rule survives a second session: two branches checked out at once, in two
|
|
11
|
+
directories, with one `.git`. Without it, an unattended run and a hand-driven
|
|
12
|
+
session share a working tree and overwrite each other's edits.
|
|
13
|
+
|
|
14
|
+
**Use one when** anything else may touch this repo while you work — an
|
|
15
|
+
unattended `loop` run, a colleague, a second Claude session. A single attended
|
|
16
|
+
session on a quiet repo can just use a branch; the discipline that is never
|
|
17
|
+
optional is the branch, not the worktree.
|
|
18
|
+
|
|
19
|
+
## Start
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
cd "$(git rev-parse --show-toplevel)" # ALWAYS anchor cwd first — see gotcha 1
|
|
23
|
+
git fetch origin
|
|
24
|
+
git worktree add -b <type>/<slug> .claude/worktrees/<slug> origin/HEAD
|
|
25
|
+
git worktree list # verify the path is DIRECTLY under .claude/worktrees/
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- **Branch off the remote default branch**, never a local copy — a stale local
|
|
29
|
+
default is how a task gets built on code that was replaced last week
|
|
30
|
+
(`.claude/rules/autonomy.md`, "Session staleness"). If `origin/HEAD` is not
|
|
31
|
+
set locally, name the branch explicitly: `origin/<default-branch>`.
|
|
32
|
+
- **Branch name: `<type>/<slug>`**, type one of `feat|fix|docs|chore|refactor`.
|
|
33
|
+
If the project's queue gives work an id, the branch carries it —
|
|
34
|
+
`feat/<id>-<slug>` — because the branch name is often the only thread between
|
|
35
|
+
a queue item and its code. Work with no queue item keeps the plain form: **do
|
|
36
|
+
not invent an id.**
|
|
37
|
+
- If tests will run there, install inside the worktree first. A worktree gets a
|
|
38
|
+
fresh, empty `node_modules`; a missing install fails as a confusing
|
|
39
|
+
module-resolution error rather than as "you forgot to install".
|
|
40
|
+
|
|
41
|
+
## Finish (after the PR is merged)
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
cd "$(git -C <repo root> rev-parse --show-toplevel)" # cd OUT of the worktree first — gotcha 2
|
|
45
|
+
git worktree remove .claude/worktrees/<slug> --force
|
|
46
|
+
git worktree prune
|
|
47
|
+
git branch -D <type>/<slug>
|
|
48
|
+
git push origin --delete <type>/<slug> # if the merge did not already delete it
|
|
49
|
+
rm -rf .claude/worktrees/<slug> # only if `remove` left the directory behind
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Add `.claude/worktrees/` to `.gitignore` once, so a live worktree never shows
|
|
53
|
+
up as untracked noise in every `git status`.
|
|
54
|
+
|
|
55
|
+
## Gotchas
|
|
56
|
+
|
|
57
|
+
1. **A stale cwd creates worktrees inside dead paths.** If your shell sits in a
|
|
58
|
+
directory that has been removed (typically the *previous* task's worktree), a
|
|
59
|
+
relative `git worktree add .claude/worktrees/x` recreates the dead path and
|
|
60
|
+
nests the new worktree inside it. Always `cd` to the repo root by an
|
|
61
|
+
**absolute** path first, and verify with `git worktree list` afterwards.
|
|
62
|
+
2. **`git worktree remove` fails while your shell is inside it** — or while a
|
|
63
|
+
watcher or install still holds a handle on `node_modules`. `cd` out first. If
|
|
64
|
+
the directory survives `remove --force`, run `git worktree prune` (the
|
|
65
|
+
metadata is then clean) and delete the leftover directory; retry later if it
|
|
66
|
+
is still busy.
|
|
67
|
+
3. **Never touch a worktree you did not create.** Concurrent sessions make
|
|
68
|
+
worktrees appear and vanish mid-task. Removing another session's worktree
|
|
69
|
+
destroys unmerged work — and it is indistinguishable, afterwards, from that
|
|
70
|
+
session never having done the work.
|
|
71
|
+
4. **One worktree per task.** Do not reuse a finished task's worktree: its
|
|
72
|
+
branch state and its install are both stale, and the reuse is invisible in
|
|
73
|
+
the diff.
|
|
@@ -46,18 +46,68 @@ them all; they are one rulebook.
|
|
|
46
46
|
short-lived branch; the default branch is never committed to directly. Once
|
|
47
47
|
the project has a remote and CI, changes reach it through the PR flow (local
|
|
48
48
|
checks → reviewer fan-out → merge on an explicit criterion). See
|
|
49
|
-
`.claude/rules/workflow.md` ("Branches and commits", "PR flow").
|
|
49
|
+
`.claude/rules/workflow.md` ("Branches and commits", "PR flow"). When another
|
|
50
|
+
session may touch this repo at the same time, the branch lives in its own
|
|
51
|
+
worktree — the `worktree-task` skill has the lifecycle and the cleanup.
|
|
50
52
|
- **Gates.** `code-reviewer` runs before every PR; `security-scanner` runs when
|
|
51
53
|
a change touches auth, secrets, parsing, or outbound calls. Blocking findings
|
|
52
54
|
are resolved, not argued with. The `pr-ship` skill drives the gate.
|
|
53
55
|
- **Enforcement is mechanical.** `guard-core-purity` catches an impure edit to
|
|
54
56
|
the core the moment it lands; `guard-web-boundary` keeps the frontend off the
|
|
55
|
-
backend; `block-no-verify` refuses pre-commit bypasses; `
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
backend; `block-no-verify` refuses pre-commit bypasses; `guard-bash` refuses
|
|
58
|
+
the "Never" tier — force-pushing a shared branch, a production deploy, a
|
|
59
|
+
filesystem wipe — and carries the kill switch; `gate-stop-dod` refuses to end
|
|
60
|
+
the session while a Definition-of-Done check fails. If a hook blocks you, fix
|
|
61
|
+
the cause; never route around a hook.
|
|
62
|
+
- **Enforcement is a pattern you can apply again.** Each of those hooks is one
|
|
63
|
+
stated invariant + one mechanical check + one test — the pattern is written down
|
|
64
|
+
in `.claude/rules/invariants.md`, and the `new-invariant` skill walks you
|
|
65
|
+
through adding one. The hooks that ship here are **examples, not laws**: if the
|
|
66
|
+
invariant they guard is not load-bearing in this project, delete it and spend
|
|
67
|
+
the slot on one that is.
|
|
68
|
+
- **There is a brake, and it is a real file.** `touch
|
|
69
|
+
~/.claude/__PROJECT_NAME__-loop-STOP` and `guard-bash` denies every merge
|
|
70
|
+
until it is removed. Everything short of the merge stays allowed on purpose:
|
|
71
|
+
finish the task, push the branch, open the PR, write the journal, stop.
|
|
72
|
+
Stopping cleanly never means losing the work.
|
|
73
|
+
- **Work comes from the queue, through an adapter.** The `loop` skill selects via
|
|
74
|
+
`.claude/scripts/queue/index.mjs`, which reads whichever queue
|
|
75
|
+
`.claude/queue.json` names — the Agent queue in `PLAN.md` by default, issues in
|
|
76
|
+
this repository once it has a remote. An empty queue **ends the session**; it is
|
|
77
|
+
never a cue to invent work, and the agent never files its own work items.
|
|
78
|
+
|
|
79
|
+
## The elevated paths of this project
|
|
80
|
+
|
|
81
|
+
Tier 2 in `.claude/rules/autonomy.md` names *kinds* of change. This block names
|
|
82
|
+
the **paths** in this repository where those kinds live, and
|
|
83
|
+
`.claude/scripts/detect-missed-gate.mjs` reads it — so a path that is not declared
|
|
84
|
+
is a path the gate sweep cannot see.
|
|
85
|
+
|
|
86
|
+
```elevated-paths
|
|
87
|
+
packages/db/src/
|
|
88
|
+
.claude/
|
|
89
|
+
.github/workflows/
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`.claude/` and `.github/workflows/` are there because they are what *disarms* the
|
|
93
|
+
rest: a merge that rewrites the Never tier, unwires a hook or edits what CI runs
|
|
94
|
+
should never pass unreviewed. `packages/db/src/` is the one the generated shape
|
|
95
|
+
has.
|
|
96
|
+
|
|
97
|
+
**They are a seed, not a law — the list is yours to extend.** It is what every
|
|
98
|
+
generated shape has; a real project accumulates more (auth handlers, billing, a
|
|
99
|
+
credentials module, a migration directory). Add a path the same day you add the
|
|
100
|
+
code, because the gap between the two is exactly the window in which a change
|
|
101
|
+
slips through unreviewed.
|
|
102
|
+
|
|
103
|
+
The declaration is **composed, not centralised**: the sweep unions this block with
|
|
104
|
+
every `elevated-paths` block in `.claude/rules/`, so a stack layer declares the
|
|
105
|
+
paths that only exist in its shape. A gate declared over a directory this project
|
|
106
|
+
does not have would report "clean" while looking nowhere.
|
|
107
|
+
|
|
108
|
+
Nothing about this list is retroactive. Installing the sweep into a repo with
|
|
109
|
+
history means passing `--epoch <the day you installed it>` once, or the first run
|
|
110
|
+
reports every merge that predates the gate.
|
|
61
111
|
|
|
62
112
|
## Foot-guns
|
|
63
113
|
|
|
@@ -23,5 +23,31 @@ journal records history; the queues state only what is next.
|
|
|
23
23
|
|
|
24
24
|
## Journal
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
Newest first, date-free — order carries the sequence. Prune freely: this is
|
|
27
|
+
operational memory, not an archive. An unattended run writes an entry at every
|
|
28
|
+
stop **and** at checkpoints along the way, because a run that dies unexpectedly
|
|
29
|
+
must not take its history with it.
|
|
30
|
+
|
|
31
|
+
The fields exist so an entry can be visibly **incomplete**. A journal with no
|
|
32
|
+
stated shape decays into a diary that reads fine and proves nothing.
|
|
33
|
+
|
|
34
|
+
<!-- Template — copy the block, drop the fields that do not apply:
|
|
35
|
+
|
|
36
|
+
### <one-line summary of the session>
|
|
37
|
+
|
|
38
|
+
- **done** — what landed, one line each, with the PR reference
|
|
39
|
+
- **escalated** — what stopped, and the diagnosis: what failed, what was tried,
|
|
40
|
+
the current hypothesis, and the one question whose answer unblocks it
|
|
41
|
+
- **reviewed** — changes that went through a reviewer gate, and what it returned
|
|
42
|
+
- **stopped at** — which stop condition ended the session (or "checkpoint,
|
|
43
|
+
still running")
|
|
44
|
+
- **queue hygiene** — queue items fixed in passing: stale state, a dependency
|
|
45
|
+
that was already satisfied, an item that describes work already done
|
|
46
|
+
- **cost** — the counts the session actually observed: reviewer subagents run,
|
|
47
|
+
CI runs consumed (re-runs included — the cheapest signal that a task fought
|
|
48
|
+
its tests), deploys triggered
|
|
49
|
+
|
|
50
|
+
A field the session cannot observe stays **visibly empty — never estimated**.
|
|
51
|
+
A plausible number will be believed, by the next reader and by the next run
|
|
52
|
+
reasoning about its own budget. Leave the gap; it is information.
|
|
53
|
+
-->
|
|
@@ -2,14 +2,30 @@
|
|
|
2
2
|
"process": [
|
|
3
3
|
".claude/rules/workflow.md",
|
|
4
4
|
".claude/rules/autonomy.md",
|
|
5
|
+
".claude/rules/invariants.md",
|
|
6
|
+
".claude/skills/new-invariant/SKILL.md",
|
|
7
|
+
".claude/skills/new-invariant/guard-invariant.example.mjs",
|
|
8
|
+
".claude/skills/new-invariant/guard-invariant.example.test.mjs",
|
|
5
9
|
".claude/agents/test-writer.md",
|
|
6
10
|
".claude/agents/code-reviewer.md",
|
|
7
11
|
".claude/agents/security-scanner.md",
|
|
8
12
|
".claude/hooks/block-no-verify.mjs",
|
|
13
|
+
".claude/hooks/guard-bash.mjs",
|
|
9
14
|
".claude/hooks/gate-stop-dod.mjs",
|
|
10
15
|
".claude/hooks/inject-rules.mjs",
|
|
11
16
|
".claude/skills/pr-ship/SKILL.md",
|
|
12
17
|
".claude/skills/loop/SKILL.md",
|
|
18
|
+
".claude/skills/worktree-task/SKILL.md",
|
|
19
|
+
".claude/scripts/detect-missed-gate.mjs",
|
|
20
|
+
".claude/scripts/reconcile-external-prs.mjs",
|
|
21
|
+
".claude/scripts/stop-flag.mjs",
|
|
22
|
+
".claude/scripts/preflight.mjs",
|
|
23
|
+
".claude/scripts/queue/core.mjs",
|
|
24
|
+
".claude/scripts/queue/plan-md.mjs",
|
|
25
|
+
".claude/scripts/queue/github-issues.mjs",
|
|
26
|
+
".claude/scripts/queue/jira.mjs",
|
|
27
|
+
".claude/scripts/queue/index.mjs",
|
|
28
|
+
".claude/queue.json",
|
|
13
29
|
"PLAN.md"
|
|
14
30
|
],
|
|
15
31
|
"architecture": [
|
|
@@ -17,5 +33,8 @@
|
|
|
17
33
|
".claude/hooks/guard-core-purity.mjs",
|
|
18
34
|
".claude/hooks/guard-web-boundary.mjs"
|
|
19
35
|
],
|
|
20
|
-
"meta": [
|
|
36
|
+
"meta": [
|
|
37
|
+
".claude/settings.json",
|
|
38
|
+
"CLAUDE.md"
|
|
39
|
+
]
|
|
21
40
|
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
name: CI
|
|
2
2
|
|
|
3
|
+
# The default token is read-only for this job: CI needs nothing else, and a
|
|
4
|
+
# workflow that can write is a workflow a compromised dependency can write with.
|
|
5
|
+
permissions:
|
|
6
|
+
contents: read
|
|
7
|
+
|
|
3
8
|
on:
|
|
4
9
|
push:
|
|
5
10
|
pull_request:
|
|
@@ -16,7 +21,7 @@ jobs:
|
|
|
16
21
|
with:
|
|
17
22
|
node-version: 22
|
|
18
23
|
cache: pnpm
|
|
19
|
-
- run: pnpm install --
|
|
24
|
+
- run: pnpm install --frozen-lockfile
|
|
20
25
|
- run: pnpm lint
|
|
21
26
|
- run: pnpm typecheck
|
|
22
27
|
- run: pnpm test
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
name: CI
|
|
2
2
|
|
|
3
|
+
# The default token is read-only for this job: CI needs nothing else, and a
|
|
4
|
+
# workflow that can write is a workflow a compromised dependency can write with.
|
|
5
|
+
permissions:
|
|
6
|
+
contents: read
|
|
7
|
+
|
|
3
8
|
on:
|
|
4
9
|
push:
|
|
5
10
|
pull_request:
|
|
@@ -16,7 +21,7 @@ jobs:
|
|
|
16
21
|
with:
|
|
17
22
|
node-version: 22
|
|
18
23
|
cache: pnpm
|
|
19
|
-
- run: pnpm install --
|
|
24
|
+
- run: pnpm install --frozen-lockfile
|
|
20
25
|
- run: pnpm lint
|
|
21
26
|
- run: pnpm typecheck
|
|
22
27
|
- run: pnpm test
|