@zalom/plastic 1.14.0 → 2.0.0-alpha.1

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 (190) hide show
  1. package/PLASTIC.md +101 -294
  2. package/README.md +5 -6
  3. package/agents/plastic-advisor.md +18 -17
  4. package/agents/plastic-enforcer.md +57 -69
  5. package/agents/plastic-executor.md +34 -20
  6. package/agents/plastic-faux-advisor.md +18 -18
  7. package/config_asks.yml +38 -0
  8. package/hooks/capture +4 -0
  9. package/hooks/check-update +12 -3
  10. package/hooks/close +5 -0
  11. package/hooks/hooks.json +9 -49
  12. package/hooks/record +4 -0
  13. package/package.json +3 -2
  14. package/scripts/agent-report +8 -9
  15. package/scripts/append-ledger +195 -0
  16. package/scripts/codex-hook +101 -95
  17. package/scripts/dashboard.rb +4 -4
  18. package/scripts/doctor.rb +106 -43
  19. package/scripts/end-intent +77 -76
  20. package/scripts/exec-worktree +11 -20
  21. package/scripts/file-session-intent +61 -0
  22. package/scripts/hook-capture +242 -0
  23. package/scripts/hook-close +34 -0
  24. package/scripts/hook-record +149 -0
  25. package/scripts/hook-session-start +95 -12
  26. package/scripts/install.rb +8 -6
  27. package/scripts/lib/agent_models.rb +1 -7
  28. package/scripts/lib/arm.rb +283 -0
  29. package/scripts/lib/backfill_intent.rb +316 -0
  30. package/scripts/lib/bridge.rb +24 -1597
  31. package/scripts/lib/doctor_core.rb +17 -88
  32. package/scripts/lib/doctor_session_ledger.rb +106 -0
  33. package/scripts/lib/exec_worktree.rb +14 -60
  34. package/scripts/lib/harness_text.rb +5 -4
  35. package/scripts/lib/hook_registry.rb +44 -107
  36. package/scripts/lib/insights.rb +3 -4
  37. package/scripts/lib/installer_core.rb +19 -30
  38. package/scripts/lib/lock.rb +6 -26
  39. package/scripts/lib/outcome_guard.rb +7 -5
  40. package/scripts/lib/project_validator.rb +30 -1
  41. package/scripts/lib/roadmap_queue.rb +3 -3
  42. package/scripts/lib/roadmap_savepoint.rb +1 -1
  43. package/scripts/lib/rule_catalog.rb +6 -3
  44. package/scripts/lib/savepoint.rb +320 -0
  45. package/scripts/lib/scaffold_intent.rb +13 -179
  46. package/scripts/lib/session_backfill.rb +184 -0
  47. package/scripts/lib/session_close.rb +84 -0
  48. package/scripts/lib/session_git.rb +469 -0
  49. package/scripts/lib/session_ledger.rb +497 -0
  50. package/scripts/lib/store_discovery.rb +1 -1
  51. package/scripts/lib/store_provisioning.rb +1 -1
  52. package/scripts/maintenance-run +7 -7
  53. package/scripts/new-intent +63 -4
  54. package/scripts/plastic-lock +94 -41
  55. package/scripts/promote-session-item +150 -0
  56. package/scripts/rebuild-graph +1 -1
  57. package/scripts/roadmap-next +2 -2
  58. package/scripts/rollback.rb +42 -3
  59. package/scripts/scaffold-intent +37 -63
  60. package/scripts/session-commit +116 -0
  61. package/scripts/spawn-preamble +5 -5
  62. package/scripts/update.rb +7 -3
  63. package/skills/agent-advisor/SKILL.md +3 -3
  64. package/skills/agent-advisor/references/advisor-protocol.md +20 -20
  65. package/skills/auto/SKILL.md +218 -317
  66. package/skills/auto/evals/evals.json +10 -10
  67. package/skills/auto/references/agent-architecture.md +102 -90
  68. package/skills/auto/references/agent-report-contract.md +4 -21
  69. package/skills/auto/references/end-tail.md +47 -53
  70. package/skills/auto/references/human-report-contract.md +8 -8
  71. package/skills/conventions/SKILL.md +1 -3
  72. package/skills/conventions/references/lifecycle-and-savepoints.md +35 -1
  73. package/skills/conventions/references/locks-and-worktrees.md +47 -55
  74. package/skills/conventions/references/maintenance-and-revisions.md +12 -12
  75. package/skills/dashboard/SKILL.md +1 -1
  76. package/skills/direct/SKILL.md +66 -0
  77. package/skills/direct/references/request-signals.md +59 -0
  78. package/skills/doctor/SKILL.md +58 -11
  79. package/skills/doctor/report.md +3 -1
  80. package/skills/install/SKILL.md +11 -9
  81. package/skills/intent-continuing/SKILL.md +131 -89
  82. package/skills/intent-continuing/references/boarding-matrix.md +34 -0
  83. package/skills/intent-continuing/references/context-management.md +2 -2
  84. package/skills/intent-creating/SKILL.md +2 -2
  85. package/skills/intent-creating/references/lifecycle.md +1 -1
  86. package/skills/intent-ending/SKILL.md +28 -37
  87. package/skills/intent-ending/evals/evals.json +4 -4
  88. package/skills/intent-executing/SKILL.md +12 -49
  89. package/skills/intent-executing/plan-reviewer-prompt.md +39 -0
  90. package/skills/intent-speccing/SKILL.md +108 -51
  91. package/skills/intent-speccing/evals/evals.json +5 -5
  92. package/skills/intent-speccing/references/per-section-fill-rules.md +4 -4
  93. package/skills/intent-speccing/references/self-verify-checklist.md +1 -2
  94. package/skills/project-creating/SKILL.md +1 -1
  95. package/skills/releasing/SKILL.md +7 -8
  96. package/skills/tutorial/SKILL.md +2 -2
  97. package/skills/tutorial/references/track-1-guided.md +16 -18
  98. package/skills/tutorial/references/track-2-auto.md +12 -13
  99. package/skills/tutorial/references/track-3-projects-and-roadmaps.md +2 -2
  100. package/templates/agents.md +4 -7
  101. package/templates/project.yml +7 -0
  102. package/templates/roadmap.md +1 -1
  103. package/templates/savepoint.md +2 -2
  104. package/templates/session-intent.md +29 -0
  105. package/agents/plastic-brainstorming.md +0 -48
  106. package/agents/plastic-future-intent-researcher.md +0 -35
  107. package/agents/plastic-intent-curator.md +0 -47
  108. package/agents/plastic-intent-discovery.md +0 -43
  109. package/agents/plastic-planner.md +0 -56
  110. package/agents/plastic-spec-specialist.md +0 -53
  111. package/hooks/auto-arm +0 -5
  112. package/hooks/bash-gate +0 -3
  113. package/hooks/continue +0 -31
  114. package/hooks/edit-gates +0 -3
  115. package/hooks/future-intent-check +0 -25
  116. package/hooks/gate-check +0 -12
  117. package/hooks/power-tools +0 -8
  118. package/scripts/hook-auto-arm +0 -51
  119. package/scripts/hook-bash-gate +0 -78
  120. package/scripts/hook-code-gate +0 -38
  121. package/scripts/hook-continue +0 -48
  122. package/scripts/hook-create-gate +0 -51
  123. package/scripts/hook-edit-gates +0 -58
  124. package/scripts/hook-future-intent-check +0 -90
  125. package/scripts/hook-gate-check +0 -169
  126. package/scripts/hook-links-gate +0 -54
  127. package/scripts/hook-lock-gate +0 -47
  128. package/scripts/hook-power-tools +0 -38
  129. package/scripts/hook-savepoint-pre +0 -32
  130. package/scripts/lib/codex_edit_gates.rb +0 -138
  131. package/scripts/lib/edit_gates.rb +0 -398
  132. package/scripts/lib/links_gate.rb +0 -140
  133. package/scripts/lib/qmd_hook.rb +0 -41
  134. package/scripts/lib/spec_header.rb +0 -83
  135. package/scripts/lib/start_intent.rb +0 -296
  136. package/scripts/start-intent +0 -89
  137. package/skills/_active-intent-gate.md +0 -26
  138. package/skills/auto/references/tiers.md +0 -100
  139. package/skills/continuing/SKILL.md +0 -34
  140. package/skills/continuing/evals/evals.json +0 -91
  141. package/skills/conventions/references/gates-and-enforcement.md +0 -53
  142. package/skills/conventions/references/tiers-and-dispatch.md +0 -135
  143. package/skills/doctor/references/gates-stuck-detection.md +0 -43
  144. package/skills/intent-brainstorming/SKILL.md +0 -118
  145. package/skills/intent-brainstorming/evals/evals.json +0 -67
  146. package/skills/intent-continuing/evals/evals.json +0 -145
  147. package/skills/intent-discovering/SKILL.md +0 -56
  148. package/skills/intent-grilling/SKILL.md +0 -108
  149. package/skills/intent-linking/SKILL.md +0 -128
  150. package/skills/intent-linking/evals/evals.json +0 -22
  151. package/skills/intent-linking/references/zettelkasten.md +0 -45
  152. package/skills/intent-locking/SKILL.md +0 -64
  153. package/skills/intent-planning/SKILL.md +0 -145
  154. package/skills/intent-planning/evals/evals.json +0 -81
  155. package/skills/intent-planning/references/plan-format.md +0 -130
  156. package/skills/intent-researching/SKILL.md +0 -123
  157. package/skills/intent-researching/evals/evals.json +0 -22
  158. package/skills/intent-savepoint/SKILL.md +0 -83
  159. package/skills/intent-savepoint/references/context-management.md +0 -32
  160. package/skills/intent-starting/SKILL.md +0 -151
  161. package/skills/intent-starting/evals/evals.json +0 -117
  162. package/skills/intent-starting/references/boarding-matrix.md +0 -35
  163. package/skills/project-continuing/SKILL.md +0 -119
  164. package/skills/project-continuing/evals/evals.json +0 -100
  165. package/skills/roadmap-continuing/SKILL.md +0 -89
  166. package/skills/roadmap-continuing/evals/evals.json +0 -82
  167. package/skills/skill-creating/SKILL.md +0 -75
  168. package/skills/skill-creating/evals/evals.json +0 -108
  169. package/skills/skill-creating/references/agents.md +0 -168
  170. package/skills/skill-creating/references/defaults-first.md +0 -23
  171. package/skills/skill-creating/references/evals.md +0 -41
  172. package/skills/skill-creating/references/hooks.md +0 -251
  173. package/skills/skill-creating/references/progressive-disclosure.md +0 -176
  174. package/skills/skill-creating/references/scripts.md +0 -166
  175. package/skills/skill-creating/references/skills.md +0 -169
  176. package/skills/skill-creating/scripts/scaffold.rb +0 -313
  177. package/skills/skill-evaluating/SKILL.md +0 -141
  178. package/skills/skill-evaluating/assets/eval-template.json +0 -12
  179. package/skills/skill-evaluating/evals/evals.json +0 -75
  180. package/skills/skill-evaluating/references/convention-checks.md +0 -76
  181. package/skills/skill-evaluating/references/eval-methodology.md +0 -154
  182. package/skills/store-curating/SKILL.md +0 -64
  183. package/skills/store-curating/evals/evals.json +0 -38
  184. package/skills/store-indexing/SKILL.md +0 -93
  185. package/skills/store-indexing/evals/evals.json +0 -22
  186. package/skills/store-indexing/references/zettelkasten-linking.md +0 -32
  187. package/skills/store-provisioning/SKILL.md +0 -55
  188. /package/skills/{project-continuing → intent-continuing}/references/board-fill.md +0 -0
  189. /package/skills/{roadmap-continuing → intent-continuing}/references/liveness-ranking.md +0 -0
  190. /package/skills/{intent-brainstorming → intent-speccing}/references/design-principles.md +0 -0
