@zalom/plastic 2.0.0-alpha.2 → 2.0.0-alpha.21

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 (127) hide show
  1. package/agents/plastic-enforcer.md +3 -1
  2. package/agents/plastic-executor.md +9 -3
  3. package/bin/test +24 -4
  4. package/hooks/call-budget +4 -0
  5. package/hooks/hooks.json +24 -0
  6. package/hooks/message-display +134 -0
  7. package/hooks/statusline +4 -27
  8. package/package.json +2 -2
  9. package/scripts/agent-report +8 -2
  10. package/scripts/dashboard.rb +297 -18
  11. package/scripts/doctor.rb +652 -5
  12. package/scripts/end-intent +219 -0
  13. package/scripts/hook-call-budget +222 -0
  14. package/scripts/hook-capture +25 -113
  15. package/scripts/hook-message-display +81 -0
  16. package/scripts/hook-record +12 -4
  17. package/scripts/hook-session-start +45 -7
  18. package/scripts/index-projection +74 -0
  19. package/scripts/intent-screen +77 -0
  20. package/scripts/lib/action_graph_shim.rb +277 -0
  21. package/scripts/lib/arm.rb +26 -1
  22. package/scripts/lib/atomic_write.rb +31 -0
  23. package/scripts/lib/compact_instructions.rb +5 -5
  24. package/scripts/lib/core_integrity.rb +71 -0
  25. package/scripts/lib/dashboard_screen.rb +40 -0
  26. package/scripts/lib/day_summary.rb +7 -2
  27. package/scripts/lib/doctor_core.rb +102 -5
  28. package/scripts/lib/doctor_session_ledger.rb +52 -0
  29. package/scripts/lib/graph_edges.rb +137 -0
  30. package/scripts/lib/graph_file.rb +246 -0
  31. package/scripts/lib/graph_tree.rb +98 -0
  32. package/scripts/lib/guarded_append.rb +155 -0
  33. package/scripts/lib/hook_registry.rb +28 -2
  34. package/scripts/lib/hook_replay.rb +211 -0
  35. package/scripts/lib/index_projection.rb +201 -0
  36. package/scripts/lib/installer_core.rb +141 -6
  37. package/scripts/lib/intent_screen.rb +309 -0
  38. package/scripts/lib/intent_screen_ansi.rb +262 -0
  39. package/scripts/lib/message_display.rb +586 -0
  40. package/scripts/lib/meter_watch.rb +179 -0
  41. package/scripts/lib/node_file.rb +214 -0
  42. package/scripts/lib/node_ids.rb +99 -0
  43. package/scripts/lib/node_ledger.rb +377 -0
  44. package/scripts/lib/node_packet.rb +908 -0
  45. package/scripts/lib/node_return.rb +199 -0
  46. package/scripts/lib/node_worktree.rb +337 -0
  47. package/scripts/lib/outcome_report.rb +440 -0
  48. package/scripts/lib/packet_wrapper.rb +132 -0
  49. package/scripts/lib/ready_set.rb +462 -0
  50. package/scripts/lib/release_guard.rb +16 -0
  51. package/scripts/lib/report_screen.rb +1967 -0
  52. package/scripts/lib/roadmap_graph.rb +210 -0
  53. package/scripts/lib/roadmap_migration.rb +95 -0
  54. package/scripts/lib/roadmap_queue.rb +155 -5
  55. package/scripts/lib/roadmap_render.rb +150 -0
  56. package/scripts/lib/roadmap_savepoint.rb +62 -12
  57. package/scripts/lib/runner_absorb.rb +620 -0
  58. package/scripts/lib/runner_answer.rb +206 -0
  59. package/scripts/lib/runner_core.rb +194 -0
  60. package/scripts/lib/runner_dispatch.rb +506 -0
  61. package/scripts/lib/runner_policy.rb +173 -0
  62. package/scripts/lib/runner_proposals.rb +275 -0
  63. package/scripts/lib/runner_rewind.rb +201 -0
  64. package/scripts/lib/runner_sweep.rb +231 -0
  65. package/scripts/lib/savepoint.rb +149 -12
  66. package/scripts/lib/screen_paint.rb +555 -0
  67. package/scripts/lib/screens/dashboard.rb +20 -0
  68. package/scripts/lib/screens/plan.rb +18 -0
  69. package/scripts/lib/screens/roadmap.rb +15 -0
  70. package/scripts/lib/session_git.rb +49 -18
  71. package/scripts/lib/session_ledger.rb +128 -0
  72. package/scripts/lib/session_usage.rb +190 -0
  73. package/scripts/lib/verify_intent.rb +33 -0
  74. package/scripts/lib/work_graph_validator.rb +201 -0
  75. package/scripts/meter-watch +57 -0
  76. package/scripts/node-packet +92 -0
  77. package/scripts/node-transition +291 -0
  78. package/scripts/outcome-report +74 -0
  79. package/scripts/plastic-lock +8 -1
  80. package/scripts/read-config +3 -3
  81. package/scripts/ready-set +126 -0
  82. package/scripts/release-check +118 -0
  83. package/scripts/report-screen +281 -0
  84. package/scripts/roadmap-graph +119 -0
  85. package/scripts/roadmap-savepoint +7 -0
  86. package/scripts/runner +397 -0
  87. package/scripts/savepoint-note +69 -0
  88. package/scripts/session-usage +56 -0
  89. package/scripts/spawn-preamble +9 -2
  90. package/scripts/validate-work-graph +39 -0
  91. package/scripts/verify-intent +2 -1
  92. package/skills/auto/SKILL.md +41 -34
  93. package/skills/auto/references/human-report-contract.md +136 -54
  94. package/skills/conventions/references/locks-and-worktrees.md +12 -0
  95. package/skills/dashboard/SKILL.md +13 -2
  96. package/skills/dashboard/templates/dashboard-global.md +1 -1
  97. package/skills/dashboard/templates/dashboard-project.md +2 -2
  98. package/skills/doctor/SKILL.md +10 -4
  99. package/skills/intent-continuing/SKILL.md +51 -41
  100. package/skills/intent-continuing/references/board-fill.md +9 -0
  101. package/skills/intent-continuing/references/boarding-matrix.md +6 -5
  102. package/skills/intent-continuing/references/context-management.md +1 -1
  103. package/skills/intent-ending/SKILL.md +36 -16
  104. package/skills/intent-executing/SKILL.md +21 -5
  105. package/skills/intent-executing/implementer-prompt.md +6 -1
  106. package/skills/intent-speccing/SKILL.md +7 -4
  107. package/skills/releasing/SKILL.md +39 -0
  108. package/skills/releasing/references/promotion-and-tagging.md +10 -6
  109. package/skills/releasing/references/release-lines.md +1 -1
  110. package/skills/roadmap/SKILL.md +26 -0
  111. package/skills/roadmap/references/file-format.md +10 -0
  112. package/templates/config.yml +3 -3
  113. package/templates/dashboard-screen.md +22 -0
  114. package/templates/display-fixture.md +21 -0
  115. package/templates/graph.md +16 -0
  116. package/templates/intent-screen.md +17 -0
  117. package/templates/node-decision.md +11 -0
  118. package/templates/node-research.md +11 -0
  119. package/templates/node-verify.md +13 -0
  120. package/templates/node-work.md +22 -0
  121. package/templates/outcome.md +19 -1
  122. package/templates/report-plan.md +15 -0
  123. package/templates/report-roadmap-delivered.md +10 -0
  124. package/templates/report-roadmap-plan.md +9 -0
  125. package/templates/report-roadmap-state.md +9 -0
  126. package/templates/report-state.md +11 -0
  127. package/templates/roadmap.md +13 -0
