heyspex 0.2.2 → 0.2.4

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 (79) hide show
  1. package/.claude-plugin/marketplace.json +2 -1
  2. package/README.md +11 -0
  3. package/bin/hs-vault-binding.mjs +157 -0
  4. package/bin/hs.mjs +83 -79
  5. package/bin/spexcode.mjs +91 -0
  6. package/dev-factory/engine/worktree.mjs +36 -7
  7. package/dev-factory/lib/epic-detect.mjs +2 -2
  8. package/dev-factory/lib/fleet-readiness.mjs +3 -5
  9. package/dev-factory/lib/fleet-state.mjs +2 -2
  10. package/dev-factory/lib/sufficiency-score.mjs +3 -5
  11. package/dist/cli/hs-check.mjs +76 -46
  12. package/dist/cli/hs-claim.mjs +63 -33
  13. package/dist/cli/hs-connect.mjs +520 -214
  14. package/dist/cli/hs-defer.mjs +161 -19
  15. package/dist/cli/hs-dev.mjs +11 -5
  16. package/dist/cli/hs-env.mjs +187 -161
  17. package/dist/cli/hs-index-rebuild.mjs +123 -78
  18. package/dist/cli/hs-index-reconcile.mjs +203 -107
  19. package/dist/cli/hs-init.mjs +426 -179
  20. package/dist/cli/hs-install.mjs +759 -437
  21. package/dist/cli/hs-join.mjs +590 -383
  22. package/dist/cli/hs-vault-pull.mjs +359 -254
  23. package/dist/cli/hs-vault-push.mjs +151 -113
  24. package/dist/cli/hs-vault.mjs +271 -104
  25. package/dist/cli/hs-workspace.mjs +90 -57
  26. package/dist/cli-templates/customer-vault/specs/protocols/session-close-protocol.md +178 -91
  27. package/docs/copilot-plugin-install.md +200 -177
  28. package/docs/driving-heyspex-from-copilot.md +174 -165
  29. package/docs/mcp-client-config.md +93 -25
  30. package/package.json +257 -250
  31. package/plugins/heyspex/.claude-plugin/plugin.json +13 -12
  32. package/plugins/heyspex/.cursor-plugin/plugin.json +16 -15
  33. package/plugins/heyspex/.mcp.json +3 -4
  34. package/plugins/heyspex/README.md +323 -312
  35. package/plugins/heyspex/assets/heyspex-glyph-128.png +0 -0
  36. package/plugins/heyspex/assets/heyspex-glyph-256.png +0 -0
  37. package/plugins/heyspex/assets/heyspex-glyph.svg +12 -0
  38. package/plugins/heyspex/bin/launch-mcp.mjs +21 -7
  39. package/plugins/heyspex/mcp.json +12 -13
  40. package/scripts/check-mcp-freshness.mjs +6 -4
  41. package/scripts/claude-hooks/_intent-classifier-router.mjs +518 -456
  42. package/scripts/claude-hooks/intent-classifier-trigger.mjs +305 -279
  43. package/scripts/claude-hooks/research-method-guard.mjs +2 -2
  44. package/scripts/claude-hooks/wip-checkpoint.mjs +33 -9
  45. package/scripts/claude-statusline/fonts/HeySpexIcons.ttf +0 -0
  46. package/scripts/claude-statusline/statusline-command.mjs +1073 -0
  47. package/scripts/copilot-statusline.mjs +130 -0
  48. package/scripts/dev-server-status.mjs +3 -2
  49. package/scripts/dev-server-stop.mjs +3 -2
  50. package/scripts/hs-capture-cli.mjs +2 -2
  51. package/scripts/hs-settings.mjs +2 -2
  52. package/scripts/hs-view.mjs +3 -2
  53. package/scripts/install-copilot-hooks.mjs +152 -36
  54. package/scripts/lib/copilot-cli.mjs +108 -0
  55. package/scripts/lib/customer-kit.mjs +223 -30
  56. package/scripts/lib/dev-mode.mjs +28 -2
  57. package/scripts/lib/shared-path-helpers.mjs +32 -0
  58. package/scripts/lib/standalone-doctor.mjs +131 -32
  59. package/scripts/wip-ledger-health.mjs +3 -2
  60. package/spexharness/src/gates/vault-mirror-catchup.mjs +113 -24
  61. package/spexharness/src/gates/vault-mirror-catchup.runner.mjs +52 -0
  62. package/spexharness/src/intent-directive.mjs +839 -626
  63. package/spexharness/src/rule-table.mjs +1 -1
  64. package/vendor/heyspex-mcp/cli-verbs.mjs +16 -2
  65. package/vendor/heyspex-mcp/cli.mjs +20 -4
  66. package/vendor/heyspex-mcp/console-fetch.mjs +15 -3
  67. package/vendor/heyspex-mcp/dev-tools.mjs +11 -4
  68. package/vendor/heyspex-mcp/events-tools.mjs +1 -1
  69. package/vendor/heyspex-mcp/factory-run-status.mjs +42 -0
  70. package/vendor/heyspex-mcp/http-transport.mjs +6 -1
  71. package/vendor/heyspex-mcp/mcp-config.mjs +4 -2
  72. package/vendor/heyspex-mcp/server-identity.mjs +13 -0
  73. package/vendor/heyspex-mcp/spec-edit-tools.mjs +26 -1
  74. package/vendor/heyspex-mcp/test-helpers.mjs +5 -2
  75. package/vendor/heyspex-mcp/tool-catalog.mjs +12 -0
  76. package/vendor/heyspex-mcp/tool-dispatch.mjs +63 -23
  77. package/vendor/heyspex-mcp/usable-dir-env.mjs +82 -0
  78. package/vendor/heyspex-mcp/vault-binding.mjs +839 -0
  79. package/vendor/heyspex-mcp/vault-resolve.mjs +353 -245