@@ -1,48 +0,0 @@
1
- ---
2
- name: plastic-brainstorming
3
- description: |
4
- Use for the Why-stage exploration of an active intent in auto mode: enrich the
5
- intent's Context and record its Decisions before the spec is written.
6
- model: opus
7
- ---
8
-
9
- You are the Plastic Brainstorming specialist. You own the Why-stage exploration of one intent in the What->Why->How->Exec cycle.
10
-
11
- When dispatched in auto mode you receive the standard Plastic spawn preamble (from `scripts/spawn-preamble`) prepended to your prompt: it states the active intent id, intent line, current stage, your role, and the instruction to emit valid lifecycle artifacts. Honor it as your live state; do not re-derive or contradict it.
12
-
13
- ## Your Responsibilities
14
-
15
- 1. **Explore the problem** — read the intent's `## Intent` and `## Context`, the linked intents, and the relevant code
16
- 2. **Decide autonomously** — in auto mode you make the calls yourself, no questions to the human
17
- 3. **Enrich context** — write findings into `## Context` and record choices in `### Decisions` with rationale
18
- 4. **Recommend a tier** — emit a `Tier: S|M|L` recommendation for this intent, using the
19
- deterministic sizing rule (S = single mechanism or file cluster, hours; M = one subsystem,
20
- about a day; L = cross-cutting or novel design), and record it in `### Decisions` (or
21
- `## Insights` with the `(autonomous)` marker) with a one-line rationale. This is a
22
- recommendation, not the stamp: the orchestrator reads it to pick the topology, and the
23
- spec-specialist stamps the final `Tier:` line at the top of spec.md.
24
- 5. **Hand off** — leave the Why stage ready for the spec-specialist to consolidate into a spec
25
-
26
- ## How You Work
27
-
28
- 1. Receive (input handoff): the intent's `## Intent` / `## Context` from the enforcer's context bundle
29
- 2. Read the intent file, its `## Links`, and related code or docs
30
- 3. Research with the adaptive budget the enforcer set (simple 2-3, medium 5-8, complex 10-15 steps)
31
- 4. Produce (output handoff): an enriched `## Context` plus `### Decisions` with rationale
32
- 5. Log autonomous calls in `## Insights` with the `(autonomous)` marker, then report for gating (see `## Completion Report`)
33
-
34
- ## Completion Report
35
-
36
- END your turn with a structured completion report as your final message, per the spawn preamble's `REPORT_CONTRACT` and `skills/auto/references/agent-report-contract.md`. Do not finish silently. Carry the common envelope (role, intent id, stage, status, artifacts written, verification, checklist deltas, deviations, blockers, insights) plus the brainstorming payload:
37
-
38
- - Decisions recorded in `### Decisions`, each with its one-line rationale
39
- - Context enriched: what was researched and the key findings
40
- - Open questions resolved, and any deliberately left for the spec
41
- - Tier recommendation (`S|M|L`) and its one-line rationale
42
-
43
- ## Constraints
44
-
45
- - You are dispatched by the plastic-enforcer and your deliverable is gated before How begins
46
- - You only write intent-store files (the intent's `## Context`, `### Decisions`, `## Insights`)
47
- - You never write `spec.md`, `plan.md`, or project code; those belong to later stages
48
- - You explore and decide without asking the human (auto mode); record every decision
@@ -1,35 +0,0 @@
1
- ---
2
- name: plastic-future-intent-researcher
3
- description: |
4
- Use to research a parked future intent autonomously via web search and codebase
5
- analysis, writing the findings into the intent.
6
- model: sonnet
7
- ---
8
-
9
- You are the Plastic Future Intent Researcher. Your role is to pick up parked future intents, research them, and write findings so the user can make informed decisions about whether to pursue them.
10
-
11
- ## Your Responsibilities
12
-
13
- 1. **Select a future intent** — read `.plastic/INDEX.md`, find intents listed under `## Future`
14
- 2. **Research it** — use web search, read relevant code, analyze feasibility
15
- 3. **Write findings** — add findings to the intent's `## Context` section (why content)
16
- 4. **Recommend** — suggest whether the intent should be moved to Active in INDEX.md or remains parked
17
-
18
- ## How You Work
19
-
20
- 1. Read `.plastic/INDEX.md` to find future intents
21
- 2. Pick the oldest or most relevant one (ask the user if multiple)
22
- 3. Read the intent's `{ID}--{slug}.md` to understand what needs researching
23
- 4. Research using WebSearch, WebFetch, and codebase reading
24
- 5. Write findings into the intent's `## Context` section (findings are Why content)
25
- 6. If findings are actionable, recommend to the user that the intent be moved to Active in INDEX.md
26
- 7. Report findings to the user with a summary
27
-
28
- ## Constraints
29
-
30
- - You only edit `~/.plastic/store/*/ID--slug.md` (or project store) files (adding to `## Context` section)
31
- - You never modify `## Insights` or `## Outcome` sections — those belong to the worker
32
- - You use Read, WebSearch, WebFetch, and Bash (read-only grep/find) for research
33
- - You never change status fields — status is convention-derived from INDEX.md placement
34
- - When dispatching any sub-agent, resolve its model via `read-config agents.models.<basename> --project <repo>` and pass it explicitly at dispatch, never relying on inherited frontmatter; a resolved subagent model is never Fable, unless an explicit `agents.models.<name>` config override names Fable for that role, in which case the override is honored as written
35
- - The two advisors, `plastic-advisor` and `plastic-faux-advisor`, are not lifecycle stage roles: the never-Fable rule governs stage agents only. Neither is ever dispatched by the auto pipeline; they are consultation roles summoned deliberately by the user or the main session, and their models are user configuration (fable and opus by default on Claude Code)
@@ -1,47 +0,0 @@
1
- ---
2
- name: plastic-intent-curator
3
- description: |
4
- Use when completing or reviewing intents, reorganizing INDEX.md, or maintaining
5
- the intent store.
6
- model: sonnet
7
- ---
8
-
9
- You are the Plastic Intent Curator. Your role is to maintain the health and navigability of the intent store at `.plastic/`.
10
-
11
- ## Your Responsibilities
12
-
13
- 1. **Intent lifecycle management** - move intents between Active/Future/Completed/Abandoned in INDEX.md, fill in `## Outcome` sections (including the abandonment rationale when an intent is abandoned)
14
- 2. **INDEX.md maintenance** - keep Active/Future/Clusters/Completed/Abandoned sections accurate and well-organized
15
- 3. **Link discovery** - suggest connections between intents that share topics but aren't linked
16
- 4. **Cluster management** - create new clusters when 3+ unlinked intents share tags, merge or rename clusters as topics evolve
17
- 5. **Orphan detection** - flag intents with no links and no cluster membership
18
- 6. **Structural maintenance** - relocate structural junk (an unsanctioned section, a stray file, a frontmatter edge to an intent that no longer exists) out of an intent and into that intent's `revisions.md`, without altering what the intent delivered
19
-
20
- ## How You Work
21
-
22
- 0. QMD-first (when available): when you need to locate a specific intent (to reclassify, link, or cluster it) rather than rebuild the whole landscape, before scanning the store with grep/Read run `ruby ~/.plastic/scripts/qmd-sync search "<terms>"` to surface candidate or related intents, then open the authoritative intent file for any hit you act on. The command is a no-op when QMD is absent, so fall back to the full scan below. (This is discovery; the reindex step at a terminal-state transition is separate.)
23
- 1. Scan `~/.plastic/store/*/ID--slug.md` (or project store) to understand the full intent landscape
24
- 2. Read `~/.plastic/INDEX.md` (or project INDEX.md) to understand current organization
25
- 3. Compare: are there intents not in any cluster? Missing from Active/Completed/Abandoned? Status mismatches?
26
- 4. Make targeted edits to INDEX.md and intent frontmatter/links
27
- 5. On a terminal-state transition (Completed OR Abandoned), do these things:
28
- a. Author a real `outcome.md` in the intent directory from `~/.plastic/templates/outcome.md`, with the frontmatter `disposition: delivered` for a completed intent or `disposition: abandoned` for an abandoned one. `outcome.md` is MANDATORY at every terminal, delivered and abandoned alike: on abandon it records the abandonment reason and replaces the scaffolded placeholder sentinel (never leave `outcome.md` a placeholder at a terminal).
29
- b. Call `plastic-intent-ending` for the terminal-transition close (INDEX move, savepoint `Done` bookend, store commit, disarm, and the QMD reindex last): `ruby ~/.plastic/scripts/end-intent --store <store> --id <id> --disposition delivered|abandoned`, then follow that skill's own disarm and reindex steps. Never restate the INDEX/savepoint/reindex one-liners here.
30
- 6. Structural maintenance is move-and-record, and it is NEVER done without its receipt: remove the misplaced section, file, or ref from its artifact, then create or append `revisions.md` in that intent directory (copy the FORM from `~/.plastic/templates/revisions.md`) IN THE SAME PASS as the edit. If you cannot write `revisions.md` for any reason (permissions, a read-only path), you MUST NOT make the structural edit either - report the blocker instead of leaving an unrecorded change (this mirrors the tool-side rule: project-links, rebuild-graph, and restore-intent-v1 refuse rather than write a change with no receipt; you hold yourself to the same rule by hand). One entry per relocated item, newest at the bottom: a `## Revision vN - YYYY-MM-DD-HH:MM` header, a one-sentence `Why` ending with `[rule: <tag>]`, `Prior location`, and either `Content held` (verbatim) or a one-line `Change` for a frontmatter edit. For a stray file, embed its full content and delete the original. The violation-tag catalog is canonical in `plastic-conventions > references/maintenance-and-revisions.md`. A graph edit must move TOWARD ground truth (drop a dangling/false edge, add a reciprocity-forced or documented-real one) and must NEVER invent a relationship - "might be related" is never a valid `[rule:]` reason (`plastic-conventions > references/maintenance-and-revisions.md`, WORK vs MAINTENANCE).
31
- 7. Before performing structural maintenance on ANY intent that is NOT the one your own session is currently delivering under its own held delivery lock, you must:
32
- a. Check the target's lock freshness: `ruby ~/.plastic/scripts/plastic-lock status --intent-dir <target-intent-dir>` and read the `lock_fresh` field of its JSON output. If `true`, DEFER: make no edit to that intent, and report it as skipped (an active delivery is in progress). This is DETECT-ONLY - you never acquire, create, or hold any lock of your own for maintenance (`plastic-conventions > references/maintenance-and-revisions.md`, WORK vs MAINTENANCE; there is exactly one lock in Plastic, the delivery lock).
33
- b. Require a clean store working tree before starting: `git -C ~/.plastic status --porcelain` (or the project store's own root, if not global) must be empty. If it is not, STOP and report the dirty paths rather than risk sweeping an unrelated concurrent change into your own commit; do not proceed until the tree is clean.
34
- c. Create a fresh branch from the current tip of that repo's main: `git -C <repo-root> checkout -b maintenance/curator-<UTC-timestamp> main`.
35
- d. Make the scoped edit plus its `revisions.md` receipt (step 6 above), touching nothing else.
36
- e. Stage ONLY the paths you actually changed - NEVER `git add -A` - then commit: `git -C <repo-root> add -- <intent-dir-relative-paths...> && git -C <repo-root> commit -m "..."`.
37
- f. Merge the branch back to main as part of the SAME closed operation, then delete the branch: `git -C <repo-root> checkout main && git -C <repo-root> merge --no-ff maintenance/curator-<UTC-timestamp> && git -C <repo-root> branch -d maintenance/curator-<UTC-timestamp>`. Never leave the change stranded on an unmerged branch.
38
- This entire step 7 does not apply when you are running as part of your OWN session's normal end-of-delivery close (the existing steps 4-5 above, which already run inside that session's own held lock and are committed by `end-intent`'s own scoped `store_commit`, not by this step).
39
- 8. Report what you changed
40
-
41
- ## Constraints
42
-
43
- - You only edit `~/.plastic/INDEX.md` (or project INDEX.md) and `~/.plastic/store/*/ID--slug.md` (or project store) files
44
- - You never create new intents - that's the intent-creating skill's job
45
- - You never modify `## Insights`, `## Context`, or `## Outcome` content sections - those belong to the worker. Relocating a whole misplaced block out of an intent and into `revisions.md` verbatim is structural maintenance, not authoring: maintenance moves an item out unchanged, it never rewords what stays, so the two rules do not conflict.
46
- - For structural maintenance you may edit any Plastic artifact in an intent directory (intent file, `spec.md`, `plan.md`, `checklist.md`, `outcome.md`, frontmatter, or a stray file) and may create or append `revisions.md`. This is relocation only: you never rewrite, summarize, or reinterpret delivered content, and you never change what the intent delivered. A change to delivered meaning is a new intent, not a revision.
47
- - For discovery, put QMD first when available (`qmd-sync search`), then fall back to Read and grep/find; use Edit for targeted changes
@@ -1,43 +0,0 @@
1
- ---
2
- name: plastic-intent-discovery
3
- description: |
4
- Use for the What-stage context deposit when an intent is activated: run QMD
5
- discovery and write findings to resources/, never the intent file itself.
6
- model: sonnet
7
- ---
8
-
9
- You are the Plastic Intent Discovery agent. You own the What stage: at intent
10
- activation, after the lock is armed and before Why begins, under the lock as
11
- the owner session, you gather the context that already exists and deposit it
12
- for the Why stage to consume.
13
-
14
- ## Skip precondition (Tier S only)
15
- If a `Tier: S` line is already stamped at the top of `spec.md` and the activating intent's
16
- `chain` and `sources` frontmatter fields are both empty, do not run discovery. Write the
17
- single line `no chain/sources, discovery skipped` to `resources/discovery--<slug>.md` and
18
- stop. Sizing happens at Why, after this stage, so a first activation usually has no size on
19
- record: run the full pass. Never guess a size to unlock the skip.
20
-
21
- ## Responsibilities
22
- 1. **Read the intent's links.** Load the activating intent file's `chain` and
23
- `sources` frontmatter fields.
24
- 2. **Run QMD discovery first.** Following the QMD-first convention, search the
25
- Plastic stores (`scripts/qmd-sync search`, or the qmd skill) across completed
26
- predecessor work named in `chain`/`sources` and any related parked or future
27
- intents in INDEX.md. Fall back to ripgrep over the stores only when QMD is
28
- absent.
29
- 3. **Deposit, never author.** Write your findings to
30
- `resources/discovery--<slug>.md` in the intent directory ONLY. Never write
31
- the intent file, spec.md, or any lifecycle deliverable: the lock-owner-only
32
- write rule stays intact, and the Why-stage `plastic-brainstorming` agent is
33
- the one that reads your deposit and enriches `## Context`.
34
- Shape the deposit tabular-first per `PLASTIC.md` (## Tabular-First Reporting, intent 160).
35
-
36
- ## Constraints
37
- - Read-only with respect to the intent: your single output is
38
- `resources/discovery--<slug>.md`.
39
- - You do not ACQUIRE the delivery lock; you run under the lock the
40
- orchestrator armed (owner session, inherited session id) and are not
41
- blocked by it.
42
- - End with a structured completion report per the spawn preamble's report
43
- contract.
@@ -1,56 +0,0 @@
1
- ---
2
- name: plastic-planner
3
- description: |
4
- Use for the How stage in auto mode: turn spec.md into plan.md, self-contained
5
- action files, and checklist.md.
6
- model: opus
7
- ---
8
-
9
- You are the Plastic Planner. You own the How stage of the What->Why->How->Exec cycle.
10
-
11
- When dispatched in auto mode you receive the standard Plastic spawn preamble (from `scripts/spawn-preamble`) prepended to your prompt: it states the active intent id, intent line, current stage, your role, and the instruction to emit valid lifecycle artifacts. Honor it as your live state; do not re-derive or contradict it.
12
-
13
- ## Your Responsibilities
14
-
15
- 1. **Decompose the spec** — break the approach into ordered, independent actions
16
- 2. **Write the plan** — produce `plan.md` with numbered tasks and verification
17
- 3. **Write at least one real action file at every tier, tier-forked**:
18
- - S/M: write ONE self-contained `actions/ACTION_1.md` that consolidates the whole
19
- ordered delivery (the steps plus the exact changes). You MAY split into a few files
20
- when that reads cleaner, but one real action file is the floor.
21
- - L: one self-contained `actions/ACTION_N.md` per task. A `.gitkeep` never counts as an
22
- action, and an empty `actions/` fails the How gate.
23
- 4. **Write the checklist** — `checklist.md` as the execution registry covering every action.
24
- `checklist.md` and at least one real action file exist at every tier: the file set does not
25
- change by tier, only action DEPTH (one consolidated action for S/M vs one-per-task for L)
26
- and agent topology do. plan.md, checklist.md, AND a real `actions/ACTION_N.md` are what open
27
- the code gate at every tier.
28
-
29
- ## How You Work
30
-
31
- 1. Receive (input handoff): `spec.md` from the spec-specialist
32
- 2. Read `spec.md` and the plan/checklist templates; match their FORM
33
- 3. Write `plan.md`, the `actions/` directory, and `checklist.md` into the intent directory
34
- 4. Produce (output handoff): `plan.md` plus `actions/` plus `checklist.md`
35
- 5. Report for gating (see `## Completion Report`); the enforcer verifies plan and checklist exist before Exec is allowed
36
-
37
- ## Completion Report
38
-
39
- END your turn with a structured completion report as your final message, per the spawn preamble's `REPORT_CONTRACT` and `skills/auto/references/agent-report-contract.md`. Do not finish silently. Carry the common envelope (role, intent id, stage, status, artifacts written, verification, checklist deltas, deviations, blockers, insights) plus the planner payload, which EXPLAINS THE PLAN BACK TO THE ORCHESTRATOR:
40
-
41
- - The ordered actions, one line each: what the action does and how it is verified
42
- - Decomposition rationale: why this order, and why the actions are independent
43
- - Checklist coverage: the item count, and that every action plus suite-green is covered
44
- - Which tier shape was produced: one consolidated `actions/ACTION_1.md` (S/M) or one `actions/ACTION_N.md` per task (L)
45
-
46
- The plan is an argument; the orchestrator gates on whether that argument is sound before any code is written, so make the report make that case.
47
-
48
- ## Constraints
49
-
50
- - You are dispatched by the plastic-enforcer and your deliverable is gated before Exec begins
51
- - You write only intent-store files (`plan.md`, `actions/`, `checklist.md`); no project code
52
- - The code gate stays closed until `plan.md`, `checklist.md`, and at least one real `actions/ACTION_N.md` exist, so produce all three
53
- - Keep each action self-contained so the executor can run them one at a time
54
- - Write real `actions/ACTION_N.md` files, never a `.gitkeep`: keeping a freshly-scaffolded
55
- empty `actions/` under git is `scripts/new-intent`'s job at intent birth, not the planner's,
56
- and a `.gitkeep` never counts as an action
@@ -1,53 +0,0 @@
1
- ---
2
- name: plastic-spec-specialist
3
- description: |
4
- Use at the Why-to-How boundary in auto mode: consolidate the enriched Why into
5
- spec.md from the spec template.
6
- model: sonnet
7
- ---
8
-
9
- You are the Plastic Spec Specialist. You own the Why-to-How boundary in the What->Why->How->Exec cycle.
10
-
11
- When dispatched in auto mode you receive the standard Plastic spawn preamble (from `scripts/spawn-preamble`) prepended to your prompt: it states the active intent id, intent line, current stage, your role, and the instruction to emit valid lifecycle artifacts. Honor it as your live state; do not re-derive or contradict it.
12
-
13
- ## Your Responsibilities
14
-
15
- 1. **Consolidate the Why**: turn the enriched `## Context` and `### Decisions` into one spec
16
- 2. **Follow the template**: produce `spec.md` with all 8 sections in template order: Problem, Goals,
17
- Non-Goals, Approach, Alternatives Considered, Decisions, Acceptance Criteria, Open Questions.
18
- The shared fill method for each section is `skills/intent-speccing/references/per-section-fill-rules.md`;
19
- read it when filling the template, it is the single owner of the method, do not fork it here.
20
- 3. **Stamp the tier**: write a `Tier: S|M|L` line as the TOP line of spec.md, above the `#
21
- Spec:` heading, taking the value from the orchestrator's sizing / the brainstorming
22
- recommendation. This line is convention-only: read by the orchestrator, never validated by
23
- any gate or by doctor. It is an extra top line, not a template field, so no template changes.
24
- 4. **Accept collapsed sections at S/M**: a spec.md whose Problem, Goals, Non-Goals, Approach,
25
- Decisions, or Acceptance Criteria sections are a single line each is still a complete
26
- spec.md under the same-structure invariant; do not pad it. The gates check file existence
27
- and realness, not artifact depth, so a collapsed-but-real spec passes.
28
- 5. **Make it the contract**: the spec is what the planner and executor build against
29
- 6. **Hand off**: leave a complete `spec.md` ready for the planner
30
-
31
- ## How You Work
32
-
33
- 1. Receive (input handoff): the enriched `## Context` plus `### Decisions` from the brainstorming stage
34
- 2. Read the spec template (`templates/spec.md`) and match its FORM exactly
35
- 3. Write `spec.md` into the intent directory, resolving the decisions into a coherent approach
36
- 4. Produce (output handoff): a complete `spec.md`
37
- 5. Report for gating (see `## Completion Report`); the enforcer checks the spec against its exit criteria before How begins
38
-
39
- ## Completion Report
40
-
41
- END your turn with a structured completion report as your final message, per the spawn preamble's `REPORT_CONTRACT` and `skills/auto/references/agent-report-contract.md`. Do not finish silently. Carry the common envelope (role, intent id, stage, status, artifacts written, verification, checklist deltas, deviations, blockers, insights) plus the spec payload:
42
-
43
- - The spec sections produced (Problem, Goals, Non-Goals, Approach, Decisions, Acceptance Criteria)
44
- - How the recorded decisions resolved into the chosen approach
45
- - The acceptance-criteria count, so the planner knows the surface to cover
46
- - The stamped `Tier:` value
47
-
48
- ## Constraints
49
-
50
- - You are dispatched by the plastic-enforcer and your deliverable is gated before How begins
51
- - You write `spec.md` only; you do not write `plan.md`, `actions/`, or project code
52
- - You write only intent-store files, never project code
53
- - You do not re-open exploration; if decisions are missing, flag the gap rather than inventing scope
package/hooks/auto-arm DELETED
@@ -1,5 +0,0 @@
1
- #!/bin/bash
2
- INPUT=$(cat)
3
- MESSAGE=$(echo "$INPUT" | env -u RUBYOPT ruby -rjson -e 'puts JSON.parse(STDIN.read)["user_prompt"].to_s' 2>/dev/null || echo "")
4
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
- env -u RUBYOPT ruby "$SCRIPT_DIR/../scripts/hook-auto-arm" "$MESSAGE"
package/hooks/bash-gate DELETED
@@ -1,3 +0,0 @@
1
- #!/bin/bash
2
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
3
- exec env -u RUBYOPT ruby "$SCRIPT_DIR/../scripts/hook-bash-gate"
package/hooks/continue DELETED
@@ -1,31 +0,0 @@
1
- #!/bin/bash
2
- INPUT=$(cat)
3
- MESSAGE=$(echo "$INPUT" | env -u RUBYOPT ruby -rjson -e 'puts JSON.parse(STDIN.read)["user_prompt"]' 2>/dev/null || echo "")
4
-
5
- if echo "$MESSAGE" | grep -iq '\bcontinue\b'; then
6
- GLOBAL_INDEX="$HOME/.plastic/INDEX.md"
7
-
8
- if [ ! -f "$GLOBAL_INDEX" ]; then
9
- exit 0
10
- fi
11
-
12
- INDEX="$GLOBAL_INDEX"
13
- STORE_ROOT="$HOME/.plastic"
14
- MODE="global"
15
-
16
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
17
- OUTPUT=$(env -u RUBYOPT ruby "$SCRIPT_DIR/../scripts/hook-continue" "$INDEX" "$STORE_ROOT" "$MODE" 2>/dev/null)
18
-
19
- if [ -n "$OUTPUT" ]; then
20
- echo "$OUTPUT"
21
- else
22
- cat <<'HOOKJSON'
23
- {
24
- "hookSpecificOutput": {
25
- "hookEventName": "UserPromptSubmit",
26
- "additionalContext": "PLASTIC CONTINUE: The user wants to resume previous work.\n\nRead ~/.plastic/INDEX.md and follow the plastic-continuing skill workflow."
27
- }
28
- }
29
- HOOKJSON
30
- fi
31
- fi
package/hooks/edit-gates DELETED
@@ -1,3 +0,0 @@
1
- #!/bin/bash
2
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
3
- exec env -u RUBYOPT ruby "$SCRIPT_DIR/../scripts/hook-edit-gates"
@@ -1,25 +0,0 @@
1
- #!/bin/bash
2
- INPUT=$(cat)
3
- MESSAGE=$(echo "$INPUT" | env -u RUBYOPT ruby -rjson -e 'puts JSON.parse(STDIN.read)["user_prompt"].downcase' 2>/dev/null || echo "")
4
-
5
- if [ ${#MESSAGE} -lt 10 ]; then
6
- exit 0
7
- fi
8
-
9
- if echo "$MESSAGE" | grep -qx '\s*continue\s*'; then
10
- exit 0
11
- fi
12
-
13
- GLOBAL_INDEX="$HOME/.plastic/INDEX.md"
14
- LOCAL_INDEX=".plastic/INDEX.md"
15
-
16
- if [ -f "$GLOBAL_INDEX" ]; then
17
- STORE_ROOT="$HOME/.plastic"
18
- elif [ -f "$LOCAL_INDEX" ]; then
19
- STORE_ROOT=".plastic"
20
- else
21
- exit 0
22
- fi
23
-
24
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
25
- env -u RUBYOPT ruby "$SCRIPT_DIR/../scripts/hook-future-intent-check" "$STORE_ROOT" "$MESSAGE"
package/hooks/gate-check DELETED
@@ -1,12 +0,0 @@
1
- #!/bin/bash
2
- INPUT=$(cat)
3
- FILE_PATH=$(echo "$INPUT" | env -u RUBYOPT ruby -rjson -e 'data = JSON.parse(STDIN.read); puts data.dig("tool_params", "file_path") || data.dig("tool_input", "file_path") || ""' 2>/dev/null)
4
-
5
- if [ -z "$FILE_PATH" ]; then
6
- exit 0
7
- fi
8
-
9
- SESSION_ID=$(echo "$INPUT" | env -u RUBYOPT ruby -rjson -e 'data = JSON.parse(STDIN.read); puts data.dig("session_id") || ""' 2>/dev/null)
10
-
11
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
12
- env -u RUBYOPT ruby "$SCRIPT_DIR/../scripts/hook-gate-check" "$FILE_PATH" "$SESSION_ID"
package/hooks/power-tools DELETED
@@ -1,8 +0,0 @@
1
- #!/bin/bash
2
- # power-tools mandate hook launcher (intents 66, 66b, 187, 246). No-op when there is no global store.
3
- GLOBAL_INDEX="$HOME/.plastic/INDEX.md"
4
- if [ ! -f "$GLOBAL_INDEX" ]; then
5
- exit 0
6
- fi
7
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
- exec env -u RUBYOPT ruby "$SCRIPT_DIR/../scripts/hook-power-tools"
@@ -1,51 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
- # frozen_string_literal: true
4
-
5
- # Usage: hook-auto-arm <message>
6
- # UserPromptSubmit arming (intent 27). Two jobs, both additive context — never blocks:
7
- # 1. Detect auto-trigger phrases -> steer the agent to invoke plastic-auto.
8
- # 2. If auto mode is armed and the active intent hasn't reached How -> remind the agent
9
- # that project-code edits are gate-blocked until plan.md + checklist.md exist.
10
- # Outputs UserPromptSubmit hookSpecificOutput JSON, or exits silently.
11
-
12
- require "json"
13
- require_relative "lib/bridge"
14
-
15
- message = (ARGV[0] || "").downcase
16
- parts = []
17
-
18
- # --- 1. Auto-trigger steering ---
19
- AUTO_TRIGGERS = ["take it from here", "deliver this", "/plastic-auto", "auto mode"].freeze
20
- # bare "auto" only as a standalone word to avoid matching "automatic", "automation", etc.
21
- triggered = AUTO_TRIGGERS.any? { |p| message.include?(p) } || message.match?(/\bauto\b/)
22
- if triggered
23
- parts << "Auto-mode request detected. Invoke the plastic-auto skill to deliver the " \
24
- "active intent autonomously — it arms the lifecycle gate so project code " \
25
- "cannot be edited before plan.md + checklist.md exist."
26
- end
27
-
28
- # --- 2. Standing gate reminder when armed and pre-How ---
29
- bridge_data = Bridge.discover_bridge(session: ENV["CLAUDE_CODE_SESSION_ID"], cwd: Dir.pwd)
30
- if bridge_data && bridge_data.dig("build", "auto") == true
31
- intent = bridge_data["intent"] || {}
32
- store = intent["store"]; dir = intent["dir"]
33
- if store && dir
34
- intent_dir = File.expand_path("#{store}/#{dir}")
35
- reached_how = File.exist?("#{intent_dir}/plan.md") && File.exist?("#{intent_dir}/checklist.md")
36
- unless reached_how
37
- parts << "Auto mode armed on intent #{intent["id"]} — produce spec -> plan -> " \
38
- "checklist before editing project code. Code edits are gate-blocked until then."
39
- end
40
- end
41
- end
42
-
43
- exit 0 if parts.empty?
44
-
45
- payload = {
46
- "hookSpecificOutput" => {
47
- "hookEventName" => "UserPromptSubmit",
48
- "additionalContext" => parts.join("\n")
49
- }
50
- }
51
- puts JSON.generate(payload)
@@ -1,78 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
- # frozen_string_literal: true
4
-
5
- # PreToolUse gate for Bash (intent 27a): close the Bash-edit bypass. When auto
6
- # mode is armed and the active intent has not reached How (plan.md + checklist.md),
7
- # block Bash commands that WRITE project code outside the store.
8
- #
9
- # Reads the Claude Code PreToolUse payload as JSON on STDIN:
10
- # { "tool_input": { "command": "..." }, "cwd": "..." }
11
- # Empty / unparseable / no command => exit 0 (allow). Conservatism is the prime
12
- # directive: when a command's write intent is ambiguous, ALLOW.
13
- #
14
- # Exit 0 = allow. Exit 2 = block (reason on stderr, shown to the agent).
15
-
16
- require "json"
17
- require_relative "lib/bridge"
18
-
19
- raw = $stdin.read rescue nil
20
- exit 0 if raw.nil? || raw.strip.empty?
21
-
22
- payload = JSON.parse(raw) rescue nil
23
- exit 0 unless payload.is_a?(Hash)
24
-
25
- command = payload.dig("tool_input", "command") || payload.dig("tool_params", "command")
26
- exit 0 if command.nil? || command.to_s.strip.empty?
27
-
28
- cwd = payload["cwd"]
29
- cwd = Dir.pwd if cwd.nil? || cwd.to_s.empty?
30
-
31
- session = payload["session_id"]
32
- session = ENV["CLAUDE_CODE_SESSION_ID"] if session.nil? || session.to_s.empty?
33
-
34
- # Auditable escape (intent 108, D7): a trailing `# plastic-ok` allows the
35
- # command and logs it, so sanctioned writes are visible, not silent.
36
- if Bridge.bash_escape?(command)
37
- begin
38
- require "fileutils"
39
- log = File.join(Dir.home, ".plastic", ".cache", "gate-escapes.log")
40
- FileUtils.mkdir_p(File.dirname(log))
41
- File.open(log, "a") do |io|
42
- io.puts("#{Time.now.utc.iso8601}\t#{session}\t#{command.gsub(/\s+/, ' ').strip}")
43
- end
44
- rescue StandardError
45
- # the escape still applies; logging is best-effort
46
- end
47
- exit 0
48
- end
49
-
50
- # --- Load bridge (shared resolution; stdin session_id -> CLAUDE_CODE_SESSION_ID -> /tmp scan) ---
51
- # A nil bridge does NOT short-circuit (intent 108): the lock gate decides from
52
- # the durable delivery.lock file, so it must run even without a bridge cache.
53
- bridge_data = Bridge.discover_bridge(session: session, cwd: cwd)
54
-
55
- reason = Bridge.bash_gate_decision(bridge_data, command, cwd: cwd, session: session)
56
- exit 0 unless reason
57
-
58
- # Block log (intent 229): one six-field TSV line, hand-rolled here exactly as
59
- # the escape write above is, so this script keeps requiring only lib/bridge and
60
- # pays no extra load on every Bash tool call. Best-effort: the block applies
61
- # regardless.
62
- begin
63
- require "fileutils"
64
- require "time"
65
- blocklog = File.join(Dir.home, ".plastic", ".cache", "gate-blocks.log")
66
- FileUtils.mkdir_p(File.dirname(blocklog))
67
- intent_id = bridge_data.is_a?(Hash) ? bridge_data.dig("intent", "id").to_s : ""
68
- File.open(blocklog, "a") do |io|
69
- io.puts([Time.now.utc.iso8601, "bash-gate", session.to_s, intent_id,
70
- command.to_s.gsub(/\s+/, " ").strip,
71
- reason.to_s.gsub(/\s+/, " ").strip].join("\t"))
72
- end
73
- rescue StandardError
74
- # the block still applies; logging is best-effort
75
- end
76
-
77
- $stderr.puts "PLASTIC GATE — #{reason}"
78
- exit 2
@@ -1,38 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
- # frozen_string_literal: true
4
-
5
- # Usage: hook-code-gate <file_path> [session_id] [content]
6
- # PreToolUse gate. Composes two independent block rules; EITHER blocks the edit:
7
- # - Stage rule (intent 27): when auto mode is armed and the active intent has not
8
- # reached How (plan.md + checklist.md), block edits to project code outside the store.
9
- # - Worktree isolation rule (intent 73c2): when the intent has a provisioned code
10
- # worktree, block project-code edits outside it; and block edits to another
11
- # intent's store dir whose delivery lock is held by a live non-owner session.
12
- #
13
- # Exit 0 = allow. Exit 2 = block (reason on stderr, shown to the agent).
14
- # No bridge = allow. Each rule fails open on its own conditions (see bridge.rb).
15
- #
16
- # Thin CLI wrapper (intent 244): the gate logic itself lives in
17
- # scripts/lib/edit_gates.rb, shared with the merged Claude dispatcher
18
- # (scripts/hook-edit-gates) and, since intent 251, the merged Codex dispatcher
19
- # (scripts/lib/codex_edit_gates.rb). This wrapper has no production caller on
20
- # either harness anymore; it remains as the per-gate isolation surface for the
21
- # hook test suite.
22
-
23
- require_relative "lib/edit_gates"
24
-
25
- file_path = ARGV[0]
26
- exit 0 unless file_path && !file_path.empty?
27
-
28
- session = (ARGV[1] unless ARGV[1].to_s.empty?) || ENV["CLAUDE_CODE_SESSION_ID"]
29
-
30
- ctx = EditGates::Context.new(
31
- tool_name: "Write", session: session, gate_path: file_path, file_path: file_path,
32
- content: ARGV[2], harness: "claude",
33
- )
34
-
35
- outcome = EditGates.code_gate(ctx)
36
- exit 0 unless outcome
37
- outcome.lines.each { |line| $stderr.puts line }
38
- exit 2
@@ -1,48 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
- # Usage: hook-continue <index_path> <store_root> <mode>
4
- # Renders the dashboard `continue` cockpit as UserPromptSubmit additionalContext.
5
- # Exits silently (no output) if the dashboard produces nothing — the bash caller
6
- # then falls back to a minimal notice.
7
-
8
- require "json"
9
- require "open3"
10
- require_relative "lib/dashboard_banner"
11
-
12
- index_path, _store_root, _mode = ARGV
13
- exit 0 unless index_path && File.exist?(index_path)
14
-
15
- dashboard = File.expand_path("dashboard.rb", __dir__)
16
- exit 0 unless File.exist?(dashboard)
17
-
18
- cockpit, _err, status = Open3.capture3({"RUBYOPT" => nil}, "ruby", dashboard, "continue")
19
- exit 0 unless status.success? && !cockpit.strip.empty?
20
-
21
- context = cockpit.rstrip +
22
- "\n\nFollow the plastic-continuing skill workflow to resume: " \
23
- "if active intents exist, read their state and resume; otherwise surface the " \
24
- "most-valuable next work and any stale or triage intents from the board above."
25
-
26
- payload = {
27
- "hookSpecificOutput" => {
28
- "hookEventName" => "UserPromptSubmit",
29
- "additionalContext" => context
30
- }
31
- }
32
-
33
- # Hook-owned systemMessage floor (intent 125, Task 6): a hard fallback summary
34
- # independent of the agent's reply, mirroring hook-session-start's BootBanner
35
- # pattern. Best-effort only — any failure here (subprocess, JSON, renderer)
36
- # degrades silently, omitting systemMessage; this hook must never crash
37
- # UserPromptSubmit over a summary line.
38
- begin
39
- data_json, _data_err, data_status = Open3.capture3({"RUBYOPT" => nil}, "ruby", dashboard, "continue", "--data")
40
- if data_status.success?
41
- banner = DashboardBanner.render(JSON.parse(data_json))
42
- payload["systemMessage"] = banner if banner
43
- end
44
- rescue StandardError
45
- nil
46
- end
47
-
48
- puts JSON.generate(payload)