@@ -5,7 +5,7 @@ description: >-
5
5
  where we left off", "where was I", "what should I work on", names a specific intent to
6
6
  resume (by id or description, or `--intent {id}`), or names a roadmap or delivery batch to
7
7
  resume (`--roadmap {slug}`, "where is the roadmap", "where did that batch land"). Presents
8
- state and resumes at the last delivered station; it never asks auto or guided, never boots
8
+ state and resumes at the last delivered stage; it never asks auto or guided, never boots
9
9
  (the SessionStart hook owns boot), and never drives work autonomously (plastic-auto does).
10
10
  Absorbs the former continuing, project-continuing, and roadmap-continuing skills and the
11
11
  read half of the former intent-starting skill (intent 304).
@@ -45,32 +45,29 @@ specific intent or roadmap named.").
45
45
 
46
46
  ## Project route: land on the board
47
47
 
48
- Land on the Markdown board through the `plastic-dashboard` skill; rendering belongs there.
49
- Run the data payload and fill the matching template:
50
- - project loaded: `ruby ~/.plastic/scripts/dashboard.rb project <slug> --data`
51
- - otherwise (the global fallback): `ruby ~/.plastic/scripts/dashboard.rb continue --data`
52
-
53
- Fill the template from `plastic-dashboard`'s `templates/` and present the filled Markdown in
54
- your reply, every time: tool-call stdout and hook context are invisible to the user. Read
55
- `references/board-fill.md` for the fill mechanics and the store-health line when filling the
56
- board. The board load runs the scoped store check (`doctor --store <scope>`); its result
57
- arrives in the payload as `store_health` and is shown as one line of data, never a blocker.
58
-
59
- Priority order on the board: active intents first, then project context (governing plus
60
- tactical intents in a registered project), then stale future intents for triage, then fresh
61
- future intents as next work. A future intent older than `stale_threshold_days` (default 3) is
62
- surfaced for triage without action: activate, abandon, or leave. Activating moves it to
48
+ Print `ruby ~/.plastic/scripts/dashboard.rb project <slug> --screen` (or `continue --screen`
49
+ for the global fallback) as the first characters of the reply: nothing before it, no fence, or
50
+ the hook cannot paint it (intent 331d/331f). It carries a title, six fields (Active, In
51
+ delivery, Delivered, Roadmap, Sessions, Changed), then the Where-we-are and Where-we-go-next
52
+ tables. The board load runs the scoped store check (`doctor --store <scope>`); its result
53
+ rides in the payload as `store_health` and prints as one line of data, never a blocker.
54
+
55
+ Priority order on the underlying data: active intents first, then project context (governing
56
+ plus tactical intents in a registered project), then stale future intents for triage, then
57
+ fresh future intents as next work. A future intent older than `stale_threshold_days` (default
58
+ 3) is surfaced for triage without action: activate, abandon, or leave. Activating moves it to
63
59
  `## Active` in `INDEX.md` and auto-commits. The board's ranked next-work order is computed by
64
60
  `dashboard.rb`; cite the rule names only (Effort, Value, Flags, Override, Caps) and read
65
61
  `plastic-dashboard`'s `references/classification.md` for their definitions.
66
62
 
67
63
  When the tier root (the directory holding `INDEX.md`) has a mid-flight roadmap
68
64
  (`ruby ~/.plastic/scripts/roadmap-next --roadmaps-dir <root>/roadmaps` reports a `state`
69
- other than `none`), say so in one line and offer the roadmap route; the board still presents
65
+ other than `none`), say so in one line and offer the roadmap route; the screen still presents
70
66
  project state and stops.
71
67
 
72
68
  Then stop: "here is the state, what next?". Do not start executing work. When the user names
