create-religion 1.3.0 → 1.5.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.
Files changed (31) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/lib/dashboard.js +4 -3
  3. package/dist/lib/doctor.js +21 -7
  4. package/dist/lib/settings.js +4 -0
  5. package/dist/lib/state.js +125 -2
  6. package/dist/lib/status.js +21 -4
  7. package/package.json +1 -1
  8. package/template/.agents/skills/audit/SKILL.md +13 -7
  9. package/template/.agents/skills/complete/SKILL.md +22 -6
  10. package/template/.agents/skills/complete/reference/land-on-top.md +174 -0
  11. package/template/.agents/skills/distill/SKILL.md +2 -1
  12. package/template/.agents/skills/feature/SKILL.md +4 -1
  13. package/template/.agents/skills/fix/SKILL.md +3 -2
  14. package/template/.agents/skills/implement/SKILL.md +38 -8
  15. package/template/.agents/skills/implement/reference/item-worktree.md +116 -0
  16. package/template/.agents/skills/implement/reference/worktrees.md +175 -0
  17. package/template/.agents/skills/rollback/SKILL.md +3 -1
  18. package/template/.claude/hooks/write-handoff.mjs +80 -3
  19. package/template/.claude/skills/audit/SKILL.md +13 -7
  20. package/template/.claude/skills/complete/SKILL.md +22 -6
  21. package/template/.claude/skills/complete/reference/land-on-top.md +174 -0
  22. package/template/.claude/skills/distill/SKILL.md +2 -1
  23. package/template/.claude/skills/feature/SKILL.md +4 -1
  24. package/template/.claude/skills/fix/SKILL.md +3 -2
  25. package/template/.claude/skills/implement/SKILL.md +38 -8
  26. package/template/.claude/skills/implement/reference/item-worktree.md +116 -0
  27. package/template/.claude/skills/implement/reference/worktrees.md +175 -0
  28. package/template/.claude/skills/rollback/SKILL.md +3 -1
  29. package/template/AGENTS.md +9 -3
  30. package/template/CLAUDE.md +9 -3
  31. package/template/religion/config.json +2 -1
