genesis-compiler 1.2.13 → 1.2.15

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 CHANGED
@@ -14,7 +14,7 @@ interaction.
14
14
  genesis/
15
15
  blueprint.md non-technical product intent
16
16
  stack.md selected technology guidance, verification, declarations, and opaque extensions
17
- stack/ optional per-component Description, Guidance, Adoption, and Deslop customization
17
+ stack/ optional per-component Description, Guidance, Adoption, Post-change, and Deslop customization
18
18
  program/ concise explanations grouped into conceptual subsystems
19
19
  .agents/skills/
20
20
  genesis-* Genesis workflow skills
@@ -213,18 +213,25 @@ adds its adapter through its Stack piece rather than teaching Genesis prompts
213
213
  to parse that language.
214
214
 
215
215
  At the end of a turn that changed Git-visible project files, the Stop hook asks
216
- Codex for two separate, bounded follow-up turns. The first reconciles the
217
- Blueprint and affected Program explanations from the changed paths and actual
218
- Git diff, then Genesis deterministically refreshes both City projections. The
219
- second performs the focused, behavior-preserving Deslop pass, after which both
220
- Cities are refreshed again to reflect any cleanup. A project with no selected
216
+ Codex for bounded follow-up turns. When the selected Stack contributes
217
+ `Post-change` work, all contributions compose deterministically into one
218
+ optional code-changing turn. Genesis then reconciles the Blueprint and affected
219
+ Program explanations from the complete changed-path set and actual Git diff,
220
+ and refreshes both City projections. A focused, behavior-preserving Deslop pass
221
+ runs before both Cities are refreshed again. Genesis then requests one concise
222
+ user-facing summary using conversation context only; that final phase is not
223
+ Stack-configurable and cannot schedule more cleanup. A project with no selected
221
224
  Stack uses only the `genesis-deslop` skill. Selected Stack components enrich
222
- reconciliation and cleanup with their general Guidance, and enrich cleanup
223
- further with technology-specific Deslop guidance.
225
+ Post-change work, reconciliation, and cleanup with general Guidance, and enrich
226
+ cleanup further with technology-specific Deslop guidance.
224
227
 
225
228
  The hook never starts another Codex process. Its small per-session phase is
226
- limited to `implementation -> reconcile -> deslop -> done`, so it cannot keep
227
- continuing recursively. Question-only and unchanged turns finish normally.
229
+ limited to `implementation -> optional post-change -> reconcile -> deslop ->
230
+ summary -> done`, so it cannot keep continuing recursively. The summary prompt
231
+ forbids repository inspection, tools, commands, tests, and edits, and the next
232
+ Stop always clears the sequence rather than scheduling more work. Empty
233
+ Post-change content is skipped rather than producing an empty turn.
234
+ Question-only and unchanged turns finish normally.
228
235
 
229
236
  Projects can customize a selected technology through its matching file, such
230
237
  as `genesis/stack/jskit.md`:
@@ -242,6 +249,10 @@ Additional project-specific context about how JSKIT is used here.
242
249
 
243
250
  - Additional project-specific implementation and review guidance.
244
251
 
252
+ ### Post-change
253
+
254
+ - Additional project-specific work to perform once after implementation.
255
+
245
256
  ### Deslop
246
257
 
247
258
  - Additional project-specific cleanup guidance.
@@ -256,6 +267,10 @@ A replacement for the installed JSKIT description.
256
267
 
257
268
  - Replacement installed implementation and review guidance.
258
269
 
270
+ ### Post-change
271
+
272
+ - Replacement installed post-change work.
273
+
259
274
  ### Deslop
260
275
 
261
276
  - Replacement installed cleanup guidance.
@@ -263,10 +278,10 @@ A replacement for the installed JSKIT description.
263
278
 
264
279
  Every field is optional. For each field, Genesis uses the installed value,
265
280
  replaces it when `Override` supplies that field, then appends the corresponding
