genesis-compiler 1.10.20 → 1.10.22
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 +74 -16
- package/docs/prompt-integration.md +19 -5
- package/docs/stack-components.md +22 -5
- package/package.json +11 -1
- package/plugins/genesis/.codex-plugin/plugin.json +1 -1
- package/prompts/deslop.txt +3 -0
- 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/prompts/security-pass.txt +26 -0
- package/prompts/speed-pass.txt +28 -0
- package/prompts/ui-pass.txt +3 -1
- package/prompts/ux-pass.txt +25 -0
- package/skills/genesis-data-pass/SKILL.md +29 -4
- package/skills/genesis-deslop/SKILL.md +47 -6
- package/skills/genesis-identity-pass/SKILL.md +29 -4
- package/skills/genesis-master-pass/SKILL.md +132 -0
- package/skills/genesis-master-pass/agents/openai.yaml +4 -0
- package/skills/genesis-quality-pass/SKILL.md +30 -4
- package/skills/genesis-review/SKILL.md +120 -0
- package/skills/genesis-review/agents/openai.yaml +4 -0
- package/skills/genesis-security-pass/SKILL.md +297 -0
- package/skills/genesis-security-pass/agents/openai.yaml +4 -0
- package/skills/genesis-speed-pass/SKILL.md +351 -0
- package/skills/genesis-speed-pass/agents/openai.yaml +4 -0
- package/skills/genesis-ui-pass/SKILL.md +38 -7
- package/skills/genesis-ux-pass/SKILL.md +276 -0
- package/skills/genesis-ux-pass/agents/openai.yaml +4 -0
- package/src/cli-commands.js +3 -1
- package/src/cli.js +14 -4
- package/src/index/agent-skills.js +53 -29
- package/src/index/assets.js +4 -1
- package/src/index/code-index.js +2 -1
- package/src/index/contracts.js +2 -0
- package/src/index/master-pass.js +76 -0
- package/src/index/pass-record.js +124 -22
- package/src/index/pass-support.js +71 -0
- package/src/index/passes.js +92 -5
- package/src/index/project-files.js +2 -1
- package/src/index/prompt.js +306 -28
- package/src/index/source-size.js +62 -0
- package/src/index.js +6 -1
|
@@ -46,18 +46,31 @@ If the current task already contains `GENESIS CONTEXT` whose task is
|
|
|
46
46
|
|
|
47
47
|
Otherwise, before resolving scope, run the Genesis `prompt --task ui-pass`
|
|
48
48
|
operation once using the invocation rule above. For a bare `UI pass` request,
|
|
49
|
-
pass no request argument. When the user names commits
|
|
50
|
-
|
|
49
|
+
pass no request argument. When the user names commits or a section, pass that
|
|
50
|
+
exact request as one safely quoted argument. When the user asks for the UI pass
|
|
51
|
+
of the whole app, pass its own pass request, `UI pass the whole app.`, exactly;
|
|
52
|
+
Genesis then adds the pass's `PASS RUN` and `PASS RECORD` steps. Treat the printed
|
|
51
53
|
prompt as the instructions for this same turn; do not dispatch it to another
|
|
52
54
|
agent and do not generate it again. This step composes the selected Stack's UI
|
|
53
55
|
pass guidance and any project customization with the portable contract below.
|
|
54
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
|
+
|
|
55
61
|
## Resolve the scope
|
|
56
62
|
|
|
57
63
|
Inspect `git status --short` and the staged and unstaged diffs before editing.
|
|
58
64
|
A dirty worktree is allowed. Preserve the existing index and unrelated work; do
|
|
59
65
|
not stage, stash, commit, or discard changes as a prerequisite.
|
|
60
66
|
|
|
67
|
+
When the prompt has a `PASS RUN` section, the request is one of the pass's own
|
|
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.
|
|
73
|
+
|
|
61
74
|
- **The changes (default).** With no stated scope, select only your own changes
|
|
62
75
|
for the current task, including preceding turns: staged, unstaged, untracked
|
|
63
76
|
and already-committed task changes, identified from task and edit history and
|
|
@@ -70,7 +83,10 @@ not stage, stash, commit, or discard changes as a prerequisite.
|
|
|
70
83
|
UI changes, report that there is nothing to pass.
|
|
71
84
|
- **A section.** A named area (a module, a route subtree, a set of screens, or
|
|
72
85
|
a shared component family): every screen in it, touched or not.
|
|
73
|
-
- **The whole app.**
|
|
86
|
+
- **The whole app.** The UI pass's own pass request, `UI pass the whole app.`:
|
|
87
|
+
every screen of the project's own source, the shell and navigation included,
|
|
88
|
+
whoever changed it and whenever. It never includes generated output, vendored
|
|
89
|
+
or copied third-party UI, or dependency directories.
|
|
74
90
|
|
|
75
91
|
If the scope is ambiguous, ask which changes or which section.
|
|
76
92
|
|
|
@@ -110,7 +126,22 @@ scope and any commit identities, what changed, files changed, the checks and
|
|
|
110
126
|
screenshots actually taken (with their paths), and follow-up findings left
|
|
111
127
|
unchanged.
|
|
112
128
|
|
|
113
|
-
|
|
114
|
-
Genesis `passes done ui-pass` operation records it in `genesis/passes.json`,
|
|
115
|
-
uncommitted change that lands in the pass's own commit.
|
|
116
|
-
|
|
129
|
+
When the prompt ends with a `PASS RECORD` step, take it once the pass has
|
|
130
|
+
finished: the Genesis `passes done ui-pass` operation records it in `genesis/passes.json`,
|
|
131
|
+
an uncommitted change that lands in the pass's own commit. Genesis adds that
|
|
132
|
+
step only to the pass's own runs, whose requests it writes itself, so a UI pass
|
|
133
|
+
of your own changes, a section or commits is never recorded as the pass;
|
|
134
|
+
neither is a pass that stopped early, was abandoned or still has failing
|
|
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.
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: genesis-ux-pass
|
|
3
|
+
description: Make software easy to use for what people come to do through an explicitly requested user experience pass over the whole app, a named section, or the agent's own changes, covering each main task's steps, navigation and findability, the words people read, defaults, first use, feedback and forgiving actions, verified by walking each task before and after. Use when asked for a UX pass, a user experience review that fixes what it finds, or to make the app simpler or clearer to use.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Genesis user experience pass
|
|
7
|
+
|
|
8
|
+
Make the main things people do with the software short, clear and hard to get
|
|
9
|
+
wrong, and prove it by walking each one. A user experience pass 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
|
+
## Load the effective project instructions once
|
|
40
|
+
|
|
41
|
+
A user experience pass request may arrive as a complete Genesis-generated
|
|
42
|
+
prompt or as a direct request such as `User experience pass`, `UX pass` or
|
|
43
|
+
`UX pass the checkout`.
|
|
44
|
+
|
|
45
|
+
If the current task already contains `GENESIS CONTEXT` whose task is
|
|
46
|
+
`ux-pass`, continue with it directly. Do not generate another prompt.
|
|
47
|
+
|
|
48
|
+
Otherwise, before resolving scope, run the Genesis `prompt --task ux-pass`
|
|
49
|
+
operation once using the invocation rule above. For a bare `User experience
|
|
50
|
+
pass` or `UX pass` request, pass no request argument. When the user names a
|
|
51
|
+
section, commits or your own changes, pass that exact request as one safely
|
|
52
|
+
quoted argument. Treat the printed prompt as the instructions for this same
|
|
53
|
+
turn; do not dispatch it to another agent and do not generate it again. This
|
|
54
|
+
step composes the selected Stack's user experience pass guidance and any
|
|
55
|
+
project customization with the portable contract below.
|
|
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
|
+
|
|
61
|
+
## Resolve the scope
|
|
62
|
+
|
|
63
|
+
Inspect `git status --short` and the staged and unstaged diffs before editing.
|
|
64
|
+
A dirty worktree is allowed. Preserve the existing index and unrelated work; do
|
|
65
|
+
not stage, stash, commit, or discard changes as a prerequisite.
|
|
66
|
+
|
|
67
|
+
When the prompt has a `PASS RUN` section, the request is one of the pass's own
|
|
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.
|
|
73
|
+
|
|
74
|
+
- **The whole app (default).** Every main task a person comes to do, from
|
|
75
|
+
where they start to where it is done.
|
|
76
|
+
- **A section.** A named area (a module, a set of screens or commands, a game
|
|
77
|
+
mode): every task that runs through it, touched or not.
|
|
78
|
+
- **The changes.** Your own changes for the current task, or explicit commits,
|
|
79
|
+
established and resolved as for Deslop: the tasks they create or change,
|
|
80
|
+
each walked from its start.
|
|
81
|
+
|
|
82
|
+
If the scope is ambiguous, ask which section or changes.
|
|
83
|
+
|
|
84
|
+
## Know who it is for and what they come to do
|
|
85
|
+
|
|
86
|
+
Read the Blueprint first: who uses the software, what they come to do, and the
|
|
87
|
+
first useful outcome it promises. From it and from the software itself, list
|
|
88
|
+
the main tasks in scope: the few things people do most often or care about
|
|
89
|
+
most, such as placing an order, answering a message, running a build from the
|
|
90
|
+
command line or starting a match. For each, note who does it (a first-time
|
|
91
|
+
visitor, a regular, an occasional administrator), how often, and what done
|
|
92
|
+
looks like to them. A pass that polishes screens nobody reaches while the main
|
|
93
|
+
task stays long has missed its point.
|
|
94
|
+
|
|
95
|
+
The sanity checks guide
|
|
96
|
+
(`.agents/skills/genesis-project/references/sanity-checks.md`) sections
|
|
97
|
+
"Screens in use", "The wait a person sees" and "State and workflow" describe
|
|
98
|
+
what good looks like; read them before walking.
|
|
99
|
+
|
|
100
|
+
## Walk each task before changing anything
|
|
101
|
+
|
|
102
|
+
Walk each main task through the real interface (a browser, a terminal, a
|
|
103
|
+
device, the game itself), twice when possible: once as a new person with no
|
|
104
|
+
data and no knowledge of the code, once as a returning person with realistic
|
|
105
|
+
data. Start where that person starts: the address they were given, a link in an
|
|
106
|
+
email, the installed command, the title screen. For each walk, write down:
|
|
107
|
+
|
|
108
|
+
- each step (a screen, a field, a click, a command, a menu) and each decision
|
|
109
|
+
the person must make to reach done;
|
|
110
|
+
- each place where they must know something the software doesn't tell them:
|
|
111
|
+
an internal name, an id, where a feature hides, what to type;
|
|
112
|
+
- each wait and each moment where nothing says what happened;
|
|
113
|
+
- each dead end, each detour back to the start, and each place where a mistake
|
|
114
|
+
costs work.
|
|
115
|
+
|
|
116
|
+
These notes are what the pass is measured against; keep them for the report.
|
|
117
|
+
Reading code shows what the software can do; only walking it shows what a
|
|
118
|
+
person has to do.
|
|
119
|
+
|
|
120
|
+
## Fewer steps and decisions
|
|
121
|
+
|
|
122
|
+
- **Ask only what is needed now.** A field, question or setting the task can
|
|
123
|
+
do without moves later or out of the way, with a default when possible.
|
|
124
|
+
Every extra field is a chance to stop, so each one earns its place.
|
|
125
|
+
- **Good defaults.** Pre-fill what the software knows or can reasonably guess:
|
|
126
|
+
today's date, the person's own details, the last choice they made, the only
|
|
127
|
+
option there is. When one choice is clearly sensible, take it and let the
|
|
128
|
+
person change it, rather than asking.
|
|
129
|
+
- **Remember where they were.** Return a person to the place, filters and
|
|
130
|
+
choices they left when possible, so coming back doesn't start over.
|
|
131
|
+
- **The next step is obvious.** After each step, the most likely next action is
|
|
132
|
+
the most visible one, near where the person's attention already is. A
|
|
133
|
+
finished task leads somewhere useful, not to a blank page.
|
|
134
|
+
- **Do the work for them.** When the software can compute, look up or fill in
|
|
135
|
+
something (a total, an address from a postcode, a name from an id), it does,
|
|
136
|
+
and the person confirms instead of typing.
|
|
137
|
+
- **Keep related steps together.** What belongs together happens in one place,
|
|
138
|
+
instead of a trip across several screens or commands.
|
|
139
|
+
|
|
140
|
+
## Easy to find
|
|
141
|
+
|
|
142
|
+
- **Where people look.** Each main task is reachable from where its people
|
|
143
|
+
start, in one or two steps when possible, and named in the main navigation,
|
|
144
|
+
the command's help or the game's main menu. A frequent task is never buried
|
|
145
|
+
in settings or an overflow menu.
|
|
146
|
+
- **Names people use.** Navigation, labels and commands use the words people
|
|
147
|
+
use for things, the ones the Blueprint uses, not the code's internal names.
|
|
148
|
+
- **Search where lists grow.** A list that can grow past a screenful can be
|
|
149
|
+
searched or filtered by what people remember about an item.
|
|
150
|
+
- **Every place has an address.** A page or record people share or come back
|
|
151
|
+
to opens directly from its link, and going back returns them where they came
|
|
152
|
+
from.
|
|
153
|
+
- **Beyond screens.** A command-line program lists its commands and options
|
|
154
|
+
with examples in `--help`, suggests the closest command for a typo and keeps
|
|
155
|
+
the common case short; a game shows its controls when they are needed and
|
|
156
|
+
lets the player reach each mode from the main menu.
|
|
157
|
+
|
|
158
|
+
## Words
|
|
159
|
+
|
|
160
|
+
- **Say what happens.** A button or command says what it does to what: "Send
|
|
161
|
+
invoice", not "Submit" or "OK". People decide from the label, so it carries
|
|
162
|
+
the consequence.
|
|
163
|
+
- **One name for each thing.** The same thing has the same name everywhere:
|
|
164
|
+
navigation, titles, buttons, messages, help and emails. Two names make people
|
|
165
|
+
wonder whether they are two things.
|
|
166
|
+
- **Plain and short.** Everyday words and the person's own terms, never
|
|
167
|
+
jargon, internal codes or ids; the important word comes first.
|
|
168
|
+
- **Say what happened and what's next.** After an action, the software says
|
|
169
|
+
what changed and, when there is one, what the person can do next.
|
|
170
|
+
- **Translated text stays translatable.** In translated software, changed
|
|
171
|
+
words go through its translation keys, not stored or hard-coded text.
|
|
172
|
+
|
|
173
|
+
## First use
|
|
174
|
+
|
|
175
|
+
- **To the first useful outcome.** A new person reaches the first outcome the
|
|
176
|
+
Blueprint promises in as few steps and with as little setup as possible,
|
|
177
|
+
without reading instructions when possible. Setup that can wait, waits.
|
|
178
|
+
- **Show by example.** Where a blank start would leave people guessing, offer
|
|
179
|
+
an example, a template or sample content they can try and remove.
|
|
180
|
+
- **One way to learn.** What a new person learns works the same way for a
|
|
181
|
+
returning one, and first-use help gets out of the way once it has done its
|
|
182
|
+
job.
|
|
183
|
+
|
|
184
|
+
## Forgiving
|
|
185
|
+
|
|
186
|
+
- **Undo over confirm.** When an action can be undone (archive, move, remove
|
|
187
|
+
from a list), do it at once and offer Undo, rather than asking first; people
|
|
188
|
+
click through confirmations they see too often. Confirmation stays for what
|
|
189
|
+
cannot be undone, and names the thing and what will be lost: "Delete the
|
|
190
|
+
project Spring launch and its 40 tasks?".
|
|
191
|
+
- **Keep the person's work.** Typed input survives a refused save, going back
|
|
192
|
+
or an expired session when possible, and leaving unsaved work asks first or
|
|
193
|
+
keeps a draft.
|
|
194
|
+
- **A way out of every step.** Each step can be cancelled, and leaving a flow
|
|
195
|
+
returns to where it began. A long task can be paused and resumed.
|
|
196
|
+
- **Hard to get wrong.** Offer choices instead of free text where the set is
|
|
197
|
+
known, show the expected format before the person types, and accept the
|
|
198
|
+
common ways of writing a value (spaces in a phone number, a date written
|
|
199
|
+
several ways) when possible.
|
|
200
|
+
|
|
201
|
+
## Consistent
|
|
202
|
+
|
|
203
|
+
- **Same thing, same place.** Similar screens put their main action, their
|
|
204
|
+
search and their way out in the same place, so learning one teaches the
|
|
205
|
+
rest.
|
|
206
|
+
- **The platform's conventions.** Follow what people already know from their
|
|
207
|
+
platform: links, Back and new tabs on the web; exit codes, standard input
|
|
208
|
+
and `--yes` or `--dry-run` on a command line; a pause menu and a way back to
|
|
209
|
+
the title screen in a game. Where the selected Stack's design guidance
|
|
210
|
+
decides, it comes first.
|
|
211
|
+
|
|
212
|
+
## Walk again and prove it
|
|
213
|
+
|
|
214
|
+
- Walk each main task again exactly as before, as the new and the returning
|
|
215
|
+
person, and compare: steps, decisions, things they had to know unprompted,
|
|
216
|
+
waits without feedback, dead ends. The report gives each task's counts
|
|
217
|
+
before and after.
|
|
218
|
+
- Where the project's tests can drive a flow (a browser test, a command-line
|
|
219
|
+
test, a scripted playthrough), lock the changed path in at the cheapest level
|
|
220
|
+
that proves it, and watch the test fail once against the old path. Run the
|
|
221
|
+
focused tests of the affected areas and the checks the Stack guidance names.
|
|
222
|
+
- Take screenshots, terminal transcripts or recordings of each changed step,
|
|
223
|
+
at phone and desktop widths on the web, and look at every one. Keep them out
|
|
224
|
+
of the repository's tracked files, delete temporary test files, and close
|
|
225
|
+
every browser and process you start.
|
|
226
|
+
|
|
227
|
+
## Boundaries
|
|
228
|
+
|
|
229
|
+
- **The path changes, the product doesn't.** The pass changes the steps,
|
|
230
|
+
words, defaults, order and placement a task takes. It adds no feature and
|
|
231
|
+
changes no permission, product rule, price, limit or stored data. A missing
|
|
232
|
+
feature, a rule that makes a task long, or a choice only the person can make
|
|
233
|
+
is a finding with a recommendation, left unchanged.
|
|
234
|
+
- **Never trade safety for a step.** Never remove a permission check, a
|
|
235
|
+
validation, the confirmation of an irreversible action, or a security step
|
|
236
|
+
such as a second factor to make a task shorter.
|
|
237
|
+
- **Other passes own their parts.** How screens look belongs to the UI pass
|
|
238
|
+
and the visual identity pass; loading, empty and error states, edge cases
|
|
239
|
+
and accessibility belong to the quality pass. Record what you notice there
|
|
240
|
+
as findings for those passes, unless it blocks a main task.
|
|
241
|
+
- The selected Stack's user experience pass guidance names where navigation,
|
|
242
|
+
actions, defaults and words live in its technology; follow it.
|
|
243
|
+
- **Fix at the owner.** When the framework itself makes a task long, report the
|
|
244
|
+
exact framework change instead of working around it in the app.
|
|
245
|
+
- You may edit source, styles, messages and tests in scope; every existing
|
|
246
|
+
behavior assertion stays, and an assertion of old wording or an old step
|
|
247
|
+
changes with it. Do not edit `.genesis/`, Git metadata, dependency
|
|
248
|
+
directories, generated build output, retained migration history, or external
|
|
249
|
+
resources. When a task's observable steps change, keep the Blueprint, the
|
|
250
|
+
Program and the project's usage documentation in step.
|
|
251
|
+
|
|
252
|
+
Leave the pass as ordinary uncommitted work for review and a later normal
|
|
253
|
+
commit. Never amend or rewrite selected commits. Summarize the resolved scope,
|
|
254
|
+
the main tasks with who does them, each task's steps and decisions before and
|
|
255
|
+
after, what changed and why, the tests, screenshots and transcripts actually
|
|
256
|
+
taken and run (with their paths), files changed, and findings left unchanged
|
|
257
|
+
with what they need and who must decide.
|
|
258
|
+
|
|
259
|
+
When the prompt ends with a `PASS RECORD` step, take it once the pass has
|
|
260
|
+
finished: the Genesis `passes done ux-pass` operation records it in `genesis/passes.json`,
|
|
261
|
+
an uncommitted change that lands in the pass's own commit. Genesis adds that
|
|
262
|
+
step only to the pass's own runs, whose requests it writes itself, so a user experience pass
|
|
263
|
+
of a section, commits or your own changes is never recorded as the pass;
|
|
264
|
+
neither is a pass that stopped early, was abandoned or still has failing
|
|
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|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') {
|
|
@@ -311,14 +314,21 @@ function writeResult(command, result) {
|
|
|
311
314
|
return;
|
|
312
315
|
}
|
|
313
316
|
if (command === 'inspect' && result.inspection === 'passes') {
|
|
317
|
+
if (result.unavailable) line(process.stdout, result.unavailable);
|
|
314
318
|
for (const pass of result.passes) {
|
|
315
319
|
line(process.stdout, `${pass.id}: ${pass.title} — ${pass.description}`);
|
|
316
320
|
line(process.stdout, ` recommended ${pass.recommend.hint}; Stack guidance: ${pass.stackGuidance ? 'yes' : 'no'}; last run: ${pass.lastRun ?? 'never'}`);
|
|
321
|
+
if (pass.unavailable && !result.unavailable) line(process.stdout, ` unavailable: ${pass.unavailable}`);
|
|
317
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'}`);
|
|
318
327
|
return;
|
|
319
328
|
}
|
|
320
329
|
if (command === 'passes') {
|
|
321
|
-
|
|
330
|
+
const ran = result.passes ? ` with ${result.passes.join(', ')}` : '';
|
|
331
|
+
line(process.stdout, `${result.pass}: recorded ${result.lastRun}${ran} in ${result.path}`);
|
|
322
332
|
return;
|
|
323
333
|
}
|
|
324
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,18 +35,14 @@ const SKILL_FIELDS = new Set([
|
|
|
35
35
|
'allowed-tools',
|
|
36
36
|
]);
|
|
37
37
|
|
|
38
|
-
//
|
|
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).
|
|
39
40
|
export const CORE_SKILL_NAMES = Object.freeze([
|
|
40
41
|
'genesis-project',
|
|
41
42
|
'genesis-program',
|
|
42
43
|
...PASSES.map(({ task }) => `genesis-${task}`),
|
|
44
|
+
`genesis-${MASTER_PASS.task}`,
|
|
43
45
|
]);
|
|
44
|
-
const CORE_SKILLS = CORE_SKILL_NAMES.map((name) => ({
|
|
45
|
-
component: null,
|
|
46
|
-
package: null,
|
|
47
|
-
path: `skills/${name}`,
|
|
48
|
-
source: `genesis:skills/${name}`,
|
|
49
|
-
}));
|
|
50
46
|
|
|
51
47
|
function invalidSkill(message, details = {}) {
|
|
52
48
|
throw new GenesisError('AGENT_SKILL_INVALID', message, details);
|
|
@@ -314,30 +310,58 @@ async function resolveLocator(locator) {
|
|
|
314
310
|
return { ...skill, component: locator.component };
|
|
315
311
|
}
|
|
316
312
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
if (projectRoot)
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
329
|
-
if (!['ENOENT', 'ENOTDIR'].includes(error?.code)) throw error;
|
|
330
|
-
}
|
|
331
|
-
if (manifest?.name === 'genesis-compiler') {
|
|
332
|
-
coreRoot = projectRoot;
|
|
333
|
-
} else if (['dependencies', 'devDependencies', 'optionalDependencies'].some((field) => (
|
|
334
|
-
Object.hasOwn(manifest?.[field] || {}, 'genesis-compiler')
|
|
335
|
-
))) {
|
|
336
|
-
coreRoot = await packageDirectory('genesis-compiler', projectRoot, { projectOnly: true });
|
|
313
|
+
// The Genesis a project's core skills come from: Genesis's own source repository, the installed genesis-compiler the
|
|
314
|
+
// project declares (even when a different compiler embeds this API), or else this compiler.
|
|
315
|
+
async function projectGenesisRoot(projectRoot) {
|
|
316
|
+
if (!projectRoot) return packageRoot;
|
|
317
|
+
let manifest;
|
|
318
|
+
try { manifest = JSON.parse(await readFile(path.join(projectRoot, 'package.json'), 'utf8')); } catch (error) {
|
|
319
|
+
// The manifest says whether the project declares its own genesis-compiler skills.
|
|
320
|
+
if (error instanceof SyntaxError) {
|
|
321
|
+
throw new GenesisError('AGENT_SKILL_SOURCE_INVALID',
|
|
322
|
+
`package.json is not valid JSON, so the project's genesis-compiler skills cannot be located: ${error.message}.`,
|
|
323
|
+
{ path: 'package.json' });
|
|
337
324
|
}
|
|
325
|
+
if (!['ENOENT', 'ENOTDIR'].includes(error?.code)) throw error;
|
|
326
|
+
}
|
|
327
|
+
if (manifest?.name === 'genesis-compiler') return projectRoot;
|
|
328
|
+
const declared = ['dependencies', 'devDependencies', 'optionalDependencies'].some((field) => (
|
|
329
|
+
Object.hasOwn(manifest?.[field] || {}, 'genesis-compiler')
|
|
330
|
+
));
|
|
331
|
+
return declared ? packageDirectory('genesis-compiler', projectRoot, { projectOnly: true }) : packageRoot;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* The project's own Genesis: its root and the names of its core skills, which are the directories of its skills
|
|
336
|
+
* folder. That Genesis is the one authority for what the project has, so a project pinned to an older
|
|
337
|
+
* genesis-compiler is planned the skills its release has: a skill this compiler added since is not selected for it,
|
|
338
|
+
* and none is taken from this compiler. Without projectRoot, this compiler's own.
|
|
339
|
+
*/
|
|
340
|
+
export async function projectGenesis({ projectRoot } = {}) {
|
|
341
|
+
const root = await projectGenesisRoot(projectRoot);
|
|
342
|
+
const skills = path.join(root, 'skills');
|
|
343
|
+
let entries;
|
|
344
|
+
try { entries = await readdir(skills, { withFileTypes: true }); } catch (error) {
|
|
345
|
+
if (!['ENOENT', 'ENOTDIR'].includes(error?.code)) throw error;
|
|
346
|
+
throw new GenesisError('AGENT_SKILL_UNAVAILABLE', `Genesis Agent Skills are unavailable: ${skills}.`, { path: skills });
|
|
338
347
|
}
|
|
348
|
+
return {
|
|
349
|
+
root,
|
|
350
|
+
coreSkills: entries.filter((entry) => entry.isDirectory()).map(({ name }) => name).sort(),
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/** Resolves the project's own Genesis workflow skills plus authoritative selected Stack skills. */
|
|
355
|
+
export async function projectSkillPlan(stack, { projectRoot } = {}) {
|
|
356
|
+
const genesis = await projectGenesis({ projectRoot });
|
|
339
357
|
const locators = [
|
|
340
|
-
...
|
|
358
|
+
...genesis.coreSkills.map((name) => ({
|
|
359
|
+
component: null,
|
|
360
|
+
package: null,
|
|
361
|
+
path: `skills/${name}`,
|
|
362
|
+
root: genesis.root,
|
|
363
|
+
source: `genesis:skills/${name}`,
|
|
364
|
+
})),
|
|
341
365
|
...(stack?.components || []).flatMap((component) => (
|
|
342
366
|
component.skill ? [{ ...component.skill, component: component.id }] : []
|
|
343
367
|
)),
|
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
|
@@ -3,6 +3,8 @@ export const GENESIS_CONTRACTS = Object.freeze({
|
|
|
3
3
|
projectInspection: 'genesis.project-inspection.v1',
|
|
4
4
|
promptTasks: 'genesis.prompt-tasks.v1',
|
|
5
5
|
passes: 'genesis.passes.v1',
|
|
6
|
+
passRuns: 'genesis.pass-runs.v1',
|
|
7
|
+
deepRuns: 'genesis.deep-runs.v1',
|
|
6
8
|
templates: 'genesis.templates.v1',
|
|
7
9
|
templateApplication: 'genesis.template-application.v1',
|
|
8
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
|
+
}
|