genesis-compiler 1.10.21 → 1.10.23
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/README.md +37 -7
- package/docs/prompt-integration.md +13 -2
- package/docs/stack-components.md +1 -1
- package/package.json +6 -2
- package/plugins/genesis/.codex-plugin/plugin.json +1 -1
- package/prompts/master-pass.txt +17 -0
- package/prompts/pass-deep.txt +77 -0
- package/prompts/pass-report.txt +15 -0
- package/prompts/review.txt +2 -1
- package/skills/genesis-data-pass/SKILL.md +24 -7
- package/skills/genesis-deslop/SKILL.md +25 -3
- package/skills/genesis-identity-pass/SKILL.md +20 -3
- package/skills/genesis-master-pass/SKILL.md +132 -0
- package/skills/genesis-master-pass/agents/openai.yaml +4 -0
- package/skills/genesis-project/references/sanity-checks.md +53 -12
- package/skills/genesis-quality-pass/SKILL.md +21 -3
- package/skills/genesis-review/SKILL.md +120 -0
- package/skills/genesis-review/agents/openai.yaml +4 -0
- package/skills/genesis-security-pass/SKILL.md +21 -3
- package/skills/genesis-speed-pass/SKILL.md +21 -3
- package/skills/genesis-ui-pass/SKILL.md +21 -3
- package/skills/genesis-ux-pass/SKILL.md +20 -3
- package/src/cli-commands.js +3 -1
- package/src/cli.js +12 -4
- package/src/index/agent-skills.js +4 -3
- package/src/index/assets.js +4 -1
- package/src/index/code-index.js +2 -1
- package/src/index/contracts.js +1 -0
- package/src/index/master-pass.js +76 -0
- package/src/index/pass-record.js +101 -24
- package/src/index/pass-support.js +4 -1
- package/src/index/passes.js +55 -1
- package/src/index/project-files.js +2 -1
- package/src/index/prompt.js +221 -37
- package/src/index/source-size.js +62 -0
- package/src/index.js +5 -1
|
@@ -173,35 +173,75 @@ one matching, and see it found.
|
|
|
173
173
|
|
|
174
174
|
**Outer limit:** a capped read narrowed in code is broken at any size.
|
|
175
175
|
|
|
176
|
-
## Data:
|
|
176
|
+
## Data: batches and background work
|
|
177
177
|
|
|
178
178
|
**Good:** a batch writes each table in a few statements inside the owner's
|
|
179
179
|
transaction, not one full create per row. Work nobody waits for runs as a
|
|
180
180
|
scheduled or queued job in bounded chunks: it loops over units of work (a
|
|
181
181
|
tenant, a user), one transaction each, never one around the whole run and
|
|
182
|
-
never one per row. A read request takes no lock and writes nothing.
|
|
183
|
-
takes its locks in one order, parents before children, so two transactions
|
|
184
|
-
never wait on each other. Two writers on the same records never produce a
|
|
185
|
-
server error.
|
|
182
|
+
never one per row. A read request takes no lock and writes nothing.
|
|
186
183
|
|
|
187
184
|
**Check:** count a batch's statements at 10 items and at 500. Look for due work
|
|
188
185
|
run inside whichever request comes first, and one long transaction around it.
|
|
189
186
|
Find any lock or write a read path takes for one-time setup: read first, lock
|
|
190
|
-
only on the rare unset path.
|
|
191
|
-
Run two writers on the same records; a retried transaction must be safe to
|
|
192
|
-
repeat, so HTTP calls, email and uploads go before or after it, or into an
|
|
193
|
-
outbox row written inside it.
|
|
187
|
+
only on the rare unset path.
|
|
194
188
|
|
|
195
189
|
**Examples:**
|
|
196
190
|
- An import created each row through the full single-record create path, with
|
|
197
191
|
its lookups and read-back, one row at a time.
|
|
198
192
|
- Overdue work ran inside the first user request after a quiet period, so that
|
|
199
193
|
request's time depended on how long nobody had used the app.
|
|
200
|
-
- Concurrent saves surfaced database deadlocks as 500s.
|
|
201
194
|
|
|
202
195
|
**Outer limit:** thousands of queries or tens of seconds for one action, or a
|
|
203
196
|
request whose time depends on how long since anyone used the app.
|
|
204
197
|
|
|
198
|
+
## Data: two changes at once
|
|
199
|
+
|
|
200
|
+
**Good:** each write uses the lightest tool that keeps the stored data right.
|
|
201
|
+
Most need nothing beyond the transaction they already run in:
|
|
202
|
+
- An ordinary edit (a form saving a record, a name or a description, settings,
|
|
203
|
+
a saved game) is a plain write, and the last save wins: when two people edit
|
|
204
|
+
the same thing at the same moment, one change replaces the other. That is
|
|
205
|
+
usually acceptable, and it needs no lock and no concurrency test. Where
|
|
206
|
+
people would care, the save can carry the version it read and refuse when
|
|
207
|
+
the record has moved on, saying that someone else changed it and to reload.
|
|
208
|
+
- A change allowed only while a value still holds (open to booked, a reward
|
|
209
|
+
claimed once) is a conditional update, a compare-and-set: of two writers one
|
|
210
|
+
wins and the other gets a clear refusal, with no lock.
|
|
211
|
+
- A value that must be unique gets a unique index or constraint, and an
|
|
212
|
+
insert that loses that race is retried where the tools offer it, or refused
|
|
213
|
+
clearly.
|
|
214
|
+
- An explicit lock is for a race that would silently leave wrong data that
|
|
215
|
+
matters: stock or quantities, money or balances, sequential document
|
|
216
|
+
numbers, a capacity limit (two bookings of the last place), or a
|
|
217
|
+
check-then-act on a shared resource (is the drier empty? then load it).
|
|
218
|
+
|
|
219
|
+
A lock makes other writers wait, can deadlock and needs a test with two
|
|
220
|
+
writers, so it usually pays only where you can name the wrong data a race
|
|
221
|
+
would leave. Whatever the tool, a lost race never becomes a server error: the
|
|
222
|
+
loser gets a refusal it can act on, or its work runs again. Take locks in one
|
|
223
|
+
order on every path, parents before children, so two transactions never wait
|
|
224
|
+
on each other. Work that may run again must be safe to repeat, so HTTP calls,
|
|
225
|
+
email and uploads go before or after the transaction, or into an outbox row
|
|
226
|
+
written inside it.
|
|
227
|
+
|
|
228
|
+
**Check:** for each write path, name its tool and why: for a lock, the wrong
|
|
229
|
+
data a race would leave; for a plain write, why the last save winning is
|
|
230
|
+
acceptable. Run two writers at once on each path that locks, writes
|
|
231
|
+
conditionally or relies on a unique key, and see one win and the other refused
|
|
232
|
+
or run again, never a server error and never both applied. Compare the order in
|
|
233
|
+
which each path locks rows. An ordinary edit needs neither a lock nor a
|
|
234
|
+
two-writer test.
|
|
235
|
+
|
|
236
|
+
**Examples:**
|
|
237
|
+
- Concurrent saves surfaced database deadlocks as 500s.
|
|
238
|
+
- A business app locked the rows of every save, names and settings included,
|
|
239
|
+
and spent hours on lock order, deadlocks and two-writer tests for edits
|
|
240
|
+
where the last save winning was fine.
|
|
241
|
+
|
|
242
|
+
**Outer limit:** a lost race that ends in a server error, or that leaves stock,
|
|
243
|
+
money, numbering or a capacity limit silently wrong.
|
|
244
|
+
|
|
205
245
|
## Work that repeats or lingers
|
|
206
246
|
|
|
207
247
|
**Good:** work whose answer does not change between calls runs once and is
|
|
@@ -440,8 +480,9 @@ hundreds of requests on a first screen.
|
|
|
440
480
|
|
|
441
481
|
**Good:** the same state twice gives the same result. Each fact has one
|
|
442
482
|
resolver. Each status names what clears it, and each gate has a case that must
|
|
443
|
-
fail it.
|
|
444
|
-
|
|
483
|
+
fail it. A step that moves a status writes only while the status it read
|
|
484
|
+
still holds, so of two at once one wins and the other is refused. A delete
|
|
485
|
+
removes what it created elsewhere. Readiness is checked directly.
|
|
445
486
|
|
|
446
487
|
**Check:** find every place that resolves the same fact. Check that what a
|
|
447
488
|
delete created outside its table is gone. When a rule's result breaks another
|
|
@@ -53,6 +53,10 @@ to another agent and do not generate it again. This step composes the selected
|
|
|
53
53
|
Stack's quality pass guidance and any project customization with the portable
|
|
54
54
|
contract below.
|
|
55
55
|
|
|
56
|
+
When the user asks for a deep run of this pass, pass its Deep request,
|
|
57
|
+
`Quality pass the whole app deeply.`, exactly;
|
|
58
|
+
Genesis then adds the run's `DEEP RUN` section.
|
|
59
|
+
|
|
56
60
|
## Resolve the scope
|
|
57
61
|
|
|
58
62
|
Inspect `git status --short` and the staged and unstaged diffs before editing.
|
|
@@ -60,9 +64,11 @@ A dirty worktree is allowed. Preserve the existing index and unrelated work; do
|
|
|
60
64
|
not stage, stash, commit, or discard changes as a prerequisite.
|
|
61
65
|
|
|
62
66
|
When the prompt has a `PASS RUN` section, the request is one of the pass's own
|
|
63
|
-
runs
|
|
64
|
-
the whole app,
|
|
65
|
-
|
|
67
|
+
runs (the whole app, the changes since its last completed run judged against
|
|
68
|
+
the whole app, or a deep run) or a run over the changes since a base commit the
|
|
69
|
+
request names, and its scope is the one that section states, whatever the
|
|
70
|
+
defaults below say. A deep run's prompt also has a `DEEP RUN`
|
|
71
|
+
section; follow it with "Deep run" below.
|
|
66
72
|
|
|
67
73
|
- **The whole app (default).** Every screen, command and flow a person uses.
|
|
68
74
|
- **A section.** A named area (a module, a route subtree, a set of screens or
|
|
@@ -172,3 +178,15 @@ step only to the pass's own runs, whose requests it writes itself, so a quality
|
|
|
172
178
|
pass of a section, commits or your own changes is never recorded as the pass;
|
|
173
179
|
neither is a pass that stopped early, was abandoned or still has failing
|
|
174
180
|
checks.
|
|
181
|
+
|
|
182
|
+
## Deep run
|
|
183
|
+
|
|
184
|
+
When the prompt has a `DEEP RUN` section, follow it: it says how the checklist,
|
|
185
|
+
evidence, chunks, commits and report work for every pass. This pass adds to the
|
|
186
|
+
checklist:
|
|
187
|
+
|
|
188
|
+
- every screen and flow, with each of its states (loading, empty, partial,
|
|
189
|
+
failed, refused, offline, first use) as an item of its own, and every
|
|
190
|
+
refusal message;
|
|
191
|
+
- the cross-subsystem item: the same state or refusal handled or worded
|
|
192
|
+
differently in different places.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: genesis-review
|
|
3
|
+
description: Review the work against what the software should do through an explicitly requested review over the whole app, the changes since its last completed run, a named section or the current work, judging the tests (each changed behavior has one that would fail without it; none weakened or skipped), the gaps between intent, code and explanation, and costs that grow with the data, writing only tests and reporting everything else. Use when asked for a review, a review pass, or to check the tests and the work against the Blueprint.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Genesis review
|
|
7
|
+
|
|
8
|
+
Judge the work against what the software should do, and the tests against the
|
|
9
|
+
work, and say plainly what was and was not verified. A review is explicit:
|
|
10
|
+
never run it merely because implementation finished.
|
|
11
|
+
|
|
12
|
+
Resolve the invocation before running the first Genesis operation. Do not use a
|
|
13
|
+
Genesis operation or `genesis --version` as an availability probe.
|
|
14
|
+
|
|
15
|
+
1. Read the repository-root `package.json`. Treat Genesis as project-pinned only
|
|
16
|
+
when that manifest's `name` is `genesis-compiler`, or its `dependencies`,
|
|
17
|
+
`devDependencies`, or `optionalDependencies` contain the exact
|
|
18
|
+
`genesis-compiler` key.
|
|
19
|
+
2. For a project-pinned repository, invoke every Genesis CLI operation with
|
|
20
|
+
`npm exec --no -- genesis <arguments>`. This runs without fetching another
|
|
21
|
+
package. If the declared package is not installed, report that the project's
|
|
22
|
+
dependencies are not prepared; do not fall back to another Genesis version.
|
|
23
|
+
3. Otherwise, do not try `npm exec`. Run `command -v genesis` (or the current
|
|
24
|
+
shell's equivalent `PATH` lookup). When it resolves an executable, invoke
|
|
25
|
+
`genesis <arguments>` directly.
|
|
26
|
+
4. When neither source is available, stop and report that Genesis is
|
|
27
|
+
unavailable. Never install or update Genesis merely to satisfy a workflow
|
|
28
|
+
instruction.
|
|
29
|
+
|
|
30
|
+
Successful invocation resolution is routine. Do not narrate whether Genesis is
|
|
31
|
+
project-pinned or on `PATH`, and never describe direct `PATH` use as a fallback.
|
|
32
|
+
Mention how the invocation was selected only when resolution fails or the user
|
|
33
|
+
explicitly asks.
|
|
34
|
+
|
|
35
|
+
Follow the configured Collaboration approach for user-facing updates, including
|
|
36
|
+
its technical depth and response length. Report concrete progress,
|
|
37
|
+
findings, or blockers; do not announce that you are following guidance.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
## Load the effective project instructions once
|
|
41
|
+
|
|
42
|
+
A review request may arrive as a complete Genesis-generated prompt or as a
|
|
43
|
+
direct request such as `Review` or `Review the Orders section`.
|
|
44
|
+
|
|
45
|
+
If the current task already contains `GENESIS CONTEXT` whose task is `review`,
|
|
46
|
+
continue with it directly. Do not generate another prompt.
|
|
47
|
+
|
|
48
|
+
Otherwise, before resolving scope, run the Genesis `prompt --task review`
|
|
49
|
+
operation once using the invocation rule above. For a bare `Review` request,
|
|
50
|
+
pass no request argument. When the user names a section, commits or the
|
|
51
|
+
current work, pass that exact request as one safely quoted argument. Treat the
|
|
52
|
+
printed prompt as the instructions for this same turn; do not dispatch it to
|
|
53
|
+
another agent and do not generate it again.
|
|
54
|
+
|
|
55
|
+
When the user asks for a deep run of this pass, pass its Deep request,
|
|
56
|
+
`Review the whole app deeply.`, exactly;
|
|
57
|
+
Genesis then adds the run's `DEEP RUN` section.
|
|
58
|
+
|
|
59
|
+
## Resolve the scope
|
|
60
|
+
|
|
61
|
+
Inspect `git status --short` and the staged and unstaged diffs before editing.
|
|
62
|
+
A dirty worktree is allowed. Preserve the existing index and unrelated work; do
|
|
63
|
+
not stage, stash, commit, or discard changes as a prerequisite.
|
|
64
|
+
|
|
65
|
+
When the prompt has a `PASS RUN` section, the request is one of the pass's own
|
|
66
|
+
runs (the whole app, the changes since its last completed run judged against
|
|
67
|
+
the whole app, or a deep run) or a run over the changes since a base commit the
|
|
68
|
+
request names, and its scope is the one that section states, whatever the
|
|
69
|
+
defaults below say. A deep run's prompt also has a `DEEP RUN`
|
|
70
|
+
section; follow it with "Deep run" below.
|
|
71
|
+
|
|
72
|
+
- **The work (default).** The relationship between the Blueprint, the code, the
|
|
73
|
+
Program and the tests as they stand now.
|
|
74
|
+
- **The whole app.** Every behavior the project's own source exposes and the
|
|
75
|
+
tests that prove it.
|
|
76
|
+
- **A section or the changes.** A named area, explicit commits, or the current
|
|
77
|
+
task's changes: the behavior they create or change and its tests.
|
|
78
|
+
|
|
79
|
+
If the scope is ambiguous, ask which section or changes.
|
|
80
|
+
|
|
81
|
+
## Boundaries
|
|
82
|
+
|
|
83
|
+
- The prompt says what a review judges. It edits only tests: it adds or updates
|
|
84
|
+
the tests changed behavior lacks and changes no product code, Blueprint,
|
|
85
|
+
Program, Stack or other file. Every other finding is reported with the
|
|
86
|
+
smallest sensible correction, left unchanged.
|
|
87
|
+
- Run the tests relevant to the scope; report what actually ran and what was not
|
|
88
|
+
verified, and never report an unrun check as passing.
|
|
89
|
+
|
|
90
|
+
Leave the review as ordinary uncommitted work for a later normal commit. Never
|
|
91
|
+
amend or rewrite selected commits.
|
|
92
|
+
|
|
93
|
+
When the prompt ends with a `PASS RECORD` step, take it once the review has
|
|
94
|
+
finished: the Genesis `passes done review` operation records it in `genesis/passes-added.json`,
|
|
95
|
+
an uncommitted change that lands in the review's own commit. Genesis adds that
|
|
96
|
+
step only to the pass's own runs, whose requests it writes itself, so a review
|
|
97
|
+
of a section, commits, a base or the current work is never recorded as the
|
|
98
|
+
pass; neither is a review that stopped early, was abandoned or still has
|
|
99
|
+
failing checks.
|
|
100
|
+
|
|
101
|
+
## Deep run
|
|
102
|
+
|
|
103
|
+
When the prompt has a `DEEP RUN` section, follow it: it says how the checklist,
|
|
104
|
+
evidence, chunks, commits and report work for every pass. This pass adds to the
|
|
105
|
+
checklist:
|
|
106
|
+
|
|
107
|
+
- every behavior the source exposes (operation, screen, command or job), each
|
|
108
|
+
with the test that would fail without it, or the missing test written or
|
|
109
|
+
reported;
|
|
110
|
+
- every test file: whether it runs in the whole suite, what it proves, what it
|
|
111
|
+
costs, and any test weakened, skipped or loosened;
|
|
112
|
+
- every list, batch and write path, with its query or call counts at a few rows
|
|
113
|
+
and at a realistic number;
|
|
114
|
+
- the Blueprint, Program and `genesis/subsystems.md` entries against the code;
|
|
115
|
+
- the cross-subsystem item: the same behavior tested in different ways or not
|
|
116
|
+
at all, a table with more than one owner, and work over a whole population
|
|
117
|
+
done inside a request.
|
|
118
|
+
|
|
119
|
+
Review's limits hold in a deep run: it writes only tests, and every other
|
|
120
|
+
finding is reported and left unchanged.
|
|
@@ -54,6 +54,10 @@ to another agent and do not generate it again. This step composes the selected
|
|
|
54
54
|
Stack's security pass guidance and any project customization with the portable
|
|
55
55
|
contract below.
|
|
56
56
|
|
|
57
|
+
When the user asks for a deep run of this pass, pass its Deep request,
|
|
58
|
+
`Security pass the whole app deeply.`, exactly;
|
|
59
|
+
Genesis then adds the run's `DEEP RUN` section.
|
|
60
|
+
|
|
57
61
|
## Resolve the scope
|
|
58
62
|
|
|
59
63
|
Inspect `git status --short` and the staged and unstaged diffs before editing.
|
|
@@ -61,9 +65,11 @@ A dirty worktree is allowed. Preserve the existing index and unrelated work; do
|
|
|
61
65
|
not stage, stash, commit, or discard changes as a prerequisite.
|
|
62
66
|
|
|
63
67
|
When the prompt has a `PASS RUN` section, the request is one of the pass's own
|
|
64
|
-
runs
|
|
65
|
-
the whole app,
|
|
66
|
-
|
|
68
|
+
runs (the whole app, the changes since its last completed run judged against
|
|
69
|
+
the whole app, or a deep run) or a run over the changes since a base commit the
|
|
70
|
+
request names, and its scope is the one that section states, whatever the
|
|
71
|
+
defaults below say. A deep run's prompt also has a `DEEP RUN`
|
|
72
|
+
section; follow it with "Deep run" below.
|
|
67
73
|
|
|
68
74
|
- **The whole app (default).** Every way in: each route, page, command,
|
|
69
75
|
action, message or socket handler, webhook, scheduled or background job,
|
|
@@ -277,3 +283,15 @@ step only to the pass's own runs, whose requests it writes itself, so a security
|
|
|
277
283
|
of a section, commits or your own changes is never recorded as the pass;
|
|
278
284
|
neither is a pass that stopped early, was abandoned or still has failing
|
|
279
285
|
checks.
|
|
286
|
+
|
|
287
|
+
## Deep run
|
|
288
|
+
|
|
289
|
+
When the prompt has a `DEEP RUN` section, follow it: it says how the checklist,
|
|
290
|
+
evidence, chunks, commits and report work for every pass. This pass adds to the
|
|
291
|
+
checklist:
|
|
292
|
+
|
|
293
|
+
- every way in from the map (each route, page, command, action, handler,
|
|
294
|
+
webhook, job, file read from outside and outbound call), every sign-in,
|
|
295
|
+
session and token flow, and every secret;
|
|
296
|
+
- the cross-subsystem item: one resource guarded differently on different
|
|
297
|
+
ways in, and a protection applied on some ways in but not on others.
|
|
@@ -53,6 +53,10 @@ to another agent and do not generate it again. This step composes the selected
|
|
|
53
53
|
Stack's speed pass guidance and any project customization with the portable
|
|
54
54
|
contract below.
|
|
55
55
|
|
|
56
|
+
When the user asks for a deep run of this pass, pass its Deep request,
|
|
57
|
+
`Speed pass the whole app deeply.`, exactly;
|
|
58
|
+
Genesis then adds the run's `DEEP RUN` section.
|
|
59
|
+
|
|
56
60
|
## Resolve the scope
|
|
57
61
|
|
|
58
62
|
Inspect `git status --short` and the staged and unstaged diffs before editing.
|
|
@@ -60,9 +64,11 @@ A dirty worktree is allowed. Preserve the existing index and unrelated work; do
|
|
|
60
64
|
not stage, stash, commit, or discard changes as a prerequisite.
|
|
61
65
|
|
|
62
66
|
When the prompt has a `PASS RUN` section, the request is one of the pass's own
|
|
63
|
-
runs
|
|
64
|
-
the whole app,
|
|
65
|
-
|
|
67
|
+
runs (the whole app, the changes since its last completed run judged against
|
|
68
|
+
the whole app, or a deep run) or a run over the changes since a base commit the
|
|
69
|
+
request names, and its scope is the one that section states, whatever the
|
|
70
|
+
defaults below say. A deep run's prompt also has a `DEEP RUN`
|
|
71
|
+
section; follow it with "Deep run" below.
|
|
66
72
|
|
|
67
73
|
- **The whole app (default).** The test suite and its preparation, every
|
|
68
74
|
screen, view or command a person opens and the main actions in it, and
|
|
@@ -331,3 +337,15 @@ step only to the pass's own runs, whose requests it writes itself, so a speed
|
|
|
331
337
|
pass of a section, commits or your own changes is never recorded as the pass;
|
|
332
338
|
neither is a pass that stopped early, was abandoned or still has failing
|
|
333
339
|
checks.
|
|
340
|
+
|
|
341
|
+
## Deep run
|
|
342
|
+
|
|
343
|
+
When the prompt has a `DEEP RUN` section, follow it: it says how the checklist,
|
|
344
|
+
evidence, chunks, commits and report work for every pass. This pass adds to the
|
|
345
|
+
checklist:
|
|
346
|
+
|
|
347
|
+
- every slow test file and phase of the suite, every screen's first load and
|
|
348
|
+
each navigation, every main request, command and job, startup, and work that
|
|
349
|
+
runs while nobody asks for anything, each measured before and after;
|
|
350
|
+
- the cross-subsystem item: the same work done in several places (repeated
|
|
351
|
+
setup, duplicate fetches, the same computation on several paths).
|
|
@@ -54,6 +54,10 @@ prompt as the instructions for this same turn; do not dispatch it to another
|
|
|
54
54
|
agent and do not generate it again. This step composes the selected Stack's UI
|
|
55
55
|
pass guidance and any project customization with the portable contract below.
|
|
56
56
|
|
|
57
|
+
When the user asks for a deep run of this pass, pass its Deep request,
|
|
58
|
+
`UI pass the whole app deeply.`, exactly;
|
|
59
|
+
Genesis then adds the run's `DEEP RUN` section.
|
|
60
|
+
|
|
57
61
|
## Resolve the scope
|
|
58
62
|
|
|
59
63
|
Inspect `git status --short` and the staged and unstaged diffs before editing.
|
|
@@ -61,9 +65,11 @@ A dirty worktree is allowed. Preserve the existing index and unrelated work; do
|
|
|
61
65
|
not stage, stash, commit, or discard changes as a prerequisite.
|
|
62
66
|
|
|
63
67
|
When the prompt has a `PASS RUN` section, the request is one of the pass's own
|
|
64
|
-
runs
|
|
65
|
-
the whole app,
|
|
66
|
-
|
|
68
|
+
runs (the whole app, the changes since its last completed run judged against
|
|
69
|
+
the whole app, or a deep run) or a run over the changes since a base commit the
|
|
70
|
+
request names, and its scope is the one that section states, whatever the
|
|
71
|
+
defaults below say. A deep run's prompt also has a `DEEP RUN`
|
|
72
|
+
section; follow it with "Deep run" below.
|
|
67
73
|
|
|
68
74
|
- **The changes (default).** With no stated scope, select only your own changes
|
|
69
75
|
for the current task, including preceding turns: staged, unstaged, untracked
|
|
@@ -127,3 +133,15 @@ step only to the pass's own runs, whose requests it writes itself, so a UI pass
|
|
|
127
133
|
of your own changes, a section or commits is never recorded as the pass;
|
|
128
134
|
neither is a pass that stopped early, was abandoned or still has failing
|
|
129
135
|
checks.
|
|
136
|
+
|
|
137
|
+
## Deep run
|
|
138
|
+
|
|
139
|
+
When the prompt has a `DEEP RUN` section, follow it: it says how the checklist,
|
|
140
|
+
evidence, chunks, commits and report work for every pass. This pass adds to the
|
|
141
|
+
checklist:
|
|
142
|
+
|
|
143
|
+
- every screen (page, view, dialog or panel) and every shared interface
|
|
144
|
+
component, each checked against the Stack's design rules, with a screenshot
|
|
145
|
+
after any change;
|
|
146
|
+
- the cross-subsystem item: the same control, layout or pattern built or
|
|
147
|
+
styled differently on different screens.
|
|
@@ -54,6 +54,10 @@ turn; do not dispatch it to another agent and do not generate it again. This
|
|
|
54
54
|
step composes the selected Stack's user experience pass guidance and any
|
|
55
55
|
project customization with the portable contract below.
|
|
56
56
|
|
|
57
|
+
When the user asks for a deep run of this pass, pass its Deep request,
|
|
58
|
+
`User experience pass the whole app deeply.`, exactly;
|
|
59
|
+
Genesis then adds the run's `DEEP RUN` section.
|
|
60
|
+
|
|
57
61
|
## Resolve the scope
|
|
58
62
|
|
|
59
63
|
Inspect `git status --short` and the staged and unstaged diffs before editing.
|
|
@@ -61,9 +65,11 @@ A dirty worktree is allowed. Preserve the existing index and unrelated work; do
|
|
|
61
65
|
not stage, stash, commit, or discard changes as a prerequisite.
|
|
62
66
|
|
|
63
67
|
When the prompt has a `PASS RUN` section, the request is one of the pass's own
|
|
64
|
-
runs
|
|
65
|
-
the whole app,
|
|
66
|
-
|
|
68
|
+
runs (the whole app, the changes since its last completed run judged against
|
|
69
|
+
the whole app, or a deep run) or a run over the changes since a base commit the
|
|
70
|
+
request names, and its scope is the one that section states, whatever the
|
|
71
|
+
defaults below say. A deep run's prompt also has a `DEEP RUN`
|
|
72
|
+
section; follow it with "Deep run" below.
|
|
67
73
|
|
|
68
74
|
- **The whole app (default).** Every main task a person comes to do, from
|
|
69
75
|
where they start to where it is done.
|
|
@@ -257,3 +263,14 @@ step only to the pass's own runs, whose requests it writes itself, so a user exp
|
|
|
257
263
|
of a section, commits or your own changes is never recorded as the pass;
|
|
258
264
|
neither is a pass that stopped early, was abandoned or still has failing
|
|
259
265
|
checks.
|
|
266
|
+
|
|
267
|
+
## Deep run
|
|
268
|
+
|
|
269
|
+
When the prompt has a `DEEP RUN` section, follow it: it says how the checklist,
|
|
270
|
+
evidence, chunks, commits and report work for every pass. This pass adds to the
|
|
271
|
+
checklist:
|
|
272
|
+
|
|
273
|
+
- every main task, walked as a new and as a returning person, with its steps
|
|
274
|
+
and decisions counted before and after;
|
|
275
|
+
- the cross-subsystem item: similar tasks or screens that work differently,
|
|
276
|
+
and one thing called by different names.
|
package/src/cli-commands.js
CHANGED
|
@@ -72,7 +72,9 @@ async function execute({ command, operands, options }, { signal, hostContext = n
|
|
|
72
72
|
}
|
|
73
73
|
if (command === 'migrate') return migrate({ projectRoot, stackPackages });
|
|
74
74
|
if (command === 'skills') return syncSkills({ projectRoot, stackPackages });
|
|
75
|
-
if (command === 'passes')
|
|
75
|
+
if (command === 'passes') {
|
|
76
|
+
return { action: 'done', ...await recordPassDone({ projectRoot, pass: operands[1], passes: operands.slice(2) }) };
|
|
77
|
+
}
|
|
76
78
|
if (command === 'adopt') {
|
|
77
79
|
return adoptProject({ projectRoot, request: operands.join(' '), stackPackages });
|
|
78
80
|
}
|
package/src/cli.js
CHANGED
|
@@ -27,6 +27,7 @@ const USAGE = `Usage:
|
|
|
27
27
|
genesis stack add <piece...>
|
|
28
28
|
genesis skills sync
|
|
29
29
|
genesis passes done <pass>
|
|
30
|
+
genesis passes done master-pass <pass...>
|
|
30
31
|
genesis templates list
|
|
31
32
|
genesis templates apply <catalogue:technology/variant>
|
|
32
33
|
genesis context <path...>
|
|
@@ -42,7 +43,7 @@ const USAGE = `Usage:
|
|
|
42
43
|
genesis inspect passes
|
|
43
44
|
genesis inspect section <name>
|
|
44
45
|
genesis prompt [request...]
|
|
45
|
-
genesis prompt --task <start|adopt|work|deslop|ui-pass|identity-pass|quality-pass|data-pass|security-pass|ux-pass|speed-pass|program|blueprint|describe|review> [request...]
|
|
46
|
+
genesis prompt --task <start|adopt|work|deslop|ui-pass|identity-pass|quality-pass|data-pass|security-pass|ux-pass|speed-pass|master-pass|program|blueprint|describe|review> [request...]
|
|
46
47
|
genesis verify
|
|
47
48
|
genesis check
|
|
48
49
|
|
|
@@ -179,8 +180,10 @@ function parseCommand(argv) {
|
|
|
179
180
|
fail('CLI_SKILLS_ACTION_REQUIRED', 'Command skills requires exactly: sync.');
|
|
180
181
|
}
|
|
181
182
|
} else if (command === 'passes') {
|
|
182
|
-
|
|
183
|
-
|
|
183
|
+
// Only the Master pass records the passes it ran with it.
|
|
184
|
+
const master = operands[1] === 'master-pass';
|
|
185
|
+
if (operands[0] !== 'done' || (master ? operands.length < 3 : operands.length !== 2)) {
|
|
186
|
+
fail('CLI_PASSES_ACTION_REQUIRED', 'Command passes requires exactly: done <pass>, or done master-pass <pass...>.');
|
|
184
187
|
}
|
|
185
188
|
} else if (command === 'codex') {
|
|
186
189
|
if (operands.length !== 1 || operands[0] !== 'install') {
|
|
@@ -317,10 +320,15 @@ function writeResult(command, result) {
|
|
|
317
320
|
line(process.stdout, ` recommended ${pass.recommend.hint}; Stack guidance: ${pass.stackGuidance ? 'yes' : 'no'}; last run: ${pass.lastRun ?? 'never'}`);
|
|
318
321
|
if (pass.unavailable && !result.unavailable) line(process.stdout, ` unavailable: ${pass.unavailable}`);
|
|
319
322
|
}
|
|
323
|
+
const { master } = result;
|
|
324
|
+
line(process.stdout, `${master.id}: ${master.title} — ${master.description}`);
|
|
325
|
+
if (master.unavailable) line(process.stdout, ` unavailable: ${master.unavailable}`);
|
|
326
|
+
else line(process.stdout, ` runs, in order: ${master.passes.join(', ')}; last run: ${master.lastRun ?? 'never'}`);
|
|
320
327
|
return;
|
|
321
328
|
}
|
|
322
329
|
if (command === 'passes') {
|
|
323
|
-
|
|
330
|
+
const ran = result.passes ? ` with ${result.passes.join(', ')}` : '';
|
|
331
|
+
line(process.stdout, `${result.pass}: recorded ${result.lastRun}${ran} in ${result.path}`);
|
|
324
332
|
return;
|
|
325
333
|
}
|
|
326
334
|
if (command === 'inspect' && result.inspection === 'skills') {
|
|
@@ -17,7 +17,7 @@ import { parse as parseYaml } from 'yaml';
|
|
|
17
17
|
|
|
18
18
|
import { asDiagnostic, GenesisError } from './errors.js';
|
|
19
19
|
import { claudeSkillLinks } from './claude-hooks.js';
|
|
20
|
-
import { PASSES } from './passes.js';
|
|
20
|
+
import { MASTER_PASS, PASSES } from './passes.js';
|
|
21
21
|
import { sha256, stableJson, writeFileAtomic } from './utils.js';
|
|
22
22
|
|
|
23
23
|
const packageRoot = fileURLToPath(new URL('../../', import.meta.url));
|
|
@@ -35,12 +35,13 @@ const SKILL_FIELDS = new Set([
|
|
|
35
35
|
'allowed-tools',
|
|
36
36
|
]);
|
|
37
37
|
|
|
38
|
-
// This release's Genesis workflow skills: the project and Program skills,
|
|
39
|
-
// directory holds exactly these, as every release's does (see projectGenesis).
|
|
38
|
+
// This release's Genesis workflow skills: the project and Program skills, one for each pass and one for the Master
|
|
39
|
+
// pass. Its skills directory holds exactly these, as every release's does (see projectGenesis).
|
|
40
40
|
export const CORE_SKILL_NAMES = Object.freeze([
|
|
41
41
|
'genesis-project',
|
|
42
42
|
'genesis-program',
|
|
43
43
|
...PASSES.map(({ task }) => `genesis-${task}`),
|
|
44
|
+
`genesis-${MASTER_PASS.task}`,
|
|
44
45
|
]);
|
|
45
46
|
|
|
46
47
|
function invalidSkill(message, details = {}) {
|
package/src/index/assets.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
|
|
3
|
-
import { PASSES } from './passes.js';
|
|
3
|
+
import { MASTER_PASS, PASSES } from './passes.js';
|
|
4
4
|
|
|
5
5
|
const root = new URL('../../', import.meta.url);
|
|
6
6
|
const assets = {
|
|
@@ -12,6 +12,9 @@ const assets = {
|
|
|
12
12
|
work: new URL('prompts/work.txt', root),
|
|
13
13
|
describe: new URL('prompts/describe.txt', root),
|
|
14
14
|
...Object.fromEntries(PASSES.map(({ task }) => [task, new URL(`prompts/${task}.txt`, root)])),
|
|
15
|
+
[MASTER_PASS.task]: new URL('prompts/master-pass.txt', root),
|
|
16
|
+
'pass-report': new URL('prompts/pass-report.txt', root),
|
|
17
|
+
'pass-deep': new URL('prompts/pass-deep.txt', root),
|
|
15
18
|
program: new URL('prompts/program.txt', root),
|
|
16
19
|
blueprint: new URL('prompts/blueprint.txt', root),
|
|
17
20
|
review: new URL('prompts/review.txt', root),
|
package/src/index/code-index.js
CHANGED
|
@@ -19,6 +19,7 @@ import { attachEntryFunctions, discoverEntryPoints } from './entry-points.js';
|
|
|
19
19
|
import { runGit } from './process.js';
|
|
20
20
|
import { CITY_SCHEMA_VERSION, MACHINE_CITY_SCHEMA, PROGRAM_CITY_SCHEMA } from './city-documents.js';
|
|
21
21
|
import { gitVisibleFileStates } from './project-files.js';
|
|
22
|
+
import { stackPackageRoots } from './source-size.js';
|
|
22
23
|
import { readStack } from './stack.js';
|
|
23
24
|
import { sha256, stableJson, stableJsonParts } from './utils.js';
|
|
24
25
|
|
|
@@ -388,7 +389,7 @@ export async function buildProjectIndex({
|
|
|
388
389
|
if (observationReader) observations = null;
|
|
389
390
|
const root = (await gitContext(projectRoot)).repositoryRoot;
|
|
390
391
|
const stack = await readStack(root, { allowUnresolvedSections, stackPackages });
|
|
391
|
-
const packageRoots = stack
|
|
392
|
+
const packageRoots = stackPackageRoots(stack);
|
|
392
393
|
const includePath = filePath => isProjectContentPath(filePath) && !packageRoots.some(directory => filePath === directory || filePath.startsWith(`${directory}/`));
|
|
393
394
|
const states = await gitVisibleFileStates(root, { includePath });
|
|
394
395
|
const files = [...states]
|
package/src/index/contracts.js
CHANGED
|
@@ -4,6 +4,7 @@ export const GENESIS_CONTRACTS = Object.freeze({
|
|
|
4
4
|
promptTasks: 'genesis.prompt-tasks.v1',
|
|
5
5
|
passes: 'genesis.passes.v1',
|
|
6
6
|
passRuns: 'genesis.pass-runs.v1',
|
|
7
|
+
deepRuns: 'genesis.deep-runs.v1',
|
|
7
8
|
templates: 'genesis.templates.v1',
|
|
8
9
|
templateApplication: 'genesis.template-application.v1',
|
|
9
10
|
collaboration: 'genesis.collaboration.v1',
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { GenesisError } from './errors.js';
|
|
2
|
+
import { ADDED_PASS_RECORD_PATH } from './pass-record.js';
|
|
3
|
+
import { deepRequest, MASTER_PASS } from './passes.js';
|
|
4
|
+
|
|
5
|
+
// The names a request may give a pass: its id or its title, either without "pass", in any case.
|
|
6
|
+
function passNames(pass) {
|
|
7
|
+
return [pass.task, pass.title, pass.task.replace(/-pass$/u, ''), pass.title.replace(/ pass$/iu, '')]
|
|
8
|
+
.map((name) => name.toLowerCase());
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const NAMED = new RegExp(`^${MASTER_PASS.title} \\(([^()]*)\\)(.*)$`, 'su');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The run and the passes a Master pass request asks for. The request is one of the runs Genesis writes (`runs`),
|
|
15
|
+
* optionally naming the passes in brackets after "Master pass", such as `Master pass (security, data, deslop) the whole
|
|
16
|
+
* app.`; without names it runs every pass the project offers. The passes run in the Master order, whatever order they
|
|
17
|
+
* were named in. Any other request, or a name the project offers no pass for, is refused, naming what it accepts.
|
|
18
|
+
* @param {string} request the request's last paragraph, after any framing a host put before it
|
|
19
|
+
* @param {{ request: string }[]} runs the Master pass's runs
|
|
20
|
+
* @param {{ task: string, title: string }[]} offered the passes the project offers, in the Master order
|
|
21
|
+
*/
|
|
22
|
+
export function masterSelection(request, runs, offered) {
|
|
23
|
+
const named = NAMED.exec(request);
|
|
24
|
+
const run = runs.find((entry) => entry.request === (named ? `${MASTER_PASS.title}${named[2]}` : request));
|
|
25
|
+
if (!run) {
|
|
26
|
+
throw new GenesisError('PASS_REQUEST_INVALID', `A ${MASTER_PASS.title} request is ${runs.map(({ request: text }) => `"${text}"`).join(' or ')}, `
|
|
27
|
+
+ `naming the passes to run, if not all, in brackets after "${MASTER_PASS.title}", such as "${MASTER_PASS.title} (security, data, deslop) the whole app."`);
|
|
28
|
+
}
|
|
29
|
+
if (!named) return { run, passes: offered };
|
|
30
|
+
const chosen = new Set();
|
|
31
|
+
for (const name of named[1].split(/,|\s+and\s+/u).map((part) => part.trim()).filter(Boolean)) {
|
|
32
|
+
const pass = offered.find((entry) => passNames(entry).includes(name.toLowerCase()));
|
|
33
|
+
if (!pass) {
|
|
34
|
+
throw new GenesisError('PASS_UNKNOWN', `The ${MASTER_PASS.title} cannot run "${name}". Name any of: `
|
|
35
|
+
+ `${offered.map(({ task, title }) => `${title} (${task})`).join(', ')}.`, { pass: name });
|
|
36
|
+
}
|
|
37
|
+
chosen.add(pass);
|
|
38
|
+
}
|
|
39
|
+
if (chosen.size === 0) {
|
|
40
|
+
throw new GenesisError('PASS_REQUEST_INVALID', `The ${MASTER_PASS.title} request names no pass in its brackets; leave them out to run every pass.`);
|
|
41
|
+
}
|
|
42
|
+
return { run, passes: offered.filter((pass) => chosen.has(pass)) };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The prompt's MASTER PASS section: the run's scope, the passes to run in order, each with the request of its own
|
|
47
|
+
* Deep run, and where the Master ledger lives. The Master pass adds only this sequence: each pass's Deep run says how
|
|
48
|
+
* that pass works, from that pass's own prompt, and is never copied here.
|
|
49
|
+
*/
|
|
50
|
+
export function masterPassSection({ run, passes, ledger }) {
|
|
51
|
+
const scope = run.commit
|
|
52
|
+
? `over the changes since commit ${run.commit}, the commit of its last completed run, judged against the whole app`
|
|
53
|
+
: 'over the whole app';
|
|
54
|
+
return [
|
|
55
|
+
`This request is a ${MASTER_PASS.title} ${scope}. It runs these passes deeply, one after another, in this`,
|
|
56
|
+
'order, each as that pass\'s own Deep run: generate its prompt with the Genesis `prompt` operation and the exact',
|
|
57
|
+
`request below, as \`.agents/skills/genesis-${MASTER_PASS.task}/SKILL.md\` says, and follow it in full before the`,
|
|
58
|
+
'next pass starts.',
|
|
59
|
+
'',
|
|
60
|
+
...passes.map((pass, index) => `${index + 1}. ${pass.title}: \`prompt --task ${pass.task} "${deepRequest(pass, run.commit)}"\``),
|
|
61
|
+
'',
|
|
62
|
+
`Keep the Master ledger at \`${ledger}\`.`,
|
|
63
|
+
].join('\n');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// A Master pass's prompt ends with recording it, with the passes it ran, as its last commit.
|
|
67
|
+
export function masterRecordStep() {
|
|
68
|
+
return [
|
|
69
|
+
'Only once every listed pass has finished or been skipped, make your last step the',
|
|
70
|
+
`Genesis \`passes done ${MASTER_PASS.task} <pass id...>\` operation, naming the passes it ran`,
|
|
71
|
+
`and leaving out those it skipped, invoked as \`.agents/skills/genesis-${MASTER_PASS.task}/SKILL.md\``,
|
|
72
|
+
`says. It records the time and those passes in \`${ADDED_PASS_RECORD_PATH}\`; commit that change`,
|
|
73
|
+
`as the ${MASTER_PASS.title}'s last commit. Do not run it for a ${MASTER_PASS.title} that stopped`,
|
|
74
|
+
'early, was abandoned, or still has failing checks.',
|
|
75
|
+
].join('\n');
|
|
76
|
+
}
|