266
- `Add` content. Customization affects only `Description`, `Guidance`, and
267
- `Deslop`; component dependencies, Agent Skill source, resources, and
268
- verification commands retain their installed contracts. `genesis stack add`
269
- preserves these matching customization files.
281
+ `Add` content. Customization affects only `Description`, `Guidance`,
282
+ `Adoption`, `Post-change`, and `Deslop`; component dependencies, Agent Skill
283
+ source, resources, and verification commands retain their installed contracts.
284
+ `genesis stack add` preserves these matching customization files.
270
285
 
271
286
  Prompt generation remains available for other agents and explicit tasks:
272
287
 
@@ -350,6 +365,7 @@ Components may contribute:
350
365
 
351
366
  - a concise description and supplemental Guidance used across relevant tasks;
352
367
  - existing-project Adoption requirements used only while importing a codebase;
368
+ - optional Post-change work composed once after a code-changing implementation;
353
369
  - one authoritative Agent Skill directory when the component owns one;
354
370
  - generic external-resource requirements;
355
371
  - cleanup advice used by explicit and automatic Deslop prompts;
@@ -358,7 +374,8 @@ Components may contribute:
358
374
 
359
375
  Technology-specific supplemental rules intentionally remain in Stack pieces.
360
376
  General `Guidance` enriches implementation, review, Program, description, and
361
- cleanup tasks; `Adoption` adds import-only requirements; `Deslop` adds
377
+ cleanup tasks; `Adoption` adds import-only requirements; `Post-change` composes
378
+ one optional code-changing continuation before explanation; `Deslop` adds
362
379
  cleanup-only rules. None shadows an official generic technology skill or
363
380
  assumes that an upstream skill contains every rule Genesis needs.
364
381
 
@@ -383,10 +400,10 @@ command without a shell. A complete successful run writes only
383
400
  - the commands that passed.
384
401
 
385
402
  The evidence becomes stale when code, selected components, declared resources,
386
- or verification commands change. Description, Guidance, Adoption, Agent Skill, and Deslop
387
- prose do not rewrite what an already-run command proved. A failed verification
388
- removes prior passing evidence before running. Verification does not claim
389
- whole-product correctness.
403
+ or verification commands change. Description, Guidance, Adoption, Post-change,
404
+ Agent Skill, and Deslop prose do not rewrite what an already-run command proved.
405
+ A failed verification removes prior passing evidence before running.
406
+ Verification does not claim whole-product correctness.
390
407
 
391
408
  A project can replace component defaults in `genesis/stack.md`:
392
409
 
@@ -17,7 +17,7 @@ Genesis reports only facts it can establish mechanically:
17
17
  City projects the Program modules and source citations that exist. Neither
18
18
  proves semantic equivalence, complete dynamic dispatch, or true duplication.
19
19
 
20
- Prompt text, Stack Description/Guidance/Adoption/Deslop prose, Program prose, Agent Skill
20
+ Prompt text, Stack Description/Guidance/Adoption/Post-change/Deslop prose, Program prose, Agent Skill
21
21
  content, and agent output are not assurance evidence. Genesis does not claim
22
22
  that product intent and code have converged, that Program is complete or
23
23
  semantically current, or that passing checks prove the whole product correct.
@@ -74,14 +74,19 @@ hosts can call `adoptProject()` and send its `prompt` directly.
74
74
 
75
75
  Codex can instead use the project-local hooks installed by `genesis init`.
76
76
  Those hooks inject a short operating guide, record whether the current turn
77
- changed project files, then request two bounded continuations: first reconcile
78
- Blueprint and affected Program explanations from the Git-visible changes, then
79
- Deslop the implementation. They invoke the same Genesis project operations and
80
- never start another agent process. A per-session phase permits only
81
- `implementation -> reconcile -> deslop -> done`. Genesis refreshes both City
82
- projections after reconciliation so Deslop sees the current explanation and
83
- function inventory, then refreshes them again after Deslop in case cleanup
84
- changed the implementation map.
77
+ changed project files, then request bounded continuations. Selected
78
+ `Post-change` contributions compose into one optional code-changing turn;
79
+ Genesis then reconciles Blueprint and affected Program explanations from the
80
+ complete Git-visible change set and Deslops the implementation. One final
81
+ summary prompt then asks for a concise user-facing account from conversation
82
+ context only, forbids tools and edits, and cannot schedule more cleanup. The
83
+ hooks invoke the same Genesis project operations and never start another agent
84
+ process. A per-session phase permits only `implementation -> optional
85
+ post-change -> reconcile -> deslop -> summary -> done`. Empty Post-change
86
+ content skips that phase. Genesis refreshes both City projections after
87
+ reconciliation so Deslop sees the current explanation and function inventory,
88
+ then refreshes them again after Deslop in case cleanup changed the
89
+ implementation map.
85
90
 
