@zalom/plastic 1.0.0-alpha.33 → 1.0.0-alpha.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/PLASTIC.md CHANGED
@@ -97,6 +97,26 @@ succession at a glance (last line = where we are).
97
97
  brainstorming, writing-plans, etc., Plastic's directory rules override
98
98
  their default output paths.
99
99
 
100
+ ## Defaults-First
101
+
102
+ Plastic stands on its own. Skills and agents use Plastic's own defaults; an
103
+ external skill (for example `superpowers:*`) is opt-in, never load-bearing.
104
+
105
+ - **Default to Plastic, delegate by exception.** Name the Plastic-native path as
106
+ the default. Delegate to an external skill only when (a) it is available in the
107
+ harness, or (b) the user explicitly asks for it. A user without that plugin must
108
+ still get the core behavior.
109
+ - **Phrase external skills as enhancements.** Write "use Plastic's native X by
110
+ default; if `superpowers:<skill>` is available, or the user prefers it, delegate
111
+ to it" never "delegate to `superpowers:<skill>`" as the only path.
112
+ - **Optional dependencies detect then degrade.** `qmd` is the reference shape:
113
+ `scripts/lib/qmd_sync.rb` detects the binary first and every verb no-ops cleanly
114
+ when it is absent (see `scripts/qmd-sync`). Optional CLIs and MCP servers follow
115
+ the same detect-then-skip pattern, so a missing tool never crashes a session.
116
+ - **Legitimate hard dependencies are exempt.** Ruby, Node, git, and POSIX tools are
117
+ the cost of running Plastic, not silent coupling. The principle targets accidental
118
+ dependence on external skills doing work Plastic should do itself.
119
+
100
120
  ## State System
101
121
 
102
122
  ```
@@ -12,6 +12,8 @@ model: inherit
12
12
 
13
13
  You are the Plastic Brainstorming specialist. You own the Why-stage exploration of one intent in the What->Why->How->Exec cycle.
14
14
 
15
+ 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.
16
+
15
17
  ## Your Responsibilities
16
18
 
17
19
  1. **Explore the problem** — read the intent's `## Intent` and `## Context`, the linked intents, and the relevant code
@@ -25,12 +25,12 @@ You are the Plastic Enforcer. You ARE the auto orchestrator, spanning the whole
25
25
  1. Arm the gate, then dispatch the brainstorming specialist; gate its `## Context` + `### Decisions`
26
26
  2. Dispatch the spec-specialist; gate `spec.md`. Then the planner; gate `plan.md` + `checklist.md`
27
27
  3. Dispatch the executor; require a green suite. Sequential, one team per intent, on one branch when files are shared
28
- 4. Delegate real parallelism and dispatch to `superpowers:subagent-driven-development` and `superpowers:dispatching-parallel-agents`
28
+ 4. Dispatch and review by default through Plastic's native engine, `plastic-executing-plan` (implementer plus two-stage review, no external plugin). If `superpowers:subagent-driven-development` and `superpowers:dispatching-parallel-agents` are available, or the user asks for them, delegate to them as an enhancement
29
29
  5. At the final gate, dispatch an independent reviewer subagent, then complete the intent
30
30
 
31
31
  ## Constraints
32
32
 
33
33
  - Enforce gates manually; do not rely on hooks, because `CLAUDE_SESSION_ID` may be unset in headless or background runs
34
34
  - You never delegate gate ownership; the orchestrator is always the gate-keeper
35
- - Roles are thin handoff contracts, not an execution engine; delegate dispatch to the superpowers skills
36
- - If the harness has no subagent dispatch, fall back to a single agent walking the full cycle
35
+ - Roles are thin handoff contracts, not an execution engine; dispatch through `plastic-executing-plan` by default, and through the superpowers skills only when they are available or the user prefers them
36
+ - Fall back by case: if the harness supports subagents but superpowers is absent, use the native `plastic-executing-plan` engine; if the harness has no subagent dispatch at all, fall back to a single agent walking the full cycle
@@ -12,6 +12,8 @@ model: inherit
12
12
 
13
13
  You are the Plastic Executor. You own the Exec stage of the What->Why->How->Exec cycle.
14
14
 
15
+ 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.
16
+
15
17
  ## Your Responsibilities
16
18
 
17
19
  1. **Implement the actions** — make the code changes for each action in order
@@ -12,6 +12,8 @@ model: inherit
12
12
 
13
13
  You are the Plastic Planner. You own the How stage of the What->Why->How->Exec cycle.
14
14
 
15
+ 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.
16
+
15
17
  ## Your Responsibilities