@@ -1,91 +1,178 @@
1
- ---
2
- id: HS-PROTO-session-close-protocol
3
- name: Session Close Protocol
4
- type: protocol
5
- status: open
6
- priority: 1
7
- owner: TODO — your name/handle
8
- created: '2026-05-14T22:47:28-05:00'
9
- updated: '2026-09-11'
10
- scope: session
11
- tags:
12
- - session
13
- - close-out
14
- - workflow
15
- - review
16
- triggers:
17
- - close_session
18
- summary: |
19
- Splits session close into the agent's terminal actions (submit for review, change-log row, WIP ledger, audit export, housekeeping) and the reviewer's job (walk the acceptance criteria, materialize memories, commit). The agent does not commit or push.
20
- related:
21
- - "[[memory-protocol]]"
22
- - "[[spec-hierarchy]]"
23
- - "[[entity-model]]"
24
- ---
25
-
26
- # Session Close Protocol
27
-
28
- Session close splits cleanly into two responsibilities: the **agent's terminal actions** (flip status through the API, write the hand-off, leave the tree for review) and the **reviewer's job** (walk the acceptance criteria, decide accept or reject, commit). The agent does not commit and does not push; the reviewer's commit is the close action.
29
-
30
- ## When to close — the agent can call last orders
31
-
32
- Closing procedures are encouraged at every wrap-up, and starting them is not the user's job alone.
33
-
34
- - **Self-initiated close-out.** When the session's work is done (deliverables complete, verification reported, no pending user ask) the agent announces in one line that it is closing out and runs the steps below without being asked.
35
- - **Guide the user at done-ness signals.** When the user signals completion ("that's all", "looks good", an end-of-day sign-off), offer or start close-out in the same reply.
36
- - **Scope guardrail.** A self-initiated close performs only what the thread type owes. It is never a license to expand the work.
37
-
38
- Call `heyspex_preflight({ intent: "close_session" })` first; it returns the procedures to consult for this session.
39
-
40
- ## Thread-type close-out — what kind of session was this? (ask first)
41
-
42
- Close-out is not one-size-fits-all. Identify what the session actually did and apply only the matching path.
43
-
44
- | Thread type | How you can tell | Close-out path |
45
- |---|---|---|
46
- | **Capture-only** | Only captured ideas; no claim, no code | No close-out. Promote the capture to research or leave it pinned. |
47
- | **Research-only** | Saved a research doc; no claimed spec | Save the research. Research is evergreen: no submit, no status flip. |
48
- | **Plan / ingest-only** | Filed milestones and epics; no task execution | Run `heyspex_validate_linkage`; confirm each spec has a `summary`. No task close. |
49
- | **One-task execution** | Claimed and finished a single task | Steps 1–8 below for that one unit. |
50
- | **Multi-task / epic push** | Claimed and finished several tasks | Steps 1–8; submit each unit; one consolidated WIP ledger. |
51
- | **Mid-implementation rollover** | Claimed but not finished | Not a close. Record a lightweight WIP checkpoint only and leave the spec `in_progress`. |
52
-
53
- Mixed threads run the union of the matching paths, in order. Every step is safe to re-run.
54
-
55
- ## Agent terminal actions (end of session)
56
-
57
- For every spec the agent completed this session:
58
-
59
- 1. **Submit build-complete through the status API.** Call `heyspex_submit_for_review({ spec_id: "<id>" })` on each completed unit. Never hand-edit `status:` in frontmatter; the status API is the single source of truth and a frontmatter-only flip does not drive the progress ladder.
60
- 2. **Report acceptance progress.** Call `heyspex_report_progress` with `acProgress` for each criterion you verified, so the acceptance checklist reflects the real state.
61
- 3. **Append a change-log row** to the spec: `| YYYY-MM-DD | <agent + model> | <one-line summary> |`.
62
- 4. **Record the structured handoff.** Call `heyspex_record_wip({ spec_id: "<epic-id>", specs_filed, remaining, verified, notes })` for the epic you worked. It is the machine-readable hand-off the next session's `/hs-next` surfaces.
63
- 5. **Flush the audit export.** Call `heyspex_export_events` (or `hs export-events`) so this session's claim and status events are written to the vault.
64
- 6. **Capture knowledge worth keeping.** Propose memory candidates (lessons, decisions, references) per [[memory-protocol]]; the reviewer decides which to materialize.
65
- 7. **Run housekeeping.** Run `heyspex_validate_linkage` and fix anything that is already yours to fix. Then say plainly, once, what is left that only the owner can act on.
66
- 8. **Do not `git commit` and do not `git push`**, unless this vault has opted in to agent commits. Leave the working tree dirty; the reviewer's commit is the close action.
67
-
68
- If a spec was only partly completed, leave it `in_progress` and do not submit it. Status hand-off is for work the agent considers reviewer-ready.
69
-
70
- ## The close-out write-up — every named item says fixed or not fixed
71
-
72
- The steps above decide what gets recorded. This section decides how the close-out message reads. The most important fact about any item is whether the thing works now, and that fact goes first on the line, in one of four words:
73
-
74
- | Word | Means |
75
- |---|---|
76
- | **Fixed** | The problem is gone. Verified, and the line names the check that proved it. |
77
- | **Partly fixed** | Some of it shipped. The line says which part did and which did not. |
78
- | **Not fixed** | Found and recorded. Nothing works differently than before. |
79
- | **Not started** | Named as work, not begun. |
80
-
81
- 1. The word comes first on the line.
82
- 2. Every named item carries one.
83
- 3. Fixed and not-fixed items go in separate groups.
84
- 4. "Filed", "flagged", "captured", "noted" and "handled" describe a record, never an outcome. They may follow one of the four words but never replace one.
85
-
86
- ## Reviewer responsibilities (human, separate pass)
87
-
88
- 1. Read each review companion or change-log entry. Walk the acceptance criteria against the actual diff.
89
- 2. Decide accept, edit or reject for every memory candidate. Materialize accepted ones as files under `specs/memory/<type>s/<slug>.md`, linked back to the parent spec.
90
- 3. On **pass**: commit the diff, including any materialized memories and the status flip. The commit is the close action.
91
- 4. On **reopen**: leave the spec `in_review`, document the gap, and the next agent session picks it up.
1
+ ---
2
+ id: HS-PROTO-session-close-protocol
3
+ name: Session Close Protocol
4
+ type: protocol
5
+ status: open
6
+ priority: 1
7
+ owner: TODO — your name/handle
8
+ created: '2026-05-14T22:47:28-05:00'
9
+ updated: '2026-10-16'
10
+ scope: session
11
+ tags:
12
+ - session
13
+ - close-out
14
+ - workflow
15
+ - review
16
+ triggers:
17
+ - close_session
18
+ summary: |
19
+ Splits session close into the agent's terminal actions (submit for review, change-log row, WIP ledger, audit export, housekeeping) and the reviewer's job (walk the acceptance criteria, materialize memories, commit). The agent does not commit or push.
20
+ related:
21
+ - "[[memory-protocol]]"
22
+ - "[[spec-hierarchy]]"
23
+ - "[[entity-model]]"
24
+ ---
25
+
26
+ # Session Close Protocol
27
+
28
+ Session close splits cleanly into two responsibilities: the **agent's terminal actions** (flip status through the API, write the hand-off, leave the tree for review) and the **reviewer's job** (walk the acceptance criteria, decide accept or reject, commit). The agent does not commit and does not push; the reviewer's commit is the close action.
29
+
30
+ ## When to close — the agent can call last orders
31
+
32
+ Closing procedures are encouraged at every wrap-up, and starting them is not the user's job alone.
33
+
34
+ - **Self-initiated close-out.** When the session's work is done (deliverables complete, verification reported, no pending user ask) the agent announces in one line that it is closing out and runs the steps below without being asked.
35
+ - **Guide the user at done-ness signals.** When the user signals completion ("that's all", "looks good", an end-of-day sign-off), offer or start close-out in the same reply.
36
+ - **Scope guardrail.** A self-initiated close performs only what the thread type owes. It is never a license to expand the work.
37
+
38
+ Call `heyspex_preflight({ intent: "close_session" })` first; it returns the procedures to consult for this session.
39
+
40
+ ## Thread-type close-out — what kind of session was this? (ask first)
41
+
42
+ Close-out is not one-size-fits-all. Identify what the session actually did and apply only the matching path.
43
+
44
+ | Thread type | How you can tell | Close-out path |
45
+ |---|---|---|
46
+ | **Capture-only** | Only captured ideas; no claim, no code | No close-out. Promote the capture to research or leave it pinned. |
47
+ | **Research-only** | Saved a research doc; no claimed spec | Save the research. Research is evergreen: no submit, no status flip. |
48
+ | **Plan / ingest-only** | Filed milestones and epics; no task execution | Run `heyspex_validate_linkage`; confirm each spec has a `summary`. No task close. |
49
+ | **One-task execution** | Claimed and finished a single task | Steps 1–8 below for that one unit. |
50
+ | **Multi-task / epic push** | Claimed and finished several tasks | Steps 1–8; submit each unit; one consolidated WIP ledger. |
51
+ | **Mid-implementation rollover** | Claimed but not finished | Not a close. Record a lightweight WIP checkpoint only and leave the spec `in_progress`. |
52
+
53
+ Mixed threads run the union of the matching paths, in order. Every step is safe to re-run.
54
+
55
+ ## Agent terminal actions (end of session)
56
+
57
+ For every spec the agent completed this session:
58
+
59
+ 1. **Submit build-complete through the status API.** Call `heyspex_submit_for_review({ spec_id: "<id>" })` on each completed unit. Never hand-edit `status:` in frontmatter; the status API is the single source of truth and a frontmatter-only flip does not drive the progress ladder.
60
+ 2. **Report acceptance progress.** Call `heyspex_report_progress` with `acProgress` for each criterion you verified, so the acceptance checklist reflects the real state.
61
+ 3. **Append a change-log row** to the spec: `| YYYY-MM-DD | <agent + model> | <one-line summary> |`.
62
+ 4. **Record the structured handoff.** Call `heyspex_record_wip({ spec_id: "<epic-id>", specs_filed, remaining, verified, notes })` for the epic you worked. It is the machine-readable hand-off the next session's `/hs-next` surfaces.
63
+ 5. **Flush the audit export.** Call `heyspex_export_events` (or `hs export-events`) so this session's claim and status events are written to the vault.
64
+ 6. **Capture knowledge worth keeping.** Propose memory candidates (lessons, decisions, references) per [[memory-protocol]]; the reviewer decides which to materialize.
65
+ 7. **Run housekeeping.** Run `heyspex_validate_linkage` and fix anything that is already yours to fix. Then say plainly, once, what is left that only the owner can act on.
66
+ 8. **Do not `git commit` and do not `git push`**, unless this vault has opted in to agent commits. Leave the working tree dirty; the reviewer's commit is the close action.
67
+
68
+ If a spec was only partly completed, leave it `in_progress` and do not submit it. Status hand-off is for work the agent considers reviewer-ready.
69
+
70
+ ## The close-out write-up — every named item says fixed or not fixed
71
+
72
+ The steps above decide what gets recorded. This section decides how the close-out message reads. The most important fact about any item is whether the thing works now, and that fact goes first on the line, in one of four words:
73
+
74
+ | Word | Means |
75
+ |---|---|
76
+ | **Fixed** | The problem is gone. Verified, and the line names the check that proved it. |
77
+ | **Partly fixed** | Some of it shipped. The line says which part did and which did not. |
78
+ | **Not fixed** | Found and recorded. Nothing works differently than before. |
79
+ | **Not started** | Named as work, not begun. |
80
+
81
+ 1. The word comes first on the line.
82
+ 2. Every named item carries one.
83
+ 3. Fixed and not-fixed items go in separate groups.
84
+ 4. "Filed", "flagged", "captured", "noted" and "handled" describe a record, never an outcome. They may follow one of the four words but never replace one.
85
+
86
+ ## Seat variant: per-COO close-out
87
+
88
+ > **Read this when the session is an unattended seat started by a launcher**, not an interactive chat. A seat is an AI project manager (a COO seat) that the SpexCode launcher starts in its own window and closes again when the seat is finished. Nobody sits in the seat to say "that's all", so the close-out has to run by itself on every way a seat can end, and the launcher has to know when it is safe to close the window. The rest of this protocol still applies; this section says **which side owns each step** when there are two sides.
89
+
90
+ **The rule in one line:** whoever is still running does the close-out. A seat that reaches its own end runs it. A seat that is killed, crashes or is stopped from outside cannot, so the launcher runs it for that seat. No step is ever done by both, and the launcher closes the window only after the seat's `close` event has landed.
91
+
92
+ ### Who owns each step
93
+
94
+ "Seat" means the seat runs the step itself at the end of its run. "Launcher" means the launcher runs it. "Reviewer" means the later human review pass. "Not owed" means no one owes it on a seat run, with the reason.
95
+
96
+ | # | Close-out step | Owner | How, on a seat run |
97
+ |---|---|---|---|
98
+ | 1 | Declare the thread type | Seat | A seat is always an execution thread. Its declaration is the `heyspex_preflight({ intent: "close_session" })` call it makes before submitting; that call also unlocks the seat's single-use submit confirm (see below). |
99
+ | 2 | Report acceptance progress | Seat | `heyspex_report_progress` after each criterion, during the work. The close-out treats a held claim as complete only when every criterion was reported met. |
100
+ | 3 | Record the WIP ledger | Seat | `heyspex_record_wip` on the epic the seat worked (on the milestone for a milestone seat's final close). When the owner must act, `remaining` carries a line `owner: <what the owner must do>`. |
101
+ | 4 | Submit or release claims | Seat | `heyspex_submit_for_review` for each held claim whose criteria are all reported met; `heyspex_release_spec` for every other claim the seat still holds. A failed submit or release is recorded and never stops the remaining steps. The seat never writes `status:`. |
102
+ | 5 | Write the summary | Seat | Done, left, needs owner, spend and time, written to the seat's window and carried in the `close` event. |
103
+ | 6 | Emit `final`, then `close` | Seat | `close` is always the last line of the seat's event stream and is emitted exactly once. |
104
+ | 7 | Keep the event audit file | Launcher | The launcher appends every event the seat streams, including `final` and `close`, to the run's audit file. The seat only emits. |
105
+ | 8 | Flush the vault audit export | Not owed | A seat does not call `heyspex_export_events`. The export is safe to repeat, and the next interactive close-out (or a scheduled export) picks the seat's events up. |
106
+ | 9 | Wait for `close`, or declare it missing | Launcher | After the seat exits, the launcher waits a set time (60 seconds by default) for its `close`. None in time is a defect (below). |
107
+ | 10 | Done-check | Launcher | The launcher checks the epic's real status in the vault and stores the result with the close record. A seat's own "done" is never taken on its word. |
108
+ | 11 | State update | Launcher | The launcher records the close (kind, who closed, summary, needs-owner text, time) and prints the needs-owner text in the run terminal. |
109
+ | 12 | Close the window | Launcher | Only after the seat has exited and its close resolved, after a short grace so the exit summary stays readable. A missing close keeps the window open. |
110
+ | 13 | Close-out for a dying seat | Launcher | Only when the seat cannot run steps 3 to 6 itself. See "Stopped from outside" below. |
111
+ | 14 | Change-log row and review notes | Reviewer | The seat's summary and WIP entry are the breadcrumb; the reviewer's pass turns them into the review record. |
112
+ | 15 | Capture knowledge worth keeping | Reviewer | The reviewer pass proposes and keeps memories. A seat does not create memory files during close-out. |
113
+ | 16 | Housekeeping owner report | Seat | The owner report is the needs-owner line in the summary. Link validation is not owed by a seat; the next interactive close runs it. |
114
+ | 17 | Commit or push | Not owed | Never, by either side. The dirty tree is the expected hand-off. |
115
+
116
+ The seat's own steps run in a fixed order: record WIP, settle claims, write the summary, emit `final`, emit `close`. Each step is safe to repeat: running the close-out again skips what already succeeded and never sends a second `close`.
117
+
118
+ ### How a seat ends its run
119
+
120
+ - **`heyspex_session_end`** means the work is done. The seat answers it itself and runs its close-out. In a milestone seat it ends only the current epic.
121
+ - **`signal_owner_gated({ reason, kind })`** means everything left needs the owner (`kind: owner_gated`, the default) or nothing can be built because no build machine is available (`kind: fleet_unavailable`). The seat runs the same close-out.
122
+
123
+ **Submit confirm.** An unattended seat has no human to approve a submit. The seat approves exactly one submit at a time for itself, and nothing else, only when it was started by the launcher in auto permission mode and its `close_session` preflight succeeded. Filing new specs stays gated.
124
+
125
+ ### Paths, one per way a seat can end
126
+
127
+ | How the seat ended | Who runs the close-out | `close_kind` | `closed_by` | What the owner sees |
128
+ |---|---|---|---|---|
129
+ | Work done | Seat | `done` | `seat` | The summary; the window closes after the grace. |
130
+ | Needs the owner | Seat | `owner_gated` | `seat` | The reason, in the run terminal and in the WIP ledger as `owner: …`. The epic is skipped, not counted as a failure. |
131
+ | No build machine | Seat | `fleet_unavailable` | `seat` | Same close-out; reported as fleet-unavailable, not as a failure. |
132
+ | Model stop or API error | Seat | `incomplete` or `error` | `seat` | Unsubmitted claims are released; the WIP ledger names what is left. |
133
+ | The seat's own budget ran out | Seat | `budget` | `seat` | The run stops for that epic (an epic budget) or for the seat (the seat budget). |
134
+ | Ctrl+C, stop, crash, stall, or a budget stop by the launcher | Launcher | `interrupted`, `crashed` or `budget` | `launcher` | See "Stopped from outside". |
135
+ | Seat exited with no `close` in time | Launcher | `forced` | `launcher` | A defect; the window stays open. |
136
+
137
+ **Needs-the-owner and no-build-machine run the same close-out as done.** The only differences are the close kind and the needs-owner text, which must name exactly what the owner has to do.
138
+
139
+ **Stopped from outside.** The seat is gone, so the launcher runs the close-out for it:
140
+
141
+ 1. Release the claims held by that seat only, never another session's.
142
+ 2. Record an interrupted WIP entry on the epic naming the specs touched, the claims released, and why.
143
+ 3. Append a `close` with `closed_by: launcher` and the matching kind.
144
+ 4. If the seat already sent its own `close`, add nothing.
145
+ 5. If the vault service is unreachable, record the failed releases, say so, and still exit. A stop never hangs.
146
+
147
+ **The missing close.** A seat that exits without a `close` in time is a defect, never a clean close. The launcher records the defect, closes the seat itself with `close_kind: forced`, and keeps the window open so someone can see what happened. A seat that streams no typed events owes no `close`; the launcher closes it at once.
148
+
149
+ ### Inside a milestone seat: a sub-close per epic, one close per seat
150
+
151
+ One seat can run a whole milestone, epic by epic. Close-out then runs at two levels.
152
+
153
+ - **Per-epic sub-close (seat).** When an epic ends, the seat records WIP on that epic, settles that epic's claims and writes its summary. It sends no `final` and no seat `close`; it marks the end of the epic with an `epic_end` event and moves on to the next epic with fresh instructions. The window stays open.
154
+ - **Seat close (seat, once).** When the milestone is done or the seat must stop, the seat runs the full close-out once and sends one `close`.
155
+ - **The launcher reacts only to the seat close.** An epic sub-close never closes the window.
156
+
157
+ ### The `close` event
158
+
159
+ `close` follows `final` as the last line of the seat's stream. Fields:
160
+
161
+ - `close_kind` (required): `done` | `owner_gated` | `fleet_unavailable` | `budget` | `interrupted` | `crashed` | `incomplete` | `error` | `forced`
162
+ - `closed_by` (required): `seat` | `launcher`
163
+ - `scope`: `seat` | `epic` (default `seat`)
164
+ - `claims`: `{ submitted[], released[], failed[] }`
165
+ - `wip_recorded`: true or false
166
+ - `steps`: each close-out step with `ok`, `skipped` or `failed`
167
+ - `summary_struct`: `{ done[], left[], needs_owner, spend_usd, elapsed_s }`
168
+
169
+ ### Order note: WIP before submit
170
+
171
+ A seat records WIP before it submits, so the hand-off exists even if a submit fails. An interactive session may submit first and record WIP after. Both are fine; the seat keeps WIP first.
172
+
173
+ ## Reviewer responsibilities (human, separate pass)
174
+
175
+ 1. Read each review companion or change-log entry. Walk the acceptance criteria against the actual diff.
176
+ 2. Decide accept, edit or reject for every memory candidate. Materialize accepted ones as files under `specs/memory/<type>s/<slug>.md`, linked back to the parent spec.
177
+ 3. On **pass**: commit the diff, including any materialized memories and the status flip. The commit is the close action.
178
+ 4. On **reopen**: leave the spec `in_review`, document the gap, and the next agent session picks it up.