73
- an intent, take the intent route.
69
+ an intent, take the intent route. Read `references/board-fill.md` only when the reader asks
70
+ for the deeper prose board (`plastic-dashboard`'s Markdown surface still exists for that ask).
74
71
 
75
72
  ## Intent route: resume one intent from its ledger
76
73
 
@@ -79,19 +76,20 @@ QMD-first when the intent is named by description: run
79
76
  authoritative intent file. The command is a no-op when QMD is absent; fall back to
80
77
  `INDEX.md`.
81
78
 
82
- If the intent is terminal (`## Completed` or `## Abandoned` in `INDEX.md`): report only.
83
- Summarize its `outcome.md` and ask what is next; never reopen it.
79
+ If the intent is terminal (`## Completed` or `## Abandoned` in `INDEX.md`): print the
80
+ intent screen (Status shows the terminal section, Next is empty), summarize its
81
+ `outcome.md`, and ask what is next; never reopen it.
84
82
 
85
83
  For a live intent's directory:
86
84
 
87
85
  1. **Read `savepoint.md` first.** It is a deterministic, append-only ledger, one line per
88
- event, newest at the bottom: `{utc-iso8601} {Stage} {milestone}`. Classify the station
86
+ event, newest at the bottom: `{utc-iso8601} {Stage} {milestone}`. Classify the stage
89
87
  from the last line alone (the table in `references/boarding-matrix.md`, read when
90
88
  classifying), then verify only that line's artifact is real (sentinel-aware:
91
89
  `Savepoint.stage_file_present?`). Do not re-probe every lifecycle file.
92
- 2. **Drift.** When the last line disagrees with the files on disk, rebuild the ledger from
90
+ 2. **Stale ledger.** When the last line disagrees with the files on disk, rebuild the ledger from
93
91
  disk and note the correction. A rebuilt ledger is the file-landing skeleton, which still
94
- pins the station:
92
+ pins the stage:
95
93
  ```bash
96
94
  ruby -r ~/.plastic/scripts/lib/savepoint -e 'Savepoint.rebuild_savepoint("<intent_dir>")'
97
95
  ```
@@ -99,21 +97,32 @@ For a live intent's directory:
99
97
  else the newest prior day) is the prior session's own account of where things stand; read
100
98
  it after the ledger, never instead of it.
101
99
  4. **Derive the next step:** the first unchecked item in `checklist.md` when it exists, else
102
- the next thing the station needs (see the matrix). The newest `## Insights` entry supplies
100
+ the next thing the stage needs (see the matrix). The newest `## Insights` entry supplies
103
101
  the human-readable context; an entry marked `(autonomous)` means an auto team was
104
102
  delivering it, so say so and offer to hand back to `plastic-auto`.
105
- 5. **Announce, then continue at that station:**
106
- ```
107
- Resuming intent [ID] - [name]
108
- Store: [global | project:<slug>]
109
- Station: [from the ledger's last line]
110
- Next step: [first unchecked checklist item | what the station needs]
111
- Context: [newest ## Insights entry | hand-off summary]
112
- Drift: [none | ledger rebuilt from disk]
113
- ```
114
- Then continue the work in the session's current mode. In auto mode the running team
115
- already holds the delivery lock; if a lock is held by a session that is gone, the
116
- `plastic-doctor` skill's lock section repairs or reclaims it.
103
+ 5. **Print the report screen as the first thing in the reply, then continue at that stage.**
104
+ The screen must open the message with nothing before it. On Claude Code, a fail-open
105
+ `MessageDisplay` hook recognizes a reply that opens this way and substitutes a styled ANSI
106
+ rendering for it there; the transcript and every other harness keep exactly this plain
107
+ form. For "where are we" on one named intent, run
108
+ `ruby ~/.plastic/scripts/report-screen state <intent_dir>` and print its output as it is:
109
+ the title, the field table, the `Changed` row, and the Steps table come from the record,
110
+ never by eye. For "where are we" with no intent named, run
111
+ `ruby ~/.plastic/scripts/report-screen session <tier_root> --session <this session's id>`
112
+ (intent 330; pass the id your harness gives you, or the screen widens to the whole day and
113
+ says so): it prints one
114
+ `delivered` screen per intent this session actually completed, oldest first, then the same
115
+ roster `report-screen state --all <store_root>` prints on its own - `state --all` stays the
116
+ right call when only the in-flight roster is wanted, with nothing delivered above it. Route
117
+ "why did X take so long" to `ruby ~/.plastic/scripts/report-screen delay <intent_dir>`
118
+ instead - every verb prints the same plain screen on any harness, painted only where the
119
+ harness supports it, with no branching on harness name. Under the `state` screen
120
+ write **What this means** as two to four bullets in plain words (what the intent is for,
121
+ what has landed, what is left, any defect named by step), then close with **needs input:**
122
+ naming the first open step. Then continue the work in the
123
+ session's current mode. In auto mode the running team already holds the delivery lock; if a
124
+ lock is held by a session that is gone, the `plastic-doctor` skill's lock section repairs or
125
+ reclaims it.
117
126
 
118
127
  ## Roadmap route: resume the mid-flight roadmap
119
128
 
@@ -127,10 +136,11 @@ For a live intent's directory:
127
136
  `delivering` or `blocked` entry wins, else the newest ledger or `## Log` timestamp.
128
137
  `roadmaps/<slug>.savepoint.md` is a derived signal read here, never a status field;
129
138
  `INDEX.md` stays the sole status writer.
130
- 2. **Present state:** the roadmap's `## Goal`, the current batch with each entry's mirrored
131
- status, the ledger's newest line beside the newest `## Log` line. Read
132
- `../plastic-conventions/references/roadmaps.md` for the file format and the status-mirror
133
- rule when a roadmap file needs interpreting.
139
+ 2. **Print state.** Print `ruby ~/.plastic/scripts/report-screen roadmap <roadmap.md> state` as
140
+ the first characters of the reply: nothing before it, no fence, or the hook cannot paint it.
141
+ It carries Goal, Progress, Frontier, Delivering, Next, and Changed, then the entries table -
142
+ never hand-typed. Read `../plastic-conventions/references/roadmaps.md` for the file format
143
+ and the status-mirror rule when a roadmap file needs interpreting.
134
144
  3. Then continue with the next dispatchable entry in the session's mode: direct work on it,
135
145
  or `plastic-auto` when the owner says auto. The coordinator that drives a batch appends