16
18
 
17
19
  1. **Decompose the spec** — break the approach into ordered, independent actions
@@ -12,6 +12,8 @@ model: inherit
12
12
 
13
13
  You are the Plastic Spec Specialist. You own the Why-to-How boundary in the What->Why->How->Exec cycle.
14
14
 
15
+ 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.
16
+
15
17
  ## Your Responsibilities
16
18
 
17
19
  1. **Consolidate the Why** — turn the enriched `## Context` and `### Decisions` into one spec
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zalom/plastic",
3
- "version": "1.0.0-alpha.33",
3
+ "version": "1.0.0-alpha.35",
4
4
  "description": "Intent-driven idea development system for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,6 +8,7 @@
8
8
 
9
9
  require "json"
10
10
  require_relative "lib/bridge"
11
+ require_relative "lib/intent_validator"
11
12
 
12
13
  file_path = ARGV[0]
13
14
  exit 0 unless file_path && !file_path.empty?
@@ -28,6 +29,24 @@ if intent_dir_abs
28
29
  end
29
30
  end
30
31
 
32
+ # --- Artifact-validity backstop (intent 4a1c1) ---
33
+ # When the written file IS the intent file itself (the `<id>--<slug>.md` directly
34
+ # inside `store/<id>--<slug>/`), run IntentValidator on it. This is headless-safe:
35
+ # it depends only on the file path and disk, never on a bridge or session. In the
36
+ # PostToolUse model the write has already happened, so we cannot prevent it; the
37
+ # loud non-zero exit + stderr is the rejection signal. NOT for spec.md/plan.md/
38
+ # checklist.md/outcome.md/savepoint.md — those are validated by the stage gates.
39
+ if intent_dir_abs && File.basename(file_path_abs) == File.basename(Bridge.intent_file(intent_dir_abs))
40
+ result = IntentValidator.validate(intent_dir_abs)
41
+ unless result[:ok]
42
+ warn "PLASTIC ARTIFACT INVALID — #{File.basename(file_path_abs)} is not born complete:"
43
+ result[:missing].each { |field| warn " missing required field: #{field}" }
44
+ result[:errors].each { |error| warn " #{error}" }
45
+ warn "Fix the frontmatter; the intent is not valid until every required field is present and sources/chain are well-formed."
46
+ exit 1
47
+ end
48
+ end
49
+
31
50
  # --- Find bridge file ---
32
51
  bridge_data = Bridge.discover_bridge(session: session, cwd: Dir.pwd)
33
52
 
@@ -208,6 +208,7 @@ class InstallerCore
208
208
  "scripts/qmd-sync" => "scripts/qmd-sync",
209
209
  "scripts/lib/intent_validator.rb" => "scripts/lib/intent_validator.rb",
210
210
  "scripts/validate-intent" => "scripts/validate-intent",
211
+ "scripts/spawn-preamble" => "scripts/spawn-preamble",
211
212
  "scripts/lib/store_provisioning.rb" => "scripts/lib/store_provisioning.rb",
212
213
  "scripts/provision-project-store" => "scripts/provision-project-store",