@@ -0,0 +1,175 @@
1
+ # Building a wave in worktrees
2
+
3
+ One detached git worktree per wave step, outside the project, so a step can neither see nor
4
+ change another step's files. The parent runs every command here; a step's subagent only
5
+ works inside the worktree it is given.
6
+
7
+ Run the phases in order. A command that fails stops the wave: report it and stop, as for any
8
+ failed step.
9
+
10
+ ## 1. Base
11
+
12
+ Once per wave, after every earlier step has landed, take the base, make the wave's directory,
13
+ and save the values every later phase needs. Run these lines as **one** command: the save
14
+ needs the values the first lines produce, and a fresh shell would have none of them.
15
+
16
+ (
17
+ root=$(git rev-parse --show-toplevel) || exit 1
18
+ case "$root" in */step-*) [ ! -f "${root%/*}/base" ] || exit 1;; esac
19
+ [ ! -e "$root/religion/.state/wave" ] || { cat "$root/religion/.state/wave"; exit 1; }
20
+ base=$(git -C "$root" stash create) || exit 1
21
+ [ -n "$base" ] || base=$(git -C "$root" rev-parse HEAD) || exit 1
22
+ wave=$(mktemp -d) && wave=$(cd -- "$wave" >/dev/null && pwd -P) || exit 1
23
+ printf '%s\n' "$base" > "$wave/base" || exit 1
24
+ mkdir -p "$root/religion/.state" && printf '%s\n' "$wave" > "$root/religion/.state/wave" || exit 1
25
+ )
26
+
27
+ Each line that can fail stops the block, rather than `set -e`, which would stay on in a tool
28
+ that keeps one shell between commands. The block runs in a subshell, so its exits end only
29
+ the subshell and never that shell; it hands nothing back, since every later phase reads the
30
+ saved values. The `cd` sends its output away so a shell hook that prints on a directory change
31
+ cannot end up in the saved path. Without the stops, a failed `mktemp` leaves `wave`
32
+ empty, `cd ""` stays in the project, and the block saves the project itself as the wave; a
33
+ failed `git stash create` falls back to `HEAD` and drops uncommitted earlier steps.
34
+
35
+ A saved wave that already exists means an earlier one was not torn down, which is what a
36
+ failed join leaves. The block prints the directory it names and stops, so the record of where
37
+ those worktrees are is never overwritten; deal with them first.
38
+
39
+ Every command that touches the project runs against `$root`, never the current directory.
40
+ From a subdirectory, `git apply` skips every path outside it and still exits 0, and
41
+ `git ls-files` lists only what is below it, so a wave started there would join nothing and
42
+ then tear down the work as if it had landed.
43
+
44
+ `git stash create` makes a commit of the working tree without touching the stash list, any
45
+ ref, or the working tree, so uncommitted earlier steps are part of the base. An empty result
46
+ means the tree is clean, and `HEAD` is the base.
47
+
48
+ Never `git stash push`, and never `git add -N` in the project: the user's index and stash
49
+ are not the wave's to change.
50
+
51
+ ## 2. Create
52
+
53
+ `pwd -P` saves the resolved path, the form `git rev-parse` reports, so the check below can
54
+ compare the two. A shell that does not keep variables between commands starts each later
55
+ phase by reading the values back, and stops if the current directory has drifted into one of
56
+ the wave's own worktrees:
57
+
58
+ root=$(git rev-parse --show-toplevel)
59
+ case "$root" in */step-*) [ ! -f "${root%/*}/base" ] || exit 1;; esac
60
+ wave=$(cat "$root/religion/.state/wave")
61
+ base=$(cat "$wave/base")
62
+ case "$root/" in "$wave"/*) exit 1;; esac
63
+
64
+ From inside a worktree, `root` would be that worktree, and the join would land there and
65
+ report success while the project stayed unchanged. The first `case` stops in a step worktree
66
+ of any wave, including one kept by an earlier failed join, recognised by the `base` file in
67
+ the wave directory beside it; the second stops in one of this wave's own. A linked worktree
68
+ the user works from is neither, so it is not refused.
69
+
70
+ Then, once per step, named for the step's number:
71
+
72
+ git -C "$root" worktree add --detach "$wave/step-<n>" "$base"
73
+
74
+ `--detach` creates no branch, whatever `git.mode` says. Keeping the worktrees outside the
75
+ project keeps a second copy of the source out of the project's own tests, linters and file
76
+ watchers.
77
+
78
+ The stash commit leaves untracked files out, so copy them in, all but the workflow's own
79
+ state, which would carry the saved wave path into the worktree:
80
+
81
+ git -C "$root" ls-files --others --exclude-standard -z |
82
+ while IFS= read -r -d '' f; do
83
+ case "$f" in religion/.state/*) continue;; esac
84
+ mkdir -p "$wave/step-<n>/$(dirname "$f")" && cp -RPp "$root/$f" "$wave/step-<n>/$f"
85
+ done
86
+
87
+ `-RP` copies an untracked link as a link. Plain `cp` refuses a link to a directory, and
88
+ following it would copy whatever it points at.
89
+
90
+ Then make the copies part of the step's base, so they are not handed back as new files:
91
+
92
+ git -C "$wave/step-<n>" add -A
93
+ git -C "$wave/step-<n>" write-tree > "$wave/step-<n>.base"
94
+
95
+ `write-tree` saves a tree object and nothing else: no commit, no ref. The saved file is the
96
+ base phase 5 diffs against, and it survives a shell that does not keep variables between
97
+ commands.
98
+
99
+ ## 3. Link
100
+
101
+ A fresh worktree has none of the project's installed dependencies. Symlink each installed
102
+ dependency directory at the project root that the gate needs, such as `node_modules`:
103
+
104
+ [ -e "$wave/step-<n>/node_modules" ] || [ -L "$wave/step-<n>/node_modules" ] ||
105
+ ln -s "$root/node_modules" "$wave/step-<n>/node_modules"
106
+
107
+ Skip the link when anything already sits at that path, such as an untracked link copied in
108
+ phase 2. `ln -s` onto an existing link to a directory does not replace it: it creates a new
109
+ link inside the directory it points at, which here is the project's real dependencies.
110
+
111
+ Never install into a worktree. That is a dependency install, which the Authority section
112
+ does not grant a wave. On Windows the link would be a junction, which this routine has not
113
+ been run against.
114
+
115
+ ## 4. Build
116
+
117
+ When the project's gate reads build output that is not committed, run the project's build in
118
+ the worktree before handing it to the subagent, so the step's checks can run there at all.
119
+ Run it in a subshell, `(cd "$wave/step-<n>" && <build>)`, so the current directory never
120
+ moves into the worktree.
121
+
122
+ ## 5. Extract
123
+
124
+ When the subagent returns, take its patch:
125
+
126
+ git -C "$wave/step-<n>" add -A
127
+ git -C "$wave/step-<n>" diff --cached --binary "$(cat "$wave/step-<n>.base")" -- . <exclusions> > "$wave/step-<n>.patch"
128
+
129
+ `add -A` writes to the worktree's own index, never the project's, and brings new files into
130
+ the patch. `<exclusions>` is one `':!<path>'` for each link made in phase 3, which an ignore
131
+ rule with a trailing slash such as `node_modules/` does not cover, because a link is not a
132
+ directory. Then one more for each path the project's instructions declare as generated, such
133
+ as rendered trees, so two steps that both regenerate a shared file do not
134
+ collide over output the build reproduces. A project that declares none keeps every path, and
135
+ a generated file that both steps touched then fails the join and stops it.
136
+
137
+ ## 6. Join
138
+
139
+ All patches, in step order, through **one** `git apply` of one file:
140
+
141
+ for p in "$wave"/step-<n>.patch "$wave"/step-<m>.patch; do [ -f "$p" ] || exit 1; done
142
+ cat "$wave"/step-<n>.patch "$wave"/step-<m>.patch > "$wave/join.patch"
143
+ git -C "$root" apply "$wave/join.patch"
144
+
145
+ Check that every step's patch exists first, and never pipe into `git apply`: without
146
+ `pipefail` a pipe reports `git apply`'s status alone, so a missing patch would land the
147
+ others as a success and teardown would delete the step that never applied.
148
+
149
+ One concatenated input applies all or nothing, including two patches to the same file.
150
+ Separate patch files given to one `git apply` do not: the first lands even when a later one
151
+ fails. Never `--3way`, never a merge, and never resolve a conflict by editing.
152
+
153
+ On failure the project is exactly as it was. Stop the wave, keep the worktrees, and report
154
+ the paths `git apply` named and where each worktree is.
155
+
156
+ On success, run the project's build once when any path was excluded, so generated output is
157
+ rendered from the joined sources, then run each step's gate on the joined tree.
158
+
159
+ ## 7. Teardown
160
+
161
+ Only after a successful join, and only for worktrees this run created for this wave. Once per
162
+ step:
163
+
164
+ rm "$wave/step-<n>/node_modules"
165
+ git worktree remove --force "$wave/step-<n>"
166
+ rm "$wave/step-<n>.patch" "$wave/step-<n>.base"
167
+
168
+ Then once for the wave:
169
+
170
+ rm "$wave/join.patch" "$wave/base"
171
+ rmdir "$wave"
172
+ rm "$root/religion/.state/wave"
173
+
174
+ Remove each link first, so nothing follows it into the project's real dependencies. Removing
175
+ any other worktree, or these after a failed join, still asks.
@@ -67,7 +67,9 @@ Stop on any failure. Do not repair a mismatch by choosing a nearby commit.
67
67
  1. Every recorded identifier matches `^[0-9a-f]{40}$`. Reject abbreviated or uppercase
68
68
  values.
69
69
  2. Every recorded commit resolves in this repository and is an ancestor of `HEAD`.
70
- 3. The recorded base is the parent of the earliest recorded commit.
70
+ 3. The recorded base is the parent of the earliest recorded commit. For an item landed on top
71
+ of another, that commit is the merge that brought the other in, and the base must be its
72
+ second parent, what it brought in: the first parent would reverse the other item's work.
71
73
  4. The working tree is clean apart from the rollback spec being written.
72
74
 
73
75
  ## Step 3 - preview the product diff
@@ -43,7 +43,8 @@ Implementation lands one small step at a time, each with a diff to read and evid
43
43
  its stated outcome was met.
44
44
 
45
45
  `religion/context/current-work.md` holds exactly one work item. Finish it, archive it,
46
- then start the next. Progress lives in checkboxes inside that file, so a cleared context
46
+ then start the next. With `workflow.parallelItems` on, other items may be in flight in other
47
+ git worktrees, one each; they land one at a time. Progress lives in checkboxes inside that file, so a cleared context
47
48
  costs nothing: a fresh session reads which steps are ticked and resumes from the first
48
49
  one that is not.
49
50
 
@@ -104,6 +105,10 @@ carry to a later instance.
104
105
  - deleting files or data, and any rewrite of existing history
105
106
  - changing a remote service, its configuration, or its secrets
106
107
 
108
+ Removing a detached worktree that the current run created for a wave, outside the project,
109
+ once that wave's join has succeeded, is not deleting files or data. Removing any other
110
+ worktree still asks.
111
+
107
112
  Pushing a branch that a run created itself is the single action that may be granted ahead
108
113
  of time, and only in the narrow way set out below. Every other push is first tier.
109
114
 
@@ -184,8 +189,9 @@ needed, a conflict appears, the work drifts outside its spec, or something in th
184
189
  tier of the authority rules comes up.
185
190
 
186
191
  `workflow.parallelSteps` ships `false`. Turned on, steps a spec marks as independent are
187
- built together in one wave and reviewed as one packet, so nothing lands unreviewed either
188
- way. While it is off, those markers are ignored and every spec builds in order.
192
+ built together in one wave, each in its own git worktree, then joined and reviewed as one
193
+ packet, so nothing lands unreviewed either way. A join that does not apply cleanly stops for
194
+ review. While it is off, those markers are ignored and every spec builds in order.
189
195
  ## Activity
190
196
 
191
197
  Any skill that changes something writes an activity record to
@@ -35,7 +35,8 @@ Implementation lands one small step at a time, each with a diff to read and evid
35
35
  its stated outcome was met.
36
36
 
37
37
  `religion/context/current-work.md` holds exactly one work item. Finish it, archive it,
38
- then start the next. Progress lives in checkboxes inside that file, so a cleared context
38
+ then start the next. With `workflow.parallelItems` on, other items may be in flight in other
39
+ git worktrees, one each; they land one at a time. Progress lives in checkboxes inside that file, so a cleared context
39
40
  costs nothing: a fresh session reads which steps are ticked and resumes from the first
40
41
  one that is not.
41
42
 
@@ -68,6 +69,10 @@ carry to a later instance.
68
69
  - deleting files or data, and any rewrite of existing history
69
70
  - changing a remote service, its configuration, or its secrets
70
71
 
72
+ Removing a detached worktree that the current run created for a wave, outside the project,
73
+ once that wave's join has succeeded, is not deleting files or data. Removing any other
74
+ worktree still asks.
75
+
71
76
  Pushing a branch that a run created itself is the single action that may be granted ahead
72
77
  of time, and only in the narrow way set out below. Every other push is first tier.
73
78
 
@@ -148,8 +153,9 @@ needed, a conflict appears, the work drifts outside its spec, or something in th
148
153
  tier of the authority rules comes up.
149
154
 
150
155
  `workflow.parallelSteps` ships `false`. Turned on, steps a spec marks as independent are
151
- built together in one wave and reviewed as one packet, so nothing lands unreviewed either
152
- way. While it is off, those markers are ignored and every spec builds in order.
156
+ built together in one wave, each in its own git worktree, then joined and reviewed as one
157
+ packet, so nothing lands unreviewed either way. A join that does not apply cleanly stops for
158
+ review. While it is off, those markers are ignored and every spec builds in order.
153
159
  ## Activity
154
160
 
155
161
  Any skill that changes something writes an activity record to
@@ -2,7 +2,8 @@
2
2
  "schemaVersion": 1,
3
3
  "workflow": {
4
4
  "stepReview": "every",
5
- "parallelSteps": false
5
+ "parallelSteps": false,
6
+ "parallelItems": false
6
7
  },
7
8
  "git": {
8
9
  "mode": "trunk",