136
146
  to `roadmaps/<slug>.savepoint.md` at its dispatch, merge, park, and handoff points with
@@ -141,6 +151,6 @@ For a live intent's directory:
141
151
  | Trigger | Read |
142
152
  |---|---|
143
153
  | Filling the board on the project route | `references/board-fill.md` |
144
- | Classifying the station from the ledger's last line | `references/boarding-matrix.md` |
154
+ | Classifying the stage from the ledger's last line | `references/boarding-matrix.md` |
145
155
  | Explaining why one roadmap ranked above another | `references/liveness-ranking.md` |
146
156
  | Saving or restoring context across a long session, or debugging a resume | `references/context-management.md` |
@@ -41,3 +41,12 @@ The project route's default target is the project board. When no project is load
41
41
  case where this route is reached without a registered project in scope), fall back to the
42
42
  global board payload (`dashboard.rb continue --data`) rather than failing. This mirrors the
43
43
  router's D6 default: a bare "continue" always lands somewhere useful.
44
+
45
+ ## The screen surface (intent 331d)
46
+
47
+ `dashboard.rb project <slug> --screen` (or `continue --screen`) prints the identical state -
48
+ Active, In delivery, Delivered, Roadmap, Sessions, Changed, then the Where-we-are and
49
+ Where-we-go-next tables - as a screen with its own grammar instead of a filled Markdown
50
+ template. It replaces this fill mechanism once intent 331f wires the project route to print
51
+ it first, the way the intent route already prints the intent screen first today; until then,
52
+ this page's fill rules stay the route's own surface.
@@ -1,8 +1,8 @@
1
- # Boarding matrix: which station a resume lands at
1
+ # Boarding matrix: which stage a resume lands at
2
2
 
3
- The station is derived from `savepoint.md`'s last line plus the real artifacts on disk.
3
+ The stage is derived from `savepoint.md`'s last line plus the real artifacts on disk.
4
4
  Classify from the last line alone, then verify only that line's artifact is real
5
- (sentinel-aware). On drift, rebuild the ledger from disk and note it.
5
+ (sentinel-aware). When the ledger is stale, rebuild it from disk and note it.
6
6
 
7
7
  | savepoint last line | latest delivered | lands at | continue with |
8
8
  |---|---|---|---|
@@ -10,11 +10,12 @@ Classify from the last line alone, then verify only that line's artifact is real
10
10
  | `Why started` (spec still sentinel) | What | **Why** | continue the conversation; rulings land as insights |
11
11
  | `Why spec.md created` | Why | **How** | the action files, `plan.md`, `checklist.md` |
12
12
  | `How started` / `How plan.md created` | (How in progress) | **How** | finish `plan.md` and `checklist.md` |
13
- | `How checklist.md created` / `Exec started` | How | **Exec** | do the work, tick the checklist |
13
+ | `How checklist.md created` / `Exec started` | How | **Exec** | do the work, check off the checklist |
14
14
  | `Exec outcome.md created` | Exec | **ready to complete** | the ending procedure (`plastic-intent-ending`) |
15
15
  | `Done delivered` / `Done abandoned` | terminal | **report only** | immutable; ask what is next |
16
+ | A node or `Intent` transition line (`n1 running ...`, `Intent needs_decision ...`) | Exec | **Exec** | a graph delivery is in progress; read node status through `NodeLedger.status`, never re-derive it by eye |
16
17
 
17
- ## Per-station behaviour (what "continue" means)
18
+ ## Per-stage behaviour (what "continue" means)
18
19
 
19
20
  - **Why**: continue the conversation, or run the work directly when the request is already
20
21
  clear; every ruling is recorded as it lands.
