claude-code-session-manager 0.75.3 → 0.77.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/dist/assets/{AgentLibrary-CzQqcObq.js → AgentLibrary-B2ie8bbw.js} +2 -2
  2. package/dist/assets/{DataModel-Bj_WlLz8.js → DataModel-BIJPYw32.js} +1 -1
  3. package/dist/assets/{History-DnSi_OHm.js → History-CeY6dk9S.js} +2 -2
  4. package/dist/assets/{Hooks-0BB0dp3S.js → Hooks-BFH2ocKg.js} +2 -2
  5. package/dist/assets/{HostBilko-DHpwwsLQ.js → HostBilko-36gj9wLz.js} +1 -1
  6. package/dist/assets/{Library-CaJVqVvi.js → Library-C-hBct39.js} +1 -1
  7. package/dist/assets/{ListDetail-C1W2HmC2.js → ListDetail-CNq64VWV.js} +1 -1
  8. package/dist/assets/{MarkdownEditor-5Ob9FW3z.js → MarkdownEditor-Bh3qt5-1.js} +1 -1
  9. package/dist/assets/{McpServers-JxCSfm1S.js → McpServers-DpGN0oyz.js} +1 -1
  10. package/dist/assets/{Memory-BDeqlqwH.js → Memory-D59hUjC4.js} +6 -6
  11. package/dist/assets/{Panel-Dh9ZHuEj.js → Panel-DCgbaoci.js} +1 -1
  12. package/dist/assets/{Permissions-DXy-CbEY.js → Permissions-DAmQ0DYV.js} +2 -2
  13. package/dist/assets/{Plugins-_n1Iuc8T.js → Plugins-Dyfgn6Is.js} +2 -2
  14. package/dist/assets/{ProvenanceBadge-BP_evfxE.js → ProvenanceBadge-BiYhPO1U.js} +1 -1
  15. package/dist/assets/SaveBar-RV7B6sOh.js +1 -0
  16. package/dist/assets/Scheduler-BPaNqx1b.js +14 -0
  17. package/dist/assets/{ScopeSwitcher-CAWzM6RI.js → ScopeSwitcher-P4mdLGNU.js} +1 -1
  18. package/dist/assets/{Settings-DRRozLyT.js → Settings-BL4vf5aX.js} +1 -1
  19. package/dist/assets/{SkillReferenceGraph-DGHDWlz4.js → SkillReferenceGraph-BRBDyi1_.js} +1 -1
  20. package/dist/assets/{Skills-D8L66eiX.js → Skills-BV08gDUH.js} +2 -2
  21. package/dist/assets/{SystemPrompt-CYtUsonD.js → SystemPrompt-CLftSsDw.js} +1 -1
  22. package/dist/assets/TagLibrary-Bp8jGsd5.js +1 -0
  23. package/dist/assets/{TiptapBody-B2hRgbPE.js → TiptapBody-jCpuB6E5.js} +1 -1
  24. package/dist/assets/{Toggle-BTwsbxam.js → Toggle-D2paA1xf.js} +1 -1
  25. package/dist/assets/{index-DijufvkJ.js → index-BDRSqBl3.js} +704 -704
  26. package/dist/assets/{index-CMLnzdZC.css → index-CYhdtisq.css} +1 -1
  27. package/dist/assets/{settingsSchema-D6wzxAi6.js → settingsSchema-6IOLjZZN.js} +1 -1
  28. package/dist/index.html +2 -2
  29. package/package.json +8 -2
  30. package/plugins/session-manager-dev/skills/develop/standards.md +1 -1
  31. package/scripts/lib/activeSessions.cjs +116 -6
  32. package/scripts/project-pages-logic/dist/logic.cjs +4709 -0
  33. package/scripts/render-project-pages/dist/renderer.cjs +18900 -0
  34. package/scripts/render-project-pages.cjs +70 -0
  35. package/scripts/scheduler-mcp-server.cjs +269 -96
  36. package/scripts/validate-project-pages-summary.cjs +62 -0
  37. package/src/main/__tests__/agentModelResolve.test.cjs +66 -0
  38. package/src/main/__tests__/epicStatusMirror.test.cjs +110 -0
  39. package/src/main/__tests__/health-delegation-chain.test.cjs +106 -0
  40. package/src/main/__tests__/prdAdminRoutes.test.cjs +295 -0
  41. package/src/main/__tests__/prdAgentType.test.cjs +103 -0
  42. package/src/main/__tests__/prdCreate.test.cjs +247 -0
  43. package/src/main/__tests__/prdFrontmatterAgentType.test.cjs +117 -0
  44. package/src/main/__tests__/prdFrontmatterQuietMachine.test.cjs +108 -0
  45. package/src/main/__tests__/projectHomeAdminRoutes.test.cjs +485 -0
  46. package/src/main/__tests__/projectPages.test.cjs +73 -1
  47. package/src/main/__tests__/rcaReport.test.cjs +54 -0
  48. package/src/main/__tests__/runVerify.test.cjs +94 -0
  49. package/src/main/__tests__/scheduler-autofix-select.test.cjs +58 -3
  50. package/src/main/__tests__/scheduler-bash-timeout-env.test.cjs +103 -0
  51. package/src/main/__tests__/scheduler-commit-guard-noop.test.cjs +41 -0
  52. package/src/main/__tests__/scheduler-effective-concurrency.test.cjs +10 -0
  53. package/src/main/__tests__/scheduler-foreign-wip-manifest.test.cjs +78 -0
  54. package/src/main/__tests__/scheduler-inplace-salvage.test.cjs +242 -0
  55. package/src/main/__tests__/scheduler-investigation-prompt.test.cjs +31 -0
  56. package/src/main/__tests__/scheduler-launch-failure.test.cjs +201 -0
  57. package/src/main/__tests__/scheduler-leftover-fields.test.cjs +52 -0
  58. package/src/main/__tests__/scheduler-looks-done.test.cjs +241 -0
  59. package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +135 -0
  60. package/src/main/__tests__/scheduler-quiet-machine-lease.test.cjs +222 -0
  61. package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +207 -1
  62. package/src/main/__tests__/scheduler-shared-tree-guard.test.cjs +212 -0
  63. package/src/main/__tests__/scheduler-stranded-investigation.test.cjs +185 -0
  64. package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +194 -0
  65. package/src/main/__tests__/seedAgentPersonas.test.cjs +75 -14
  66. package/src/main/__tests__/seedSchedulerMcp.test.cjs +66 -0
  67. package/src/main/__tests__/uniquePrdNumbers.test.cjs +14 -5
  68. package/src/main/bilkoHost.cjs +4 -3
  69. package/src/main/chatRunner.cjs +6 -1
  70. package/src/main/config.cjs +25 -33
  71. package/src/main/health.cjs +153 -2
  72. package/src/main/index.cjs +64 -5
  73. package/src/main/ipcSchemas.cjs +69 -1
  74. package/src/main/lib/__tests__/activeIndexRebuild.test.cjs +179 -0
  75. package/src/main/lib/__tests__/childWithLog.test.cjs +141 -0
  76. package/src/main/lib/__tests__/delegationReadiness.test.cjs +391 -42
  77. package/src/main/lib/__tests__/ephemeralCwd.test.cjs +91 -0
  78. package/src/main/lib/__tests__/epicWorktreeMint.test.cjs +5 -3
  79. package/src/main/lib/__tests__/fixChainDepth.test.cjs +40 -0
  80. package/src/main/lib/__tests__/gitWorktree.test.cjs +290 -5
  81. package/src/main/lib/__tests__/gitWorktreeSalvage.test.cjs +107 -0
  82. package/src/main/lib/__tests__/gitWorktreeSalvageDelta.test.cjs +153 -0
  83. package/src/main/lib/__tests__/jobWorktree.test.cjs +6 -4
  84. package/src/main/lib/__tests__/landedSinceRun.test.cjs +73 -0
  85. package/src/main/lib/__tests__/launchFailure.test.cjs +220 -0
  86. package/src/main/lib/__tests__/loadGate.test.cjs +159 -0
  87. package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +102 -0
  88. package/src/main/lib/__tests__/opsOwnership.test.cjs +7 -0
  89. package/src/main/lib/__tests__/opsRootAbsoluteCwd.test.cjs +151 -0
  90. package/src/main/lib/__tests__/opsRootResolve.test.cjs +149 -0
  91. package/src/main/lib/__tests__/prdDeclaredPaths.test.cjs +82 -0
  92. package/src/main/lib/__tests__/projectRootResolve.test.cjs +148 -0
  93. package/src/main/lib/__tests__/queueHealth.test.cjs +58 -0
  94. package/src/main/lib/__tests__/quietMachineLease.test.cjs +39 -0
  95. package/src/main/lib/__tests__/reaperHelpers.test.cjs +133 -0
  96. package/src/main/lib/__tests__/schedulerBatchDepends.test.cjs +19 -9
  97. package/src/main/lib/__tests__/schedulerBatchFairness.test.cjs +213 -0
  98. package/src/main/lib/__tests__/schedulerBatchLaunchHold.test.cjs +125 -0
  99. package/src/main/lib/__tests__/schedulerBatchProjectCap.test.cjs +127 -0
  100. package/src/main/lib/__tests__/schedulerBatchQuietMachine.test.cjs +109 -0
  101. package/src/main/lib/__tests__/schedulerMcpServerHeadlessRefusal.test.cjs +71 -0
  102. package/src/main/lib/__tests__/schedulerMcpServerHelp.test.cjs +217 -0
  103. package/src/main/lib/__tests__/schedulerMcpServerProjectHome.test.cjs +350 -0
  104. package/src/main/lib/activeIndexMerge.cjs +15 -0
  105. package/src/main/lib/activeIndexRebuild.cjs +133 -0
  106. package/src/main/lib/agentModelResolve.cjs +58 -0
  107. package/src/main/lib/buildTarget.cjs +3 -2
  108. package/src/main/lib/childWithLog.cjs +69 -2
  109. package/src/main/lib/claudeBin.cjs +54 -1
  110. package/src/main/lib/crossProjectFeedback.cjs +8 -1
  111. package/src/main/lib/definitionOfDone.cjs +3 -2
  112. package/src/main/lib/delegationReadiness.cjs +514 -26
  113. package/src/main/lib/ephemeralCwd.cjs +78 -0
  114. package/src/main/lib/epicDelegationStats.cjs +2 -1
  115. package/src/main/lib/epicMint.cjs +17 -1
  116. package/src/main/lib/epicStatusMirror.cjs +95 -0
  117. package/src/main/lib/epicValidationHook.cjs +2 -1
  118. package/src/main/lib/epicWorktreeMint.cjs +5 -2
  119. package/src/main/lib/fixChainDepth.cjs +45 -0
  120. package/src/main/lib/gitWorktree.cjs +520 -21
  121. package/src/main/lib/jobWorktree.cjs +2 -0
  122. package/src/main/lib/landedSinceRun.cjs +55 -0
  123. package/src/main/lib/launchFailure.cjs +357 -0
  124. package/src/main/lib/loadGate.cjs +134 -0
  125. package/src/main/lib/mcpToolCatalog.cjs +370 -0
  126. package/src/main/lib/opsErrorLog.cjs +12 -1
  127. package/src/main/lib/opsOwnership.cjs +106 -0
  128. package/src/main/lib/prdAdminRoutes.cjs +43 -3
  129. package/src/main/lib/prdAgentType.cjs +84 -0
  130. package/src/main/lib/prdCreate.cjs +103 -15
  131. package/src/main/lib/prdDeclaredPaths.cjs +70 -0
  132. package/src/main/lib/prdFrontmatter.cjs +17 -3
  133. package/src/main/lib/prdLocations.cjs +13 -6
  134. package/src/main/lib/projectHomeAdminRoutes.cjs +402 -0
  135. package/src/main/lib/projectPageSummarySchema.cjs +181 -0
  136. package/src/main/lib/projectRootResolve.cjs +134 -0
  137. package/src/main/lib/promptSessionSchema.cjs +7 -0
  138. package/src/main/lib/queueHealth.cjs +38 -0
  139. package/src/main/lib/queueStore.cjs +40 -7
  140. package/src/main/lib/quietMachineLease.cjs +48 -0
  141. package/src/main/lib/rcaReport.cjs +54 -4
  142. package/src/main/lib/reaperHelpers.cjs +64 -1
  143. package/src/main/lib/scheduleJobSchema.cjs +31 -0
  144. package/src/main/lib/scheduleJobTransitions.cjs +6 -2
  145. package/src/main/lib/schedulerBatch.cjs +301 -55
  146. package/src/main/lib/schedulerConfig.cjs +99 -0
  147. package/src/main/projectBrief.cjs +3 -2
  148. package/src/main/projectPages.cjs +162 -3
  149. package/src/main/promptSessionTranscript.cjs +0 -0
  150. package/src/main/pty.cjs +5 -0
  151. package/src/main/queueOps.cjs +15 -8
  152. package/src/main/runVerify.cjs +50 -9
  153. package/src/main/scheduler/prdParser.cjs +18 -1
  154. package/src/main/scheduler.cjs +1701 -130
  155. package/src/main/seedAgentPersonas.cjs +62 -21
  156. package/src/main/seedSchedulerMcp.cjs +58 -4
  157. package/src/main/templates/project-pages-catalog.json +741 -0
  158. package/src/main/templates/project-pages-pipeline.md +417 -0
  159. package/src/preload/api.d.ts +187 -3
  160. package/src/preload/index.cjs +9 -0
  161. package/src/seed/agents/project-home-builder.md +59 -0
  162. package/dist/assets/SaveBar-D-gCUx4n.js +0 -1
  163. package/dist/assets/Scheduler-Bpd4OGju.js +0 -14
  164. package/dist/assets/TagLibrary-E5CLeuVk.js +0 -1