213
214
  "scripts/lib/installer_core.rb" => "scripts/lib/installer_core.rb",
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # frozen_string_literal: true
4
+
5
+ # spawn-preamble — deterministic live-state injection for spawned agents
6
+ # (intent 4a1c1, agent harness foundation).
7
+ #
8
+ # Emits a preamble block built ONLY from filesystem state for a single intent
9
+ # directory. It is a PURE function of the intent dir: no network, no randomness,
10
+ # no wall-clock reads. Two runs over the same on-disk state produce byte-identical
11
+ # output. This is the authoritative L2 (live-state) mechanism for harnesses whose
12
+ # spawned sub-agents do not inherit a top-level session event (see
13
+ # docs/reference/harness-adapters.md).
14
+ #
15
+ # Usage:
16
+ # spawn-preamble <intent_dir> [--role ROLE] [--step STEP]
17
+ #
18
+ # The preamble reports the active intent (id + intent line from frontmatter), the
19
+ # current lifecycle stage (last savepoint line if present, else derived from which
20
+ # lifecycle files exist), the cycle role/step (from --role/--step, else the
21
+ # derived stage), and an imperative honoring instruction.
22
+ #
23
+ # Exit codes: 0 (preamble emitted), 2 (usage).
24
+
25
+ require_relative "lib/bridge"
26
+
27
+ # Verbatim honoring instruction. Kept as one constant so the contract doc and the
28
+ # test assert against the exact same string.
29
+ HONOR_INSTRUCTION =
30
+ "You are operating inside Plastic. Use it as your operating scaffold. " \
31
+ "Emit VALID lifecycle artifacts; do not hallucinate intents or stages. " \
32
+ "Your output is a deliverable, not a message."
33
+
34
+ def parse_args(argv)
35
+ role = nil
36
+ step = nil
37
+ positional = []
38
+ i = 0
39
+ while i < argv.length
40
+ case argv[i]
41
+ when "--role"
42
+ role = argv[i + 1]
43
+ i += 2
44
+ when "--step"
45
+ step = argv[i + 1]
46
+ i += 2
47
+ else
48
+ positional << argv[i]
49
+ i += 1
50
+ end
51
+ end
52
+ [positional.first, role, step]
53
+ end
54
+
55
+ # Read the intent file frontmatter via the same parser the validator uses, so the
56
+ # id/intent we report match what the rest of Plastic sees. Returns a Hash (possibly
57
+ # empty) — never raises.
58
+ def frontmatter_for(intent_dir)
59
+ ifile = Bridge.intent_file(intent_dir)
60
+ return {} unless File.exist?(ifile)
61
+
62
+ content = File.read(ifile)
63
+ return {} unless content.start_with?("---")
64
+
65
+ parts = content.split("---", 3)
66
+ return {} if parts.length < 3
67
+
68
+ require "yaml"
69
+ require "date"
70
+ require "time"
71
+ YAML.safe_load(parts[1], permitted_classes: [Date, Time]) || {}
72
+ rescue StandardError
73
+ {}
74
+ end
75
+
76
+ # Current stage label. Prefer the last non-empty line of savepoint.md (the ledger
77
+ # already encodes the furthest-reached milestone). Fall back to the file-derived
78
+ # stage when there is no ledger.
79
+ STAGE_LABELS = {
80
+ "what" => "What", "why" => "Why", "how" => "How",
81
+ "exec" => "Exec", "done" => "Done"
82
+ }.freeze
83
+
84
+ def current_stage(intent_dir)
85
+ ledger = File.join(intent_dir, Bridge::SAVEPOINT_FILE)
86
+ if File.exist?(ledger)
87
+ last = File.read(ledger).each_line.map(&:strip).reject(&:empty?).last
88
+ return last if last
89
+ end
90
+ STAGE_LABELS.fetch(Bridge.derive_stage(intent_dir), Bridge.derive_stage(intent_dir))
91
+ end
92
+
93
+ intent_dir_arg, role, step = parse_args(ARGV)
94
+
95
+ if intent_dir_arg.nil? || intent_dir_arg.empty?
96
+ warn "usage: spawn-preamble <intent_dir> [--role ROLE] [--step STEP]"
97
+ exit 2
98
+ end
99
+
100
+ intent_dir = File.expand_path(intent_dir_arg)
101
+
102
+ fm = frontmatter_for(intent_dir)
103
+ id = fm["id"].to_s.strip
104
+ intent_name = fm["intent"].to_s.strip
105
+ id = "(unknown)" if id.empty?
106
+ intent_name = "(unknown)" if intent_name.empty?
107
+
108
+ stage = current_stage(intent_dir)
109
+ cycle = role || step || stage
110
+
111
+ lines = []
112
+ lines << "=== Plastic spawn preamble ==="
113
+ lines << "Store: #{intent_dir}"
114
+ lines << "Active intent: #{id} - #{intent_name}"
115
+ lines << "Current stage: #{stage}"
116
+ lines << "Cycle step / role: #{cycle}"
117
+ lines << ""
118
+ lines << HONOR_INSTRUCTION
119
+ lines << "=== end preamble ==="
120
+
121
+ puts lines.join("\n")
@@ -64,7 +64,9 @@ Roster (one role per cycle stage):
64
64
  - **plastic-executor** (code + checklist + `## Insights`)
65
65
  - **plastic-enforcer** (orchestrates + gates; that is YOU)
66
66
 