@@ -19,7 +19,7 @@ step looks stale):
19
19
  (see `SKILL.md`'s `## Conditional Ledger-Resume` for the full state table).
20
20
  2. Confirm the artifact that line implies (`plan.md`, `checklist.md`, `outcome.md`, ...) is
21
21
  present and non-empty on disk.
22
- 3. If the two disagree, the ledger has drifted: rebuild it rather than hand-editing:
22
+ 3. If the two disagree, the ledger is stale: rebuild it rather than hand-editing:
23
23
  `ruby -r ~/.plastic/scripts/lib/savepoint -e 'Savepoint.rebuild_savepoint("<intent_dir>")'`
24
24
  4. Re-read the rebuilt last line and re-derive the next step from `checklist.md`'s first
25
25
  unchecked item.
@@ -51,21 +51,39 @@ on disk is what the record becomes, so before the call:
51
51
  reported gap that lands verbatim in the backfilled `## Follow-ups`.
52
52
  2. Confirm every acceptance criterion in spec.md is verifiable (tests pass,
53
53
  or the manual check described in its HOW line was actually run).
54
- 3. Decide what you have to say. A spec.md, plan.md, action file, or outcome.md
55
- left as the scaffold placeholder is written from the record by
56
- `scripts/end-intent` (the intent file's `## Intent`, `### Decisions`, and
57
- `## Insights`, the checklist, the diff on the intent's own worktree). A
58
- file you wrote, even under a still-present sentinel, is never touched.
59
- Write outcome.md yourself when the summary deserves more than the
60
- `--outcome-summary` line; otherwise let the backfill carry it.
54
+ 3. Decide what you have to say. For an intent with a `graph.md`, `outcome.md` is
55
+ GENERATED by `scripts/end-intent` itself, through `scripts/lib/outcome_report.rb`
56
+ (`scripts/outcome-report` is its standalone CLI, useful for checking the
57
+ generated text before the close): `## Delivered`, `## Verification`,
58
+ `## Graph diff`, and `## Findings` are read straight from `graph.md`, `nodes/`,
59
+ and the ledger every time, never hand-typed. `## Summary`, `## Needs you`, and
60
+ `## Follow-ups`, and every frontmatter key but `disposition`, are preserved
61
+ byte for byte when you author them and generated as plain facts otherwise, so
62
+ writing a summary yourself still works exactly as before. For an intent with
63
+ no `graph.md`, or when the generated text would be refused by the close's own
64
+ gates, a spec.md, plan.md, action file, or outcome.md left as the scaffold
65
+ placeholder is written from the record by `scripts/end-intent` (the intent
66
+ file's `## Intent`, `### Decisions`, and `## Insights`, the checklist, the
67
+ diff on the intent's own worktree). A file you wrote, even under a
68
+ still-present sentinel, is never touched.
61
69
 
62
70
  ### Step 1-5. Run `scripts/end-intent`
63
71
 
64
- Author outcome.md yourself when it deserves prose: copy `templates/outcome.md`,
65
- set the frontmatter to `disposition: delivered` or `disposition: abandoned`, and
66
- fill `## Summary`, `## Delivered`, `## Verification`, `## Follow-ups`. On
67
- abandon, `## Summary` states the abandonment reason and the trail (see Pivot
68
- below). A placeholder outcome.md is backfilled from the record instead, with the
72
+ Author outcome.md yourself when the summary deserves more prose than the generator's
73
+ plain facts: copy `templates/outcome.md`, set the frontmatter to `disposition: delivered`
74
+ or `disposition: abandoned`, and fill `## Summary`, `## Delivered`, `## Verification`,
75
+ `## Follow-ups`. `## Delivered` is a `| Row | What |` table: one row per thing delivered,
76
+ in plain wording a reader recognizes, not a method name or an implementation summary
77
+ (that detail belongs in `## Summary`). Each row's label must appear as a standalone token
78
+ in an action-file heading (or a node-file heading, for an intent whose graph replaces
79
+ actions/ with nodes/) that owns the matrix table (`### S1 - ...` or
80
+ `## n1 failure-mode matrix` with a table beneath it proves that row; a table-less
81
+ heading naming the label is skipped); that heading's matrix rows become the row's
82
+ Proven-by cell on `report-screen delivered`'s post-delivery screen. `## Needs you` is
83
+ the literal None or a `| N | What | Why |` table. On abandon, `## Summary` states the
84
+ abandonment reason and the trail (see Pivot below). An intent with a `graph.md` and no
85
+ hand-written outcome.md gets one generated instead (Step 0.3 above); a placeholder
86
+ outcome.md on an intent with no `graph.md` is backfilled from the record, with the
69
87
  close's disposition and the `--outcome-summary` line as its summary. Also author
70
88
  the rich INDEX entry note now (a short line in the store's existing
71
89
  Completed/Abandoned convention: mode, what shipped or why it was
@@ -138,11 +156,13 @@ ruby ~/.plastic/scripts/qmd-sync reindex --store <store-root> --async
138
156
  No-op when QMD is absent. Runs in the background so it never blocks the
139
157
  turn.
140
158
 
141
- ### Step 7. EM-to-CTO report
159
+ ### Step 7. Print `delivered`
142
160
 
143
- Brief the human like an engineering manager to a CTO: impact and risk first,
144
- in plain language, the decision left to them (merge, release, or accept).
145
- See `outcome.md` for the details; do not restate it verbatim.
161
+ Print `ruby ~/.plastic/scripts/report-screen delivered <intent_dir>` as the first characters
162
+ of the reply: nothing before it, no fence, or the hook cannot paint it. Asked, Delivered (with
163
+ its Proven-by column), Evidence, and Needs you come straight from the record - the EM-to-CTO
164
+ report, impact and risk first, in plain language, with the decision left to the human (merge,
165
+ release, or accept). See `outcome.md` for the details; do not restate it verbatim.
146
166
 
147
167
  ## Abandoned is the same procedure
148
168
 
@@ -44,6 +44,10 @@ Dispatches subagents to do the work. The controller never implements. It dispatc
44
44
 
45
45
  The post-execution review in Step 3 runs by risk (the rule lives in the auto skill). When it runs, the reviewer is a separate agent with fresh context, never the maker. The plan itself is reviewed before code by the adversarial plan reviewer (`plan-reviewer-prompt.md`), dispatched by the lead at How.
46
46
 
47
+ ### Graph dispatch: the paste
48
+
49
+ When the plan is a graph (`nodes/*.md`, not `plan.md` plus action files), the dispatch step is the paste, not a lead's hand-typed brief. `runner step` computes readiness, applies policy, and prints a spawn block per dispatched node - agent, model, packet path, the one test command, the call cap - fenced in its own stdout. Copy each block into the Agent tool as its own dispatch, verbatim; the runner itself never spawns an agent (327 D42).
50
+
47
51
  ### Inline (Fallback)
48
52
  Executes tasks sequentially in the current session. Use when subagents aren't available or user explicitly requests inline mode.
49
53
 
@@ -61,6 +65,10 @@ Run Step 0 (Sync Worktree First) before this step.
61
65
 
62
66
  Dispatch ONE executor subagent and give it the whole delivery: every task's full text from `plan.md` (pasted in, never a file reference), every action file with its failure-mode matrix, the checklist items it must tick, the project context from CLAUDE.md, the active intent context from `{ID}--{slug}.md`, and the worktree path. In auto mode this is the `plastic-executor` agent; elsewhere use the `implementer-prompt.md` template. The executor writes the matrix's tests and commits them red, implements the consolidated action in order, ticks each item as it lands (see `## Tick-as-you-land`), and drives the test suite green.
63
67
 
68
+ After each commit lands (the red commit and every commit after it), append a `Commit` line to the savepoint ledger: `ruby ~/.plastic/scripts/savepoint-note <intent_dir> --kind Commit --text "<sha> <what it proves>"` (intent 317, D17). This is what feeds `report-screen delay`; a commit with no line is a gap the delay report cannot explain.
69
+
70
+ Print `ruby ~/.plastic/scripts/report-screen state <intent_dir> --changed "<what just landed>"` as the first characters of the reply, nothing before it, no fence, right after the red commit and again once the suite goes green (intent 331f).
71
+
64
72
  Read its response by code:
65
73
  - DONE or DONE_WITH_CONCERNS → proceed to Step 3.
66
74
  - NEEDS_CONTEXT → provide the missing context, re-dispatch the executor.
@@ -69,6 +77,10 @@ Read its response by code:
69
77
  ### Step 3: Review by Risk
70
78
  Apply the auto skill's risk rule to the executor's return and the diff: a matrix row no test could prove, a diff touching a hook, the lock, the worktree code, the installer, or a release file, a DONE_WITH_CONCERNS or a deviation from the matrix, or an owner-facing surface no test pins. When a rule fires, dispatch the post-execution reviewer with `code-quality-reviewer-prompt.md` (a separate agent with fresh context, never the maker); if it returns changes, re-dispatch the executor to fix them, then run the suite once more. When no rule fires, the green suite is the review.
71
79
 
80
+ Whenever a review verdict returns - the plan review before code, or the post-execution review above - the lead appends a `Review` line: `ruby ~/.plastic/scripts/savepoint-note <intent_dir> --kind Review --text "<verdict, what changed>"` (intent 317, D17). This is the other half of what `report-screen delay` reads.
81
+
82
+ **The D19 heading convention.** An action file's `## Delivered` row (in `outcome.md`) is proven by the first `actions/ACTION_N.md` OR `nodes/*.md` heading that carries that row's label as a standalone token AND owns the matrix table (322 D1r, 334 D10r) - `### Row A -` with a table beneath it proves row A, `### S1 -` proves row S1, `## n1 failure-mode matrix` proves row n1; a heading that only names the label, with no table under it, is skipped. Readers check `actions/` first, then `nodes/` (334 D15r). Write action-file or node-file section headings so the label they prove is unambiguous (never a substring another label could also match, like `A` inside `AB`); `report-screen delivered`'s Proven-by column renders `not recorded` when no heading owns a matching table and no matrix row cell carries the label either.
83
+
72
84
  ### Step 4: Update Intent and Complete
73
85
  Capture observations in `## Insights`. When ALL checklist items are checked:
74
86
 
@@ -102,11 +114,15 @@ Capture observations in `## Insights`. When ALL checklist items are checked:
102
114
 
103
115
  ## Tick-as-you-land
104
116
 
105
- As each task lands, in the same edit: move its checklist item from `## In
106
- Progress` to `## Completed` in `checklist.md`, and add one `## Session Log`
107
- row (Date, Items Completed, Notes). Do not batch several tasks' worth of
108
- checklist updates into one later edit; tick the moment the task is verified,
109
- before moving to the next task.
117
+ A tick is two edits, made together: mark the item's box `[x]`, and move its
118
+ checklist item from `## In Progress` to `## Completed` in `checklist.md`;
119
+ then add one `## Session Log` row (Date, Items Completed, Notes). The box is
120
+ the half the state screen's Progress bar reads: `IntentScreen::ITEM_RE` and
121
+ `progress_fields` count `[x]`, not which section the line sits in, so a line
122
+ moved to `## Completed` with its box left unmarked still reads as zero
123
+ progress. Do not batch several tasks' worth of checklist updates into one
124
+ later edit; tick the moment the task is verified, before moving to the next
125
+ task.
110
126
 
111
127
  ## Verify before every owner review
112
128
 
@@ -20,12 +20,17 @@ You are implementing a specific task from a plan. You have been given the full t
20
20
  2. Implement exactly what the task specifies — nothing more, nothing less.
21
21
  3. Write tests first when the task includes test steps (TDD).
22
22
  4. Follow the file paths specified in the task exactly.
23
- 5. Commit after each logical unit of work.
23
+ 5. Commit after each logical unit of work, and in the same step tick the checklist item that
24
+ unit lands: mark its box `[x]` and move the line to `## Completed`, then append the
25
+ savepoint `Commit` line
26
+ (`scripts/savepoint-note <intent_dir> --kind Commit --text "<sha> <what it proves>"`). A
27
+ commit without its tick is incomplete.
24
28
  6. When done, self-review against this checklist:
25
29
  - [ ] All steps in the task are completed
26
30
  - [ ] Tests pass
27
31
  - [ ] Code is clean and follows project conventions
28
32
  - [ ] No unrelated changes
33
+ - [ ] Every landed unit's checklist item is ticked
29
34
 
30
35
  ## Report Format
31
36
 
@@ -111,10 +111,13 @@ When the rulings are enough to build from:
111
111
  rulings say more than the record already does.
112
112
  3. **Self-verify.** Read `references/self-verify-checklist.md` before presenting; fix any
113
113
  failing check and re-verify from the top.
114
- 4. **Present and hand off.** Present `spec.md` and the action files. Then offer the routes:
115
- run it now inline when the work is small enough for direct mode; hand to `plastic-auto`
116
- when the owner says auto and the checklist above passes (all decisions resolved, scope
117
- bounded, dependencies named, success criteria defined); or keep thinking.
114
+ 4. **Present and hand off.** Print `ruby ~/.plastic/scripts/report-screen plan <intent_dir>` as
115
+ the first characters of the reply: nothing before it, no fence, or the hook cannot paint it.
116
+ It carries Asked, Decisions, Steps, Mode, Reviewer, then the Steps and Risks tables, filled
117
+ from `spec.md` and the action files just written, never restated by eye. Then offer the
118
+ routes: run it now inline when the work is small enough for direct mode; hand to
119
+ `plastic-auto` when the owner says auto and the checklist above passes (all decisions
120
+ resolved, scope bounded, dependencies named, success criteria defined); or keep thinking.
118
121
 
119
122
  Report, in this order: which files were written (`spec.md` new or rewritten, the action
120
123
  files), the count of acceptance criteria, which `## Insights` rulings superseded an earlier
@@ -206,6 +206,45 @@ The dist-tag is derived from the version string in `package.json`:
206
206
  - Contains `-beta` → `--tag beta`
207
207
  - No pre-release suffix → no `--tag` flag (publishes to `latest`)
208
208
 
209
+ #### `npm_publish_workflow`
210
+
211
+ The tag pushed in step 6 starts the project's publish workflow (GitHub Actions, keyed on the
212
+ workflow file `publish.yml`) instead of a local `npm publish`. The workflow runs with a
213
+ short-lived, per-run OIDC credential, so no npm token exists in this session or on this
214
+ machine.
215
+
216
+ 1. **Confirm a run exists for the tag.** A tag cut from a ref that does not carry the
217
+ workflow starts no run at all, and silence would read as success:
218
+
219
+ ```bash
220
+ gh run list --workflow publish.yml --limit 5
221
+ ```
222
+
223
+ 2. **Follow the run.**
224
+
225
+ ```bash
226
+ gh run watch <run-id>
227
+ ```
228
+
229
+ 3. **Verify the registry, not just the run.** The release is not done until the new version
230
+ shows up on the expected channel:
231
+
232
+ ```bash
233
+ npm view <package> dist-tags
234
+ ```
235
+
236
+ The dist-tag is derived from the version string in `package.json`, the same rule
237
+ `ReleaseGuard.dist_tag` implements:
238
+
239
+ | Version contains | dist-tag |
240
+ | --- | --- |
241
+ | `-alpha` | `alpha` |
242
+ | `-beta` | `beta` |
243
+ | no pre-release suffix | `latest` |
244
+
245
+ Do not run `npm whoami` on this path. npm documents that `whoami` does not reflect OIDC
246
+ authentication, so on a workflow-published project it can only mislead.
247
+
209
248
  #### Other values
210
249
 
211
250
  If `on_green` contains an action not listed above, log it:
@@ -34,18 +34,22 @@ cleared is a no-op.
34
34
  ## Promotion
35
35
 
36
36
  Promotion is not a CLI flag; there is no `--promote` command. It is a set of steps the
37
- agent performs during the releasing workflow, reusing the normal release mechanics
38
- (version bump, tag, `npm publish` with the channel's dist-tag, GitHub release):
37
+ agent performs during the releasing workflow, reusing the normal release mechanics (version
38
+ bump, tag, GitHub release). For a project on the `npm_publish_workflow` post-push action,
39
+ the tag push itself starts the publish; there is no local publish command to run.
39
40
 
40
41
  ```bash
41
- # Promote alpha → beta: set version files from -alpha.N to -beta.1, commit, tag, then
42
- npm publish --access public --tag beta
42
+ # Promote alpha → beta: set version files from -alpha.N to -beta.1, commit, tag, push.
43
+ # The publish workflow reads the new version and publishes to the beta dist-tag.
43
44
 
44
45
  # Promote beta → stable: strip the pre-release suffix (e.g., 1.0.0-beta.3 → 1.0.0),
45
- # commit, tag, then
46
- npm publish --access public # no --tag flag publishes to latest
46
+ # commit, tag, push. The publish workflow reads the new version and publishes to latest.
47
47
  ```
48
48
 
49
+ A project still on the `npm_publish` action (publishing locally from the session) runs
50
+ `npm publish --access public --tag <channel>` at this point instead, per that action's own
51
+ section in SKILL.md.
52
+
49
53
  **Promotion rules:**
50
54
  - Linear only: alpha → beta → stable. Cannot skip channels.
51
55
  - Version files are bumped and committed as in a normal release.
@@ -78,7 +78,7 @@ re-deriving this decision.
78
78
  of 1.1.0, versioned `1.2.0-beta.1` (`c48601a`). There is nothing left to execute on the git side;
79
79
  this playbook describes what happens next, not a pending action.
80
80
 
81
- **Preconditions**, both required before any npm publish of `1.2.0-beta.1`:
81
+ **Preconditions**, both required before any publish of `1.2.0-beta.1`:
82
82
 
83
83
  - (a) One documentation pass over beta-line skills and docs for the hybrid savepoint contract:
84
84
  on beta, only the terminal Done bookend still writes a live `savepoint.md`; every other
@@ -43,10 +43,36 @@ See `references/file-format.md` for the exact entry-line shape, status vocabular
43
43
  format, and a worked example. See `references/operations.md` for step-by-step mechanics of each
44
44
  verb above.
45
45
 
46
+ ## Graph (intent 337)
47
+
48
+ A roadmap may carry an optional `## Graph` section - the same `needs` edge grammar as an
49
+ intent's own `graph.md` (`- <id> needs <id> <id>`, or `- <id> needs nothing` for a root). When
50
+ present, batches are computed from it (`roadmap-graph check`/`render`), not hand-ordered; the
51
+ template scaffolds a fenced example so a new roadmap starts with the section already in place.
52
+ Three verbs, all `--dry-run`-able:
53
+
54
+ | Verb | What it does |
55
+ |------|--------------|
56
+ | `roadmap-graph check <roadmap.md>` | Prints the computed batches, the ready set, and any dangling id (a graph names it, no batch lists it); exits 1 on a cyclic graph or a dangling id. |
57
+ | `roadmap-graph render <roadmap.md>` | Writes `## Tree` (a box-drawing render of the graph) and regroups the batch/wave section from the computed batches, entry lines carried over verbatim. |
58
+ | `roadmap-graph migrate <roadmap.md>` | Derives a conservative `## Graph` for a graphless roadmap from its existing batch order (batch N needs every entry of batch N-1); never overwrites an existing graph. |
59
+
60
+ A roadmap with no `## Graph` section keeps working exactly as before (wave-order dispatch); the
61
+ graph is additive, never required.
62
+
46
63
  Read `../plastic-conventions/references/roadmaps.md` for the roadmap file format, batch
47
64
  semantics, and the status-mirror rule that this skill's own file-format reference builds on. This
48
65
  path resolves relative to this skill's own installed directory.
49
66
 
67
+ ## Reports (intent 331f)
68
+
69
+ Each verb prints its report screen as the first characters of the reply: nothing before it, no
70
+ fence, or the hook cannot paint it.
71
+
72
+ - Create prints `ruby ~/.plastic/scripts/report-screen roadmap <roadmap.md> plan`.
73
+ - Read / consume prints `ruby ~/.plastic/scripts/report-screen roadmap <roadmap.md> state`.
74
+ - Close / archive prints `ruby ~/.plastic/scripts/report-screen roadmap <roadmap.md> delivered`.
75
+
50
76
  ## Notes
51
77
 
52
78
  - File location and the four-section shape are identical across tiers; do not invent a different
@@ -96,6 +96,16 @@ The ledger is derived and rebuildable (`ruby ~/.plastic/scripts/roadmap-savepoin
96
96
  roadmaps/{slug}.md`, reconstructing it from `## Log`), never a status source: `INDEX.md` stays the
97
97
  single writer of intent status, exactly as for the roadmap file itself.
98
98
 
99
+ ## Screens read this format (intent 331c)
100
+
101
+ `report-screen roadmap <roadmap.md> plan|state|delivered` reads exactly the shapes above and
102
+ nothing else: `## Goal`'s first sentence, the `## Batches` (or legacy `## Waves`) grouping and its
103
+ entries (through `RoadmapQueue`'s own reconciled reader - INDEX still wins), and the events from
104
+ the savepoint ledger, falling back to `## Log` classified through the same keyword vocabulary when
105
+ no ledger file exists (an archived roadmap moved before intent 134 shipped, `manual-first.md`
106
+ among them). A screen never invents a status, a time, or a merge sha the file, `INDEX.md`, or the
107
+ ledger did not already carry - the same `not recorded` floor the intent screens use.
108
+
99
109
  ## Worked example
100
110
 
101
111
  ```
@@ -2,11 +2,11 @@ version: 3
2
2
  project_roots:
3
3
  - ~/.plastic/projects
4
4
  stale_threshold_days: 3
5
- # When to compact. Absolute token counts for a 1M window (35 and 50 percent), not
5
+ # When to compact. Absolute token counts for a 1M window (15 and 25 percent), not
6
6
  # percentages: models are reliable only to roughly 50 to 65 percent of advertised
7
7
  # context, so a percentage that is right at 200k floats to an untested size at 1M.
8
- context_offer_tokens: 350000
9
- context_insist_tokens: 500000
8
+ context_offer_tokens: 150000
9
+ context_insist_tokens: 250000
10
10
  execution_mode: subagent-driven
11
11
  hash_length: 6
12
12
  hash_algorithm: sha256-base36
@@ -0,0 +1,22 @@
1
+ ## ▶ {{scope}} · dashboard
2
+
3
+ | | | |
4
+ | --- | --- | --- |
5
+ | **Active** | {{active}} | intents |
6
+ | **In delivery** | {{in_delivery}} | with a fresh lock |
7
+ | **Delivered** | {{delivered}} | in the last 7 days |
8
+ | **Roadmap** | {{roadmap}} | frontier batch |
9
+ | **Sessions** | {{sessions}} | alive |
10
+ | **Changed** | {{changed}} | newest savepoint |
11
+
12
+ **Where we are**
13
+
14
+ | Graph ID | Intent | Stage | Progress | Lead |
15
+ | --- | --- | --- | --- | --- |
16
+ {{where_we_are.rows}}
17
+
18
+ **Where we go next**
19
+
20
+ | Rank | Graph ID | Intent | Reason |
21
+ | --- | --- | --- | --- |
22
+ {{where_we_go_next.rows}}
@@ -0,0 +1,21 @@
1
+ <!-- Doctor's display self-test fixture (intent 331e). Replayed through the
2
+ installed MessageDisplay hook by `display_hook_paints` to prove painting
3
+ still works; this is NOT a report-screen scaffold (no {{...}} mustache
4
+ placeholders) and ships no data of its own. -->
5
+
6
+ ## ▶ 331e · Doctor display check
7
+
8
+ | | | |
9
+ | --- | --- | --- |
10
+ | **Store** | project:plastic | the plastic project store |
11
+ | **Status** | Active | listed under ## Active in INDEX.md |
12
+ | **Stage** | Exec | What, Why, How, Exec delivered; the work is open |
13
+ | **Progress** | ██████████░░░░░░░░░░ 3 / 6 | 3 steps open |
14
+
15
+ **Steps**
16
+
17
+ | Step | Status | What |
18
+ | --- | --- | --- |
19
+ | S1 | done | Tests red |
20
+ | S2 | done | check_display_registration in doctor_core.rb |
21
+ | S3 | open | The three full-run checks in doctor.rb |
@@ -0,0 +1,16 @@
1
+ # Graph: <intent name>
2
+
3
+ ## Goal
4
+ <What this intent's graph delivers once every node reaches done.>
5
+
6
+ ## Decisions
7
+ - D1 <first ruling made while building this graph>
8
+
9
+ ## Graph
10
+ Edges, `needs` only; the head needs the tail done. The literal target `nothing` declares a root.
11
+ - n1 needs nothing
12
+
13
+ ## Status
14
+ | Node | State | Detail |
15
+ | --- | --- | --- |
16
+ | n1 | planned | |
@@ -0,0 +1,17 @@
1
+ ## ▶ {{id}} · {{name}}
2
+
3
+ | | | |
4
+ | --- | --- | --- |
5
+ | **Store** | {{store}} | {{store.note}} |
6
+ | **Status** | {{status}} | {{status.note}} |
7
+ | **Stage** | {{stage}} | {{stage.note}} |
8
+ | **Savepoint** | {{savepoint}} | {{savepoint.note}} |
9
+ | **Progress** | {{progress.bar}} {{progress.done}} / {{progress.total}} | {{progress.note}} |
10
+ | **Next** | {{next}} | {{next.note}} |
11
+ | **Insight** | {{insight}} | {{insight.note}} |
12
+
13
+ **Steps**
14
+
15
+ | Step | Status | Detail |
16
+ | --- | --- | --- |
17
+ {{steps.rows}}