86
91
  Once Codex identifies relevant source, `genesis context <path...>` returns only
87
92
  Program modules citing those paths plus concise selected Stack context, the
@@ -99,8 +104,9 @@ This follows Agent Skills progressive disclosure and keeps official or
99
104
  user-installed generic technology skills independent.
100
105
 
101
106
  Matching files under `genesis/stack/<component>.md` may add to or override that
102
- selected component's Description, Guidance, Adoption, and Deslop fields. Effective
103
- Guidance is used by work, review, Program, describe, Deslop, and path-context
104
- generation. The Codex continuation flow also carries it into reconciliation and
105
- cleanup; effective Deslop guidance remains cleanup-only. Effective Adoption
107
+ selected component's Description, Guidance, Adoption, Post-change, and Deslop
108
+ fields. Effective Guidance is used by work, review, Program, describe, Deslop,
109
+ and path-context generation. The Codex continuation flow also carries it into
110
+ Post-change work, reconciliation, and cleanup; effective Post-change work runs
111
+ once before reconciliation, while Deslop guidance remains cleanup-only. Effective Adoption
106
112
  guidance is included only in the adoption workflow.
@@ -68,6 +68,10 @@ Concise technology context.
68
68
 
69
69
  - Existing-project import guidance.
70
70
 
71
+ ## Post-change
72
+
73
+ - Optional work to perform once after a code-changing implementation turn.
74
+
71
75
  ## Deslop
72
76
 
73
77
  - Technology-specific cleanup guidance.
@@ -82,9 +86,10 @@ Concise technology context.
82
86
  ```
83
87
  ````
84
88
 
85
- `Description`, `Guidance`, `Adoption`, and `Deslop` are prose. `Requires` and
86
- `Conflicts` define component selection. `Skill` names one complete authoritative
87
- Agent Skill directory. `Indexers` selects installed structural adapters.
89
+ `Description`, `Guidance`, `Adoption`, `Post-change`, and `Deslop` are prose.
90
+ `Requires` and `Conflicts` define component selection. `Skill` names one
91
+ complete authoritative Agent Skill directory. `Indexers` selects installed
92
+ structural adapters.
88
93
  `Resources`, `Environment defaults`, `Environment files`, and `Verification`
89
94
  use the small Genesis grammars documented below. Every other `##` section is an
90
95
  opaque extension.
@@ -155,8 +160,8 @@ contract therefore stales prior Genesis verification evidence even though
155
160
  Genesis does not interpret the extension.
156
161
 
157
162
  Prose and Agent Skill contents are instructions rather than verification
158
- evidence. Changes to Description, Guidance, Adoption, Deslop, or the installed
159
- Skill do not rewrite what an already-run command proved.
163
+ evidence. Changes to Description, Guidance, Adoption, Post-change, Deslop, or
164
+ the installed Skill do not rewrite what an already-run command proved.
160
165
 
161
166
  `City regions` and `Indexers` control only the derived structural maps. Indexers
162
167
  identify language adapters. City regions can exclude test/spec paths and group
@@ -177,6 +182,10 @@ A selected component may have one prose-only customization at
177
182
 
178
183
  - Additional project guidance.
179
184
 
185
+ ### Post-change
186
+
187
+ - Additional project-specific post-change work.
188
+
180
189
  ## Override
181
190
 
182
191
  ### Deslop
@@ -184,9 +193,10 @@ A selected component may have one prose-only customization at
184
193
  - Replacement cleanup guidance.