67
- Dispatch rule: sequential, one specialist per stage on one branch (the deliverables share files). Gate each deliverable against the stage's exit criteria before handing off. Delegate the actual How and Exec dispatch to `superpowers:subagent-driven-development` and `superpowers:dispatching-parallel-agents` (see the How and Exec phases below); do not restate them.
67
+ Dispatch rule: sequential, one specialist per stage on one branch (the deliverables share files). Gate each deliverable against the stage's exit criteria before handing off. The How and Exec phases below default to Plastic's native dispatch (`plastic-executing-plan`) and delegate to the superpowers skills only when they are available or the user asks; do not restate the phase mechanics here.
68
+
69
+ Spawn preamble (live-state injection): before dispatching any specialist, run `scripts/spawn-preamble <intent_dir> --role <role>` and PREPEND its output to that specialist's prompt. The preamble is a deterministic, filesystem-only snapshot of the active intent (id, intent line, current stage) plus the honoring instruction, so every spawned agent boots with accurate live state instead of guessing. This is the authoritative L2 mechanism for harnesses whose sub-agents do not inherit a top-level session event (see `docs/reference/harness-adapters.md`).
68
70
 
69
71
  Final-gate review: dispatch an independent reviewer subagent at the final gate only, not as a standing role.
70
72
 
@@ -48,6 +48,19 @@ The chain: intent `## Intent` / `## Context`, then enriched `## Context` plus
48
48
  `### Decisions`, then `spec.md`, then `plan.md` plus `actions/` plus `checklist.md`,
49
49
  then the code changes plus a checked-off checklist plus `## Insights`.
50
50
 
51
+ ### Spawn Preamble (L2 live-state injection)
52
+
53
+ Every dispatched specialist is booted with a spawn preamble: the enforcer runs
54
+ `scripts/spawn-preamble <intent_dir> --role <role>` and prepends its output to the
55
+ specialist's prompt. The preamble is a pure function of the intent directory on disk
56
+ (no network, no clock, no randomness), so it is deterministic and rebuildable. It
57
+ carries the active intent id and intent line, the current lifecycle stage (the last
58
+ savepoint line, else stage derived from which lifecycle files exist), the cycle
59
+ role, and the honoring instruction that the agent must emit valid lifecycle artifacts
60
+ and not hallucinate intents or stages. This is the standard L2 live-state mechanism
61
+ for harnesses whose spawned sub-agents do not inherit the top-level session event. See
62
+ `docs/reference/harness-adapters.md` for how it slots into the per-harness contract.
63
+
51
64
  ### Gate Ownership
52
65
 
53
66
  The enforcer arms and verifies the lifecycle gate, then gates every stage transition.
@@ -64,16 +77,21 @@ derived-key fallback and verifies state itself.
64
77
 
65
78
  ### Delegation
66
79
 
67
- The roles are thin handoff contracts, not a spawning engine. Real parallelism and
68
- dispatch are delegated to `superpowers:subagent-driven-development` and
69
- `superpowers:dispatching-parallel-agents`. The team model defines who hands what to
70
- whom and where the gates sit, the superpowers skills do the actual dispatching.
71
-
72
- ### Solo Fallback
73
-
74
- If the harness has no subagent dispatch, auto mode falls back to a single agent
75
- walking the full What, Why, How, Exec cycle itself. This preserves the original
76
- behavior on harnesses without teams. The enforcer's gate discipline still applies.
80
+ The roles are thin handoff contracts, not a spawning engine. Dispatch and review run
81
+ by default through Plastic's own engine, `plastic-executing-plan` (implementer plus
82
+ two-stage review, no external plugin). When `superpowers:subagent-driven-development`
83
+ and `superpowers:dispatching-parallel-agents` are available, or the user asks for them,
84
+ they delegate to those as an enhancement. The team model defines who hands what to whom
85
+ and where the gates sit; the dispatch engine, native or superpowers, does the actual
86
+ spawning.
87
+
88
+ ### Fallback by Case
89
+
90
+ The default is always Plastic's native engine, so a user without superpowers still gets
91
+ the full behavior. If the harness supports subagents but superpowers is absent, auto
92
+ mode dispatches through `plastic-executing-plan`. If the harness has no subagent dispatch
93
+ at all, auto mode falls back to a single agent walking the full What, Why, How, Exec
94
+ cycle itself. The enforcer's gate discipline still applies in every case.
77
95
 
78
96
  ### Dogfood Proof
79
97
 
@@ -3,7 +3,7 @@ name: plastic-brainstorming-grill-me
3
3
  description: >-
4
4
  Deep brainstorming that interviews the user relentlessly about a plan or design until reaching shared understanding.
5
5
  Use when user wants to stress-test a plan, get grilled on their design, or mentions "grill me".
6
- Complements superpowers:brainstorming — use brainstorming for quick ideation, grill-me for thorough interrogation.
6
+ Pair with plastic-brainstorming for quick ideation and use grill-me for thorough interrogation. If superpowers:brainstorming is installed it complements this skill, but it is not required.
7
7
  ---
8
8
 
9
9
  # Grill Me — Deep Brainstorming