@@ -0,0 +1,417 @@
1
+ # Project Pages pipeline — architecture spec
2
+
3
+ Canonical design for the "Project Page" feature: Project Home generates 5
4
+ static HTML pages per project (**Home**, Marketing Landing, Feature
5
+ Description, Architecture Overview, **Brief**) from a fixed component
6
+ library, plus a never-generated "About these templates" view explaining the
7
+ five lenses and where to hand-edit them. This is the design source of truth
8
+ for the four `project_home_*` MCP tools (`project_home_get_contract`,
9
+ `project_home_validate_summary`, `project_home_render`, `project_home_status`,
10
+ served over the app's admin routes, PRD 1089) that actually drive a
11
+ `project-home-builder` Epic's session — edit here, not in the tool
12
+ implementations, when the design changes.
13
+
14
+ **Correction, PRD "project-home-portable-persona":** generation is no longer
15
+ grounded by pointing a session at this file (or any other repo-relative
16
+ path) directly. This spec stopped being something a builder Epic reads —
17
+ neither the seeded `project-home-builder` persona
18
+ (`src/seed/agents/project-home-builder.md`, delivered to
19
+ `~/.claude/agents/`) nor the `project-home-builder` Epic tag's grounding
20
+ prompt (`src/renderer/lib/agentTagDefs.ts`) names a repo path anymore, because
21
+ a builder Epic can run against a project that never had this repo checked
22
+ out (the npm-installed case). Instead, both now point a session at the
23
+ `project_home_get_contract` MCP tool as the FIRST call of the run — its
24
+ response is a fully self-contained protocol + schema + catalog payload
25
+ computed from this spec (see "Epic tag" below). This file remains the
26
+ design source of truth for whoever implements or changes the MCP tools
27
+ themselves; it is no longer read at generation time by the builder Epic.
28
+ session-manager's own repo keeps a lean project-local overlay,
29
+ `.claude/agents/project-home-builder.md`, that adds only session-manager-
30
+ specific historical context (the saved design-mock library) on top of the
31
+ seeded persona's real protocol — see that file.
32
+
33
+ **Correction, 2026-08-02:** the original spec shipped 3 lenses
34
+ (marketing/feature/architecture) only, with Project Home's own live Brief
35
+ dashboard staying a separate, hand-built React view above the generated
36
+ block. The human then asked for the Brief's own content to be available as a
37
+ 4th generated template too ("Home") — same component-library/summary/picks
38
+ pipeline as the other three, reusing `identity`/`stats`/`pillars` (already
39
+ in `ProjectPageSummary`, no schema change needed) rather than the live
40
+ Epic-queue data the React Brief shows (that stays live-only; a static page
41
+ can't show "what's running right now" truthfully). The live Brief dashboard
42
+ above the Project Pages block is unchanged and still the primary live view —
43
+ Home is an *additional* static snapshot, not a replacement for it.
44
+
45
+ **Correction, 2026-08-03 (Epic "Project Home Layout"):** the 2026-08-02
46
+ correction above is now itself superseded. Project Home is no longer a
47
+ hand-built React page with a Project Pages viewer embedded at the bottom —
48
+ its primary content area IS the generated `home` document, hosted at a fixed
49
+ path, with a shipped default so a brand-new project is never empty. The
50
+ live Brief dashboard's synthesized fields (purpose/what/areas/scope/
51
+ conventions) become their own 5th generated lens, `brief`, rather than a
52
+ separate hand-built React block stack — see "Project Home is a hosted
53
+ document, not a React page" below for the full design, and Stage 4 for how
54
+ the display changes. `PhNow`/`PhOpenQuestions` (live Epic-queue and
55
+ open-question state) are the one part of the old React page that stays
56
+ live React, per the same "a static page can't show what's running right now
57
+ truthfully" reasoning the 2026-08-02 correction already established for
58
+ Epic-queue data.
59
+
60
+ ## Project Home is a hosted document, not a React page
61
+
62
+ - Project Home's main content area renders a generated, self-contained
63
+ static HTML document, displayed via the same sandboxed
64
+ `<iframe sandbox="allow-same-origin" srcDoc={html} />` mechanism Stage 4
65
+ already uses for the other lenses — Project Home does not recompose this
66
+ content live in its own React tree.
67
+ - That document lives at a **fixed path**,
68
+ `session-manager-operations/project-pages/output/home.html` — this is what
69
+ the app always reads for Project Home's main view, regardless of whether
70
+ it was just generated or is days old.
71
+ - Session-manager **ships a default `home.html`** baked into the app build
72
+ (not per-project state — see "Storage / ownership" below). A brand-new
73
+ project with no generated output still renders a real page, never an
74
+ empty state.
75
+ - The only way that document is replaced is the **"Generate My Project
76
+ Home"** action, which creates (or resumes) an Epic tagged
77
+ `project-home-builder`, bound to the `project-home-builder` agent — reusing
78
+ the exact Epic-creation mechanism `ProjectPagesSection.tsx`'s
79
+ `findActiveBuilderEpic` + `composeEpicIntake` already implement for
80
+ "Generate Now" today (see Stage 4). Never an inline function call, never a
81
+ main-process `claude -p` spawn — same non-negotiable Stage 1 already
82
+ states for `summary.json`.
83
+
84
+ ## Inputs (as specified by the human, 2026-08-01, extended 2026-08-02, 2026-08-03)
85
+
86
+ 1. **Component Library** — fixed, ships with the app. Source design for the
87
+ original 3 lenses saved at
88
+ `session-manager-operations/design-mocks/project-pages-component-library/`
89
+ (read its `README.md` first) — the `home` lens has no saved design mock;
90
+ it was authored directly in
91
+ `src/renderer/lib/projectPages/library/homeSlots.tsx` reusing the same
92
+ `PageLensDef` shape and the marketing lens's `identity`/`stats`/`pillars`
93
+ fields, styled as an internal dashboard rather than an outward pitch. The
94
+ `brief` lens likewise has no saved design mock — it is authored directly
95
+ against `ProjectBrief`'s own fields (see "Stage 1" below for the exact
96
+ source-field mapping), styled as a straightforward read of what the
97
+ project is, what it does, and its conventions, rather than a pitch or a
98
+ dashboard.
99
+ Shape: 5 lenses (`home` / `marketing` / `feature` / `architecture` /
100
+ `brief`), each a stack of **slots**, each slot 2-4 **variant** components,
101
+ each lens shipping named **presets** (fixed slot→variant picks) plus a
102
+ "custom" override state.
103
+ 2. **Project summary** — a JSON computed per project (see schema below).
104
+ 3. **Summary → component mapping** — picks the best-fitting variant per slot
105
+ (and/or a whole preset) from the summary's content, then renders.
106
+
107
+ ## Non-negotiables from the human's instructions
108
+
109
+ - Output **MUST be static HTML** — 5 files, one per lens. Project Home does
110
+ not recompose the pages live in its own React tree; it hosts pre-rendered
111
+ HTML. This is what "guaranteed to render" means: the generated artifact is
112
+ immune to the app's own React/Tailwind version ever drifting under it.
113
+ - Before the first "Generate My Project Home" run, Project Home renders the
114
+ **shipped default `home.html`** (see "Project Home is a hosted document,
115
+ not a React page" above) — no placeholder/fake content ever, and no
116
+ fabricated per-project claims in the default either (see Stage 4's
117
+ "Shipped default" subsection).
118
+ - Generation is not a bare function call — it runs as an Epic of a
119
+ **new type, `project-home-builder`**, so grounding, objective and output
120
+ are pinned before the agent starts (see "Epic tag" below), the same way
121
+ every other unit of work in this app is an Epic (CLAUDE.md's TAB/EPIC
122
+ domain model).
123
+ - The agent doing the generation is a **registered local agent**
124
+ (`.claude/agents/project-home-builder.md`), not an ad hoc prompt.
125
+ - Never fabricate content. Every field in the summary must trace to
126
+ something concrete (an Epic goal, a file/dir, a CLAUDE.md convention, a
127
+ git log entry) — same rule already enforced for `project-brief`, and now
128
+ also the rule governing the shipped default `home.html`'s copy.
129
+
130
+ ## Stage 0 — Component Library (build-time asset, already captured)
131
+
132
+ Port `design-mocks/project-pages-component-library/source/*.jsx` into real
133
+ `.tsx` under `src/renderer/lib/projectPages/library/` (or a sibling location
134
+ a PRD should decide precisely). Precompile with esbuild into a pure
135
+ function:
136
+
137
+ ```ts
138
+ renderProjectPages(summary: ProjectPageSummary, picks: ProjectPagePicks)
139
+ => { home: string; marketing: string; feature: string; architecture: string; brief: string }
140
+ ```
141
+
142
+ Each string is a **fully self-contained HTML document** — inline CSS, fonts
143
+ self-hosted as local assets bundled with the app (never fetched from Google
144
+ Fonts at generation time — this is the same "no network egress" principle
145
+ the design library's own `PROJ.arch.principles` already states). No runtime
146
+ JSX transform, no CDN script tags, no in-browser Babel (the source bundle
147
+ uses browser-side Babel for its own live-preview tool; that is NOT the
148
+ shipped renderer).
149
+
150
+ ## Stage 1 — Project Summary (`ProjectPageSummary`, computed per project)
151
+
152
+ New schema, a strict superset of the existing `ProjectBrief`
153
+ (`session-manager-operations/project-brief/`, `purpose/what/areas/scope/
154
+ conventions` only). Build incrementally on top of an already-generated
155
+ Brief rather than re-reading the repo from scratch:
156
+
157
+ - `identity`: name, tagline, oneLine, claim, sub, install command — derived
158
+ from `package.json` + Brief's `purpose`.
159
+ - `stats[]`, `pillars[]` — derived from Brief's `areas` (file counts, heat,
160
+ notes become pillar copy).
161
+ - `feature` (ONE deep-dive) — derived from the most-active open Epic
162
+ (highest `heat`/most recent scope entries): name, problem/solution framed
163
+ from that Epic's goal + its scope-timeline entries, steps from its PRD
164
+ chain if one exists.
165
+ - `architecture` — layers/modules from Brief's `areas` + their `epic`
166
+ ownership; decisions from Brief's `scope` entries tagged `decided`; risks
167
+ are the one field with no clean Brief source — leave empty rather than
168
+ invent, or optionally source from open `discussion`-tagged Epics.
169
+ - `brief` — the `brief` lens's source fields, read directly off
170
+ `ProjectBrief` (`session-manager-operations/project-brief/brief.json`)
171
+ with no reshaping: `purpose` (string), `what[]`, `areas[]`, `scope[]`,
172
+ `conventions[]`. This is the generated form of what the live React Brief
173
+ used to render by hand (`PhWhat`/`PhAreas`/`PhScope`/`PhConventions`) —
174
+ the `brief` lens's slots map one-to-one to these four array fields plus
175
+ the `purpose` string; a later PRD implementing the lens should not need to
176
+ invent any additional source data. `brief.json`'s `pins` (per-block
177
+ edit-pins) still apply at the Brief-authoring layer (Stage 1, before this
178
+ mapping) — the `brief` lens renders whatever `brief.json` currently holds,
179
+ pinned or not, same as every other summary field here.
180
+ - `quotes[]` — **do not fabricate testimonials**. Either omit entirely
181
+ (proof-strip variants that need a quote simply aren't selectable) or wire
182
+ a future opt-in source (e.g. GitHub issue comments) — out of scope for v1.
183
+
184
+ Written to `session-manager-operations/project-pages/summary.json`.
185
+
186
+ **Correction vs. an earlier draft of this spec:** this is NOT a
187
+ `projectBrief.refresh`-style main-process-orchestrated `claude -p` spawn.
188
+ Per the human's explicit instruction, generation runs as a
189
+ `project-home-builder`-tagged **Epic** — an ordinary Chat/Terminal claude
190
+ session grounded by that tag's `initialPromptTemplate` (`agentTagDefs.ts`),
191
+ which drives the session to call the `project_home_get_contract` MCP tool
192
+ first and follow the protocol it returns (see the correction note at the top
193
+ of this file). That session reads `brief.json` and the repo directly
194
+ (Read/Grep/Bash tools) and composes `summary.json` itself, then writes it
195
+ via `project_home_render` (not a raw Write-tool file write — see Stage 3).
196
+ There is no separate nested `claude -p` call and no new main-process IPC for
197
+ synthesis beyond the four `project_home_*` admin-routed tools themselves.
198
+ Cost-gating is inherent: it only runs when a human clicks **"Generate My
199
+ Project Home"** (which creates/resumes the Epic), same discipline as any
200
+ other Epic. `brief.json` itself is still produced by
201
+ `projectBrief.refresh`'s existing main-process-orchestrated mechanism — that
202
+ mechanism is unchanged and stays, because `brief.json` remains an *input* to
203
+ Stage 1, read by the `project-home-builder` Epic session same as any other
204
+ repo file. What changes is only that `projectBrief.refresh` no longer has
205
+ its own dedicated user-facing button — see Stage 4's "One action, not two"
206
+ subsection.
207
+
208
+ ## Stage 2 — Summary → component mapping (selection)
209
+
210
+ **Reversed 2026-08-03 (Epic "Project Home Layout"): there is no separate
211
+ deterministic selection stage.** The `project-home-builder` agent itself
212
+ picks each slot's variant, by reasoning over its composed summary against
213
+ the component library's own variant notes — the same class of step as
214
+ Stage 1's summary authoring, not a distinct machine-checkable predicate
215
+ scorer. Concretely: for each lens, for each slot, the agent reads the
216
+ candidate variants' prose `note`/description — served to it directly in
217
+ `project_home_get_contract`'s catalog response, sourced server-side from
218
+ `src/renderer/lib/projectPages/library/*.tsx` so the agent never needs to
219
+ read that source itself (e.g. "Needs a real quote.", "Needs a strong
220
+ screenshot.") — and judges which variant genuinely fits this project's
221
+ summary content, then passes the resulting picks to `project_home_render` —
222
+ no intermediate predicate language, no scorer script.
223
+
224
+ Output persisted to `session-manager-operations/project-pages/picks.json`
225
+ in the same shape as before (`Record<lensId, Record<slotId, variantId>>`),
226
+ plus a top-level `schemaVersion` field (see "Stale-picks migration" below).
227
+ **The 'respect existing hand-picks unless explicit start-over' rule is
228
+ unchanged and still what keeps selection stable across regenerates**: a
229
+ project's picks are judged once (or on an explicit reset request) and then
230
+ persisted like `project-brief`'s pinned blocks, so moving selection from a
231
+ script to agent judgment does not reintroduce per-regenerate
232
+ nondeterminism — the agent must not silently overwrite it (mirrors
233
+ `project-brief`'s per-block `pins`, but per-slot-pick here instead of
234
+ per-paragraph-text).
235
+
236
+ **Stale-picks migration (found 2026-08-03).** Today's on-disk
237
+ `picks.json` was written by the now-deleted deterministic scorer
238
+ (`selectionPredicates.ts`, retired by PRD 958) — every existing project's
239
+ picks are preset-`v1` defaults, not real judgment. The 'preserve existing
240
+ hand-picks on regenerate' rule above would otherwise grandfather these in
241
+ forever, silently defeating agent-owned selection for every project that
242
+ already has a `picks.json`. Decided: `picks.json` carries
243
+ `schemaVersion: 1` for scorer-era files (files with no `schemaVersion`
244
+ field at all are treated as `schemaVersion: 1` — the scorer never wrote
245
+ one) and `schemaVersion: 2` once written by the agent or hand-edited by a
246
+ human. On the first `project-home-builder` Epic run after this change, the
247
+ agent checks `picks.json`'s `schemaVersion`: if `1` (or absent), the
248
+ existing picks are **non-authoritative** — the agent re-judges every slot
249
+ from scratch (ignoring the stale values, not merging with them) and writes
250
+ the result back as `schemaVersion: 2`. Every later run treats a
251
+ `schemaVersion: 2` file as real hand/agent judgment and follows the normal
252
+ 'preserve unless explicit start-over' rule. This re-judgment happens
253
+ exactly once per project, not on every run — `schemaVersion` is the marker
254
+ that prevents repeating it.
255
+
256
+ ## Stage 3 — Render
257
+
258
+ `renderProjectPages(summary, picks)` → 5 HTML strings. Write to
259
+ `session-manager-operations/project-pages/output/{home,marketing,feature,
260
+ architecture,brief}.html` plus a `manifest.json` (`generatedAt`, `model`,
261
+ `summarySynthesizedAt`, and a drift flag vs. the Brief's own
262
+ `synthesizedAt` — same drift-chip idea `project-brief` already uses).
263
+ `output/home.html` is the fixed path Project Home's main view reads (see
264
+ "Project Home is a hosted document, not a React page" above) — it is
265
+ written by this same single render pass as the other four lenses, not by a
266
+ separate mechanism.
267
+
268
+ ## Stage 4 — Project Home display
269
+
270
+ - **No empty state for the main view.** With a shipped default `home.html`
271
+ (see "Project Home is a hosted document, not a React page" above), Project
272
+ Home's main content area always has something real to show — either the
273
+ shipped default or a project-generated document. What the UI must surface
274
+ instead is **provenance**: a chip stating whether the currently-displayed
275
+ `home.html` is the shipped default or a generated document, and if
276
+ generated, when (`manifest.json`'s `generatedAt`). The **"Generate My
277
+ Project Home"** action is always available regardless of which state is
278
+ showing.
279
+ - **Shipped default `home.html`** is a **build-time asset**, not per-project
280
+ state — it ships baked into the app bundle (same "ships with the app"
281
+ status as the component library in Stage 0), not written into any
282
+ project's `session-manager-operations/`. It must be honest about being a
283
+ default: its copy describes what Project Home is in general and prompts
284
+ the reader to press "Generate My Project Home" — it must **not** contain
285
+ fabricated project-specific content (name, stats, claims about this
286
+ particular repo), per this spec's existing never-fabricate rule. The app
287
+ falls back to this shipped asset whenever a project's own
288
+ `output/home.html` is absent; once a project has generated its own, that
289
+ file (at the fixed per-project path) takes over and the shipped default is
290
+ never shown again for that project.
291
+ - **"Generate My Project Home"** click creates (or resumes) an Epic tagged
292
+ `project-home-builder` in the active project and sends it the tag's
293
+ grounding prompt (see Epic tag below) as the opening message — the Epic
294
+ IS the unit of work, same as every other Epic in this app. This reuses
295
+ the exact mechanism `ProjectPagesSection.tsx`'s `findActiveBuilderEpic` +
296
+ `composeEpicIntake` already implement today (there under the "Generate
297
+ Now"/"Regenerate" names) — no new Epic-creation code path, only a rename
298
+ and a widened trigger surface (see "One action, not two" below).
299
+ - **One action, not two.** Today there are two competing CTAs: "Refresh
300
+ brief" (regenerates `brief.json` for the old hand-built React blocks) and
301
+ "Generate Now"/"Regenerate" (regenerates the Project Pages HTML). These
302
+ **consolidate into the single "Generate My Project Home" action**, because
303
+ the Brief's content is now one of the five generated lenses (`brief`) —
304
+ there is no longer a separate live-React consumer of `brief.json` that
305
+ needs its own refresh trigger. `brief.json` itself, and the
306
+ `projectBrief.refresh` mechanism that writes it, are unchanged and still
307
+ needed — `brief.json` is still an *input* to Stage 1 (see Stage 1's
308
+ correction note above) — it simply stops being exposed as its own
309
+ user-facing button. "Generate My Project Home" is responsible for
310
+ ensuring `brief.json` is fresh enough before it runs Stages 1-3 (e.g.
311
+ invoking `projectBrief.refresh` itself as a first step, or the
312
+ `project-home-builder` agent reading `brief.json` and refreshing it
313
+ in-session if stale) — the exact mechanics of that call are an
314
+ implementation detail for the PRD that wires the button, not specified
315
+ further here.
316
+ - Once a project has generated its own `output/*.html`, Project Home renders
317
+ the 5 pages via a sandboxed
318
+ `<iframe sandbox="allow-same-origin" srcDoc={html} />`, toggled by lens
319
+ (Home / Marketing / Feature / Architecture / Brief) — never re-parsed into
320
+ the app's own React tree. The main Project Home view defaults to the
321
+ `home` lens; the other four remain reachable the same way
322
+ `ProjectPagesSection.tsx` exposes them today.
323
+ - **`PhNow` and `PhOpenQuestions` stay live React**, rendered as a thin strip
324
+ **above** the hosted HTML document (default or generated) rather than
325
+ folded into any generated lens. Reason: they show live state — "what is
326
+ in flight" (the live Epic queue) and "waiting on you" (live unresolved
327
+ questions) — and injecting live data into a generated static document
328
+ would violate this spec's own non-negotiable that the generated artifact
329
+ is "self-contained static HTML, immune to the app's own React/Tailwind
330
+ drift" (see "Non-negotiables" above): a document that embeds live data
331
+ stops being self-contained the moment that data changes underneath it.
332
+ This is the same reasoning the 2026-08-02 correction already applied to
333
+ the old React Brief's Epic-queue data — carried forward unchanged, just
334
+ now scoped to two specific components instead of the whole page.
335
+ - A 6th tab, **"About these templates,"** is always reachable (even before
336
+ the first "Generate My Project Home") and is never part of
337
+ `output/*.html` — it's static explainer copy
338
+ (`ProjectPagesLibraryExplainer` in `ProjectPagesSection.tsx`) naming the 5
339
+ lenses, their source slot files, and the 3 real on-disk paths a human
340
+ would touch to change what gets generated:
341
+ `project-pages/summary.json` (the computed inputs), `project-pages/
342
+ picks.json` (per-project, per-slot overrides — hand-edit a pick here and
343
+ regenerating preserves it, since the `project-home-builder` agent respects
344
+ existing picks unless explicitly told to start over, same rule Stage 2
345
+ already had — see Stage 2's schema-version note for the one-time
346
+ exception), and `src/renderer/lib/projectPages/library/` (the component
347
+ library itself, shared across every project — editing it is a code
348
+ change, not a per-project override).
349
+
350
+ ## Storage / ownership
351
+
352
+ **Correction, PRD 1089/1090 (`project_home_*` MCP tools):** the write path
353
+ described in an earlier draft of this section — a builder Epic's own `Write`
354
+ tool writing `summary.json`/`picks.json`/`output/*.html` directly, with no
355
+ `OWNERS` entry needed because no main-process code was involved — is
356
+ superseded. `project_home_render` now writes those files via the app's
357
+ admin API, which IS main-process code going through `config.cjs`'s write
358
+ helpers. `project-pages` is therefore now listed in `OWNERS`
359
+ (`src/main/lib/opsOwnership.cjs`), owned by `project-home`, scoped to the
360
+ app's admin render route only (per CLAUDE.md's domain-model law) — see
361
+ `project-pages/README.md` for the exact split. A builder Epic's own direct
362
+ Write-tool authoring of anything under `project-pages/` (as opposed to going
363
+ through `project_home_render`) stays ungoverned/unsupported; the sanctioned
364
+ path for a builder Epic is always the MCP tool, never a raw file write.
365
+
366
+ The concurrency concern is real but bounded a different way: "Generate My
367
+ Project Home" must check for an already-active `project-home-builder` Epic
368
+ for this project and **resume/focus it** instead of creating a second one —
369
+ the same "refuse a live session" guard pattern `deleteEpic` already uses
370
+ elsewhere — rather than relying on filesystem-level write arbitration.
371
+
372
+ The **shipped default `home.html`** is a different storage class again: it
373
+ is packaged with the app build itself (e.g. under the renderer's own static
374
+ assets, resolved at runtime the same way other build-time-baked assets are)
375
+ — it is never written to, or read from, any project's
376
+ `session-manager-operations/` tree, and carries no per-project state at all.
377
+ It is not part of `project-pages/` and is not a candidate for an `OWNERS`
378
+ entry.
379
+
380
+ Add `session-manager-operations/project-pages/README.md` once the first
381
+ file lands, documenting the shape (matching `design-mocks/`'s and
382
+ `HUMAN_LEARN/`'s own READMEs, not an `OWNERS` namespace README).
383
+
384
+ ## Epic tag: `project-home-builder`
385
+
386
+ Added to `src/renderer/lib/tagLibrary.ts` (`EpicTag` union + `TAG_LIBRARY`
387
+ entry) and `src/renderer/lib/agentTagDefs.ts` (`AGENT_TAG_DEFS` entry with
388
+ an `initialPromptTemplate` that grounds the session): call
389
+ `project_home_get_contract` first — its response IS the protocol, the
390
+ schemas, and the catalog, entirely self-contained — then follow it through
391
+ `project_home_validate_summary` → `project_home_render` →
392
+ `project_home_status`. The template names no repo-relative path (this is
393
+ what makes generation work on a machine with only the npm package
394
+ installed) and explicitly instructs the session to report and stop, never
395
+ build pipeline infrastructure, if the contract tool is unavailable or
396
+ errors. Deliberately **not**
397
+ added to `AGENT_TAG_DEFS`'s `AGENT_TAG_ORDER` yet — same precedent as the
398
+ existing `build` tag ("no UI surface to create a build-tagged Epic exists
399
+ yet"): the creation surface (the "Generate My Project Home" button) is
400
+ itself one of the PRDs building this feature, so it adds the tag to
401
+ `AGENT_TAG_ORDER` at the same time it wires the button, rather than exposing
402
+ a half-built creation path in the New Epic composer before that button
403
+ exists.
404
+
405
+ ## Screenshots
406
+
407
+ Several variants need real app screenshots (`FvShot` placeholders in the
408
+ saved library). Reuse the existing `blog-for-project-feature` skill's real-
409
+ capture pipeline rather than building a second one — out of scope for the
410
+ first PRD chain; ship with the honest placeholder pattern until wired.
411
+
412
+ ## Explicit non-goals for v1
413
+
414
+ - No installable "design pack" packaging (Stage 0 ships baked into the app;
415
+ making it swappable is a later roadmap item, not part of this build).
416
+ - No automatic/background regeneration — manual trigger only, same
417
+ cost-discipline as `project-brief`.