185
194
  ```
186
195
 
187
- Customizations may add or override only Description, Guidance, Adoption, and
188
- Deslop. They cannot mutate selection, resources, environment declarations,
189
- Verification, Agent Skill ownership, indexers, or opaque consumer sections.
196
+ Customizations may add or override only Description, Guidance, Adoption,
197
+ Post-change, and Deslop. They cannot mutate selection, resources, environment
198
+ declarations, Verification, Agent Skill ownership, indexers, or opaque consumer
199
+ sections.
190
200
 
191
201
  ## Public inspection
192
202
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genesis-compiler",
3
- "version": "1.2.13",
3
+ "version": "1.2.15",
4
4
  "type": "module",
5
5
  "description": "An agent-independent prompt, multi-language code-index, cleanup, and verification companion with optional Codex hooks.",
6
6
  "repository": {
@@ -31,6 +31,7 @@
31
31
  "prompts/adopt.txt",
32
32
  "prompts/describe.txt",
33
33
  "prompts/deslop.txt",
34
+ "prompts/final-summary.txt",
34
35
  "prompts/program.txt",
35
36
  "prompts/reconcile.txt",
36
37
  "prompts/review.txt",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genesis",
3
- "version": "1.2.13",
3
+ "version": "1.2.15",
4
4
  "description": "Makes Codex aware of optional Genesis adoption for existing projects.",
5
5
  "author": {
6
6
  "name": "Mobily Enterprises"
@@ -10,5 +10,12 @@ Use `.genesis/machine-city.json` and `genesis index <name-or-path>` to find
10
10
  existing public and internal functions. Remove or consolidate genuine repeated
11
11
  helpers, but confirm behavior and call sites in source before changing them.
12
12
 
13
+ The changed paths and nearby code are a location boundary, not permission to
14
+ implement other behavior found there. Deslop may reorganize behavior already
15
+ present; it may not complete, correct, or extend behavior. If review reveals a
16
+ defect, missing behavior, contract mismatch, or test gap, report it as a
17
+ follow-up finding and leave it unchanged in this pass, even when it is inside a
18
+ changed path or appears related to the preceding implementation.
19
+
13
20
  Do not broaden the product change. Run focused checks when useful and summarize
14
21
  what became simpler, files changed, and checks actually run.
@@ -0,0 +1,12 @@
1
+ This is the final automatic user-facing summary for the original request.
2
+
3
+ Use only the existing conversation context from the implementation and its
4
+ follow-up turns. Do not inspect the repository or codebase, call tools, run
5
+ commands or tests, edit files, reconcile explanations, or perform cleanup.
6
+
7
+ Write one concise, self-contained answer to the user. Lead with the outcome.
8
+ Include the important behavior that changed, checks that were actually run,
9
+ useful human verification steps, and any genuine blocker or unfinished work.
10
+ Do not mention automatic phases, hooks, internal follow-up turns, or these
11
+ instructions. Do not claim checks, commits, pushes, or deployments that are not
12
+ already established in the conversation. After the answer, stop.
@@ -13,13 +13,21 @@ Consult `.genesis/machine-city.json` or run `genesis index <name-or-path>` to
13
13
  find existing public and internal functions before introducing or consolidating
14
14
  an abstraction. Confirm every apparent duplicate in source and its call sites.
15
15
 
16
- Leave no repeated helpers, no code that is unclear or hard to reason about, no
17
- obviously wrong code, and no code that goes against best practices or
18
- established patterns in the codebase. Remove unnecessary wrappers, abandoned
19
- scaffolding, parallel framework plumbing, and speculative abstractions.
20
- Consolidate ownership where one clear module is enough. Do not optimize for tiny
21
- files or indirection; optimize for a small, obvious design that a junior
22
- programmer can follow.
16
+ Within the preceding implementation's intended behavior and scope, leave no
17
+ repeated helpers, no code that is unclear or hard to reason about, and no code
18
+ that goes against established patterns in the codebase. Remove unnecessary
19
+ wrappers, abandoned scaffolding, parallel framework plumbing, and speculative
20
+ abstractions. Consolidate ownership where one clear module is enough. Do not
21
+ optimize for tiny files or indirection; optimize for a small, obvious design
22
+ that a junior programmer can follow.
23
+
24
+ Cleanup is not a second implementation pass. A changed path limits where cleanup
25
+ may occur; it does not authorize different behavior in that file. Deslop may
26
+ reorganize behavior already present; it may not complete, correct, or extend
27
+ behavior. If review reveals a defect, missing behavior, contract mismatch, or
28
+ test gap, report it as a follow-up finding and leave it unchanged, even when it
29
+ is inside a changed path or appears related to the preceding implementation. Do
30
+ not implement the finding or alter tests to accommodate it during Deslop.
23
31
 
24
32
  Apply every technology-specific Deslop instruction supplied by the selected
25
33
  Stack. Load applicable official technology skills for additional framework and
@@ -8,6 +8,7 @@ const assets = {
8
8
  describe: new URL('prompts/describe.txt', root),
9
9
  reconcile: new URL('prompts/reconcile.txt', root),
10
10
  deslop: new URL('prompts/deslop.txt', root),
11
+ finalSummary: new URL('prompts/final-summary.txt', root),
11
12
  program: new URL('prompts/program.txt', root),
12
13
  blueprint: new URL('prompts/blueprint.txt', root),
13
14
  review: new URL('prompts/review.txt', root),
@@ -134,8 +134,8 @@ export async function codexSessionContext({ projectRoot } = {}) {
134
134
  '- Before creating a helper or public operation, run `genesis index <name-or-path>` and reuse an existing function when it already owns the behavior.',
135
135
  '- `.genesis/machine-city.json` is the detailed code/function map; `.genesis/program-city.json` is the simpler subsystem/operation map.',
136
136
  '- Program is fallible explanation; code, tests, and runtime behavior remain evidence.',
137
- '- Keep implementation focused; the Stop hook owns later Blueprint/Program reconciliation and Deslop turns.',
138
- '- After a code-changing turn, Genesis may request separate explanation and behavior-preserving cleanup turns.',
137
+ '- Keep implementation focused; the Stop hook owns optional Stack Post-change work, Blueprint/Program reconciliation, and Deslop turns.',
138
+ '- After a code-changing turn, Genesis may request separate post-change, explanation, cleanup, and final-summary turns.',
139
139
  `Selected Stack components: ${stackStatus}.`,
140
140
  ].join('\n'),
141
141
  };
@@ -173,8 +173,12 @@ function hookId(input, field) {
173
173
  return value;
174
174
  }
175
175
 
176
+ function normalizedPaths(values = []) {
177
+ return [...new Set(values.map(normalizeRelative).filter(Boolean))];
178
+ }
179
+
176
180
  function zeroPaths(buffer) {
177
- return buffer.toString('utf8').split('\0').filter(Boolean).map(normalizeRelative);
181
+ return normalizedPaths(buffer.toString('utf8').split('\0'));
178
182
  }
179
183
 
180
184
  async function repositorySnapshot(projectRoot) {
@@ -292,6 +296,24 @@ async function reconciliationContinuation(projectRoot, changedPaths) {
292
296
  ].join('\n');
293
297
  }
294
298
 
299
+ function postChangeContinuation(changedPaths, stack) {
300
+ return [
301
+ 'This is the one automatic Stack Post-change turn for the preceding implementation.',
302
+ 'Use the same conversation context and the Git-visible changes below.',
303
+ 'Perform only the composed Post-change work. Do not broaden the task, reconcile Genesis explanations, or perform Deslop yet.',
304
+ 'Do not repeat or schedule another Post-change turn. If none of the configured work applies, make no changes and respond minimally.',
305
+ '',
306
+ 'CHANGED PROJECT PATHS',
307
+ '',
308
+ ...changedPathLines(changedPaths),
309
+ '',
310
+ 'COMPOSED STACK POST-CHANGE WORK',
311
+ '',
312
+ stack.postChange,
313
+ ...(stack.guidance ? ['', 'SELECTED STACK GUIDANCE', '', stack.guidance] : []),
314
+ ].join('\n');
315
+ }
316
+
295
317
  async function deslopContinuation(projectRoot, changedPaths) {
296
318
  const [instructions, stack] = await Promise.all([
297
319
  readInstalledAsset('deslop'),
@@ -318,6 +340,10 @@ async function deslopContinuation(projectRoot, changedPaths) {
318
340
  ].join('\n');
319
341
  }
320
342
 
343
+ async function finalSummaryContinuation() {
344
+ return (await readInstalledAsset('finalSummary')).trim();
345
+ }
346
+
321
347
  export async function completeCodexTurn({ input, projectRoot } = {}) {
322
348
  const root = (await gitContext(projectRoot || input?.cwd)).repositoryRoot;
323
349
  const statePath = await hookStatePath(root, input);
@@ -334,14 +360,18 @@ export async function completeCodexTurn({ input, projectRoot } = {}) {
334
360
  await rm(statePath, { force: true });
335
361
  return {};
336
362
  }
363
+ const stack = await optionalStack(root);
364
+ const postChange = Boolean(stack?.postChange?.trim());
337
365
  await writeTurnState(statePath, {
338
366
  ...state,
339
- phase: 'reconcile',
367
+ phase: postChange ? 'post-change' : 'reconcile',
340
368
  changedPaths,
341
369
  });
342
370
  return {
343
371
  decision: 'block',
344
- reason: await reconciliationContinuation(root, changedPaths),
372
+ reason: postChange
373
+ ? postChangeContinuation(changedPaths, stack)
374
+ : await reconciliationContinuation(root, changedPaths),
345
375
  };
346
376
  }
347
377
 
@@ -350,9 +380,32 @@ export async function completeCodexTurn({ input, projectRoot } = {}) {
350
380
  return {};
351
381
  }
352
382
 
383
+ if (state.phase === 'post-change') {
384
+ const currentPaths = await changedProjectPaths(root, state.snapshot, await repositorySnapshot(root));
385
+ const changedPaths = normalizedPaths([...state.changedPaths, ...currentPaths]).sort();
386
+ if (changedPaths.length === 0) {
387
+ await rm(statePath, { force: true });
388
+ return {};
389
+ }
390
+ await writeTurnState(statePath, {
391
+ ...state,
392
+ phase: 'reconcile',
393
+ changedPaths,
394
+ });
395
+ return {
396
+ decision: 'block',
397
+ reason: await reconciliationContinuation(root, changedPaths),
398
+ };
399
+ }
400
+
353
401
  if (state.phase === 'reconcile') {
354
402
  const currentPaths = await changedProjectPaths(root, state.snapshot, await repositorySnapshot(root));
355
- const changedPaths = [...new Set([...state.changedPaths, ...currentPaths])].sort();
403
+ const changedPaths = normalizedPaths([...state.changedPaths, ...currentPaths]).sort();
404
+ if (changedPaths.length === 0) {
405
+ await refreshProjectIndex(root);
406
+ await rm(statePath, { force: true });
407
+ return {};
408
+ }
356
409
  await refreshProjectIndex(root);
357
410
  await writeTurnState(statePath, {
358
411
  ...state,
@@ -365,7 +418,18 @@ export async function completeCodexTurn({ input, projectRoot } = {}) {
365
418
  };
366
419
  }
367
420
 
368
- await refreshProjectIndex(root);
421
+ if (state.phase === 'deslop') {
422
+ await refreshProjectIndex(root);
423
+ await writeTurnState(statePath, {
424
+ ...state,
425
+ phase: 'summary',
426
+ });
427
+ return {
428
+ decision: 'block',
429
+ reason: await finalSummaryContinuation(),
430
+ };
431
+ }
432
+
369
433
  await rm(statePath, { force: true });
370
434
  return {};
371
435
  }
@@ -4,6 +4,7 @@ import { buildProjectIndex, MACHINE_CITY_PATH, PROGRAM_CITY_PATH } from './code-
4
4
  import { BLUEPRINT_SKELETON_SOURCE, readBlueprint } from './blueprint.js';
5
5
  import { readStack, stackPromptContext } from './stack.js';
6
6
  import { listStackCatalogPieces } from './stack-catalog.js';
7
+ import { normalizeStackPieceId } from './stack-piece.js';
7
8
  import { GenesisError } from './errors.js';
8
9
  import { gitContext } from './git.js';
9
10
  import { inspectProgram } from './program.js';
@@ -25,13 +26,16 @@ const DEFAULT_REQUEST = {
25
26
  review: 'Review the complete useful relationship between Blueprint, code, Program, and tests.',
26
27
  };
27
28
 
28
- function stackCatalogContext(pieces = []) {
29
- return pieces.map(({ id, description, requires, conflicts }) => ({
30
- id,
31
- description,
32
- requires,
33
- conflicts,
34
- }));
29
+ function stackCatalogContext(pieces = [], hiddenStackPieces = []) {
30
+ const hidden = new Set(hiddenStackPieces.map(normalizeStackPieceId));
31
+ return pieces
32
+ .filter(({ id }) => !hidden.has(id))
33
+ .map(({ id, description, requires, conflicts }) => ({
34
+ id,
35
+ description,
36
+ requires,
37
+ conflicts,
38
+ }));
35
39
  }
36
40
 
37
41
  function requestText(value, task) {
@@ -205,7 +209,14 @@ async function generateExplanationPrompt({ instructions, program, request, root,
205
209
  };
206
210
  }
207
211
 
208
- async function generateStartPrompt({ instructions, program, request, root, stackPackages }) {
212
+ async function generateStartPrompt({
213
+ hiddenStackPieces,
214
+ instructions,
215
+ program,
216
+ request,
217
+ root,
218
+ stackPackages,
219
+ }) {
209
220
  let blueprint;
210
221
  try {
211
222
  blueprint = await readBlueprint(root, { required: true });
@@ -255,7 +266,7 @@ async function generateStartPrompt({ instructions, program, request, root, stack
255
266
  description: blueprint.description,
256
267
  },
257
268
  stack: stackPromptContext(stack),
258
- availableStackPieces: stackCatalogContext(catalog),
269
+ availableStackPieces: stackCatalogContext(catalog, hiddenStackPieces),
259
270
  program: programContext(program),
260
271
  codeIndex: codeIndexContext(index),
261
272
  },
@@ -273,6 +284,7 @@ async function generateStartPrompt({ instructions, program, request, root, stack
273
284
 
274
285
  export async function generateProjectPrompt({
275
286
  environment = process.env,
287
+ hiddenStackPieces = [],
276
288
  projectRoot,
277
289
  request = '',
278
290
  stackPackages = [],
@@ -314,6 +326,7 @@ export async function generateProjectPrompt({
314
326
  if (task === 'start') {
315
327
  return generateStartPrompt({
316
328
  instructions,
329
+ hiddenStackPieces,
317
330
  program,
318
331
  request: userRequest,
319
332
  root,
@@ -338,6 +351,7 @@ export async function generateProjectPrompt({
338
351
  if (error?.code !== 'STACK_REQUIRED') throw error;
339
352
  return generateStartPrompt({
340
353
  instructions: await readInstalledAsset('start'),
354
+ hiddenStackPieces,
341
355
  program,
342
356
  request: userRequest,
343
357
  root,
@@ -347,6 +361,7 @@ export async function generateProjectPrompt({
347
361
  if (stack.components.length === 0) {
348
362
  return generateStartPrompt({
349
363
  instructions: await readInstalledAsset('start'),
364
+ hiddenStackPieces,
350
365
  program,
351
366
  request: userRequest,
352
367
  root,
@@ -8,7 +8,13 @@ import { normalizeSource } from './utils.js';
8
8
 
9
9
  const STACK_PIECE_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;
10
10
  const STACK_CUSTOMIZATION_TITLE = /^# Stack customization: ([a-z0-9]+(?:-[a-z0-9]+)*)\s*$/u;
11
- const STACK_CUSTOMIZATION_FIELDS = new Set(['Description', 'Guidance', 'Adoption', 'Deslop']);
11
+ const STACK_CUSTOMIZATION_FIELDS = new Map([
12
+ ['Description', 'description'],
13
+ ['Guidance', 'guidance'],
14
+ ['Adoption', 'adoption'],
15
+ ['Post-change', 'postChange'],
16
+ ['Deslop', 'deslop'],
17
+ ]);
12
18
  const STACK_PIECE_SECTIONS = new Set([
13
19
  'Adoption',
14
20
  'City regions',
@@ -19,6 +25,7 @@ const STACK_PIECE_SECTIONS = new Set([
19
25
  'Environment files',
20
26
  'Guidance',
21
27
  'Indexers',
28
+ 'Post-change',
22
29
  'Requires',
23
30
  'Resources',
24
31
  'Skill',
@@ -73,7 +80,7 @@ function customizationSections(source, piecePath) {
73
80
  if (!field) return;
74
81
  const value = content.join('\n').trim();
75
82
  if (!value) invalid(piecePath, `Stack customization ${mode} ${field} must not be empty.`);
76
- result[mode.toLowerCase()][field.toLowerCase()] = value;
83
+ result[mode.toLowerCase()][STACK_CUSTOMIZATION_FIELDS.get(field)] = value;
77
84
  field = null;
78
85
  content = [];
79
86
  }
@@ -96,7 +103,7 @@ function customizationSections(source, piecePath) {
96
103
  if (!mode || !STACK_CUSTOMIZATION_FIELDS.has(fieldHeading[1])) {
97
104
  invalid(piecePath, `Unknown or misplaced customization field: ${fieldHeading[1]}.`);
98
105
  }
99
- const key = fieldHeading[1].toLowerCase();
106
+ const key = STACK_CUSTOMIZATION_FIELDS.get(fieldHeading[1]);
100
107
  if (Object.hasOwn(result[mode.toLowerCase()], key)) {
101
108
  invalid(piecePath, `Duplicate ${mode} ${fieldHeading[1]} customization.`);
102
109
  }
@@ -106,12 +113,12 @@ function customizationSections(source, piecePath) {
106
113
  if (/^#{1,3}\s+/u.test(line)) invalid(piecePath, `Unknown customization heading: ${line.trim()}.`);
107
114
  if (field) content.push(line);
108
115
  else if (line.trim()) {
109
- invalid(piecePath, 'Customization content must be below Description, Guidance, Adoption, or Deslop.');
116
+ invalid(piecePath, 'Customization content must be below Description, Guidance, Adoption, Post-change, or Deslop.');
110
117
  }
111
118
  }
112
119
  finishField();
113
120
  if (Object.values(result).every((values) => Object.keys(values).length === 0)) {
114
- invalid(piecePath, 'Stack customization must add or override Description, Guidance, Adoption, or Deslop.');
121
+ invalid(piecePath, 'Stack customization must add or override Description, Guidance, Adoption, Post-change, or Deslop.');
115
122
  }
116
123
  return result;
117
124
  }
@@ -243,6 +250,7 @@ export function parseStackPieceSource(value, {
243
250
  const description = textSection(all, 'Description');
244
251
  const guidance = textSection(all, 'Guidance');
245
252
  const adoption = textSection(all, 'Adoption');
253
+ const postChange = textSection(all, 'Post-change');
246
254
  const deslop = textSection(all, 'Deslop');
247
255
  if (!description) invalid(piecePath, 'Stack piece needs Description.');
248
256
  const verificationCommands = parseStackVerificationLines(
@@ -266,6 +274,7 @@ export function parseStackPieceSource(value, {
266
274
  description,
267
275
  guidance,
268
276
  adoption,
277
+ postChange,
269
278
  requires: idList(all, 'Requires', piecePath, { required: true }),
270
279
  conflicts: idList(all, 'Conflicts', piecePath),
271
280
  indexers: idList(all, 'Indexers', piecePath),
@@ -320,6 +329,11 @@ export function applyStackPieceCustomization(piece, customization) {
320
329
  customization.override.adoption,
321
330
  customization.add.adoption,
322
331
  ),
332
+ postChange: customizedText(
333
+ piece.postChange,
334
+ customization.override.postChange,
335
+ customization.add.postChange,
336
+ ),
323
337
  deslop: customizedText(piece.deslop, customization.override.deslop, customization.add.deslop),
324
338
  };
325
339
  }
@@ -362,6 +362,7 @@ export async function readStack(projectRoot, { stackPackages = [] } = {}) {
362
362
  resources,
363
363
  guidance: composedProse(components, 'guidance'),
364
364
  adoption: composedProse(components, 'adoption'),
365
+ postChange: composedProse(components, 'postChange'),
365
366
  deslop: composedProse(components, 'deslop'),
366
367
  };
367
368
  }