@zalom/plastic 1.0.0-beta.31 → 1.0.0-beta.33

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
@@ -150,6 +150,28 @@ agent that can write the file) persists it via the helper. A session that cannot
150
150
  intent file still returns its report, so the insight survives.
151
151
  For full lifecycle detail, the skills in the Detail column have references/.
152
152
 
153
+ ## Tiers (proportional auto sizing)
154
+
155
+ Auto mode sizes every intent S/M/L at Why: S = single mechanism or file cluster (hours);
156
+ M = one subsystem (about a day); L = cross-cutting or novel design.
157
+
158
+ Speed comes from two levers only: artifact content depth and agent topology. The
159
+ same-structure invariant holds: same file set, stage order, gates, and savepoint ledger at
160
+ every tier and in both modes.
161
+
162
+ S/M collapse the topology (one thinker agent writes spec.md then plan.md plus
163
+ checklist.md in one context; actions/ only for L; a sonnet executor implements). L keeps
164
+ the full team.
165
+
166
+ Never cut at any tier: the independent reviewer, outcome.md as truth of delivery, the
167
+ delivery lock, worktree isolation, intent creation via skill, INDEX as status truth, the
168
+ QMD reindex at End.
169
+
170
+ Tier is recorded as a `Tier: S|M|L` line at the top of spec.md. It is convention-only,
171
+ read by the orchestrator, not enforced by any gate or by doctor.
172
+
173
+ Guided mode is unchanged: full-depth artifacts, the human at every gate.
174
+
153
175
  ## Agent Models and Dispatch (intent 116)
154
176
 
155
177
  Every lifecycle stage has exactly one dispatchable background agent, plus the enforcer that
@@ -300,6 +322,45 @@ One-line entry convention. Each index entry is ONE line: `- [<id> <terse title>]
300
322
  The title is the title, not a summary: aim for about 80 characters, no multi-sentence
301
323
  descriptions. This is a self-check, not a gate.
302
324
 
325
+ ## Roadmaps
326
+
327
+ Roadmaps exist for planned parallel delivery of intents in a coherent and organized way. A roadmap
328
+ is a named, ordered, delivery-side collection of intents: the delivery-side counterpart to a
329
+ release (completion-side, tracked in `CHANGELOG.md`). Use `plastic-roadmap` to create, order,
330
+ close, and consume one.
331
+
332
+ File location: `roadmaps/{slug}.md`, a sibling of `INDEX.md`, wherever `INDEX.md` lives, never
333
+ inside `store/` (store holds intent directories, not project artifacts). For a project that is its
334
+ root, `~/.plastic/projects/{slug}/roadmaps/`, beside `project.yml`; for the global tier it is
335
+ `~/.plastic/roadmaps/`, beside `~/.plastic/INDEX.md`. `roadmaps/` lists only live (open or
336
+ in-flight) roadmaps: once a roadmap's goal is reached, it moves to `roadmaps/archived/{slug}.md`,
337
+ a sibling subdirectory scaffolded once with a `.gitkeep`.
338
+
339
+ A roadmap file has four sections, in order: a title/meta header, `## Goal`, `## Waves`, and an
340
+ append-only dated `## Log`. `## Goal` is a checkable prose condition read by a human or agent, not
341
+ an executable checker. `## Waves` holds ordered waves; entries inside a wave are parallel-safe,
342
+ waves run sequentially, top to bottom.
343
+
344
+ Each wave entry carries a status token (`queued`/`delivering`/`delivered`/`abandoned`/`blocked`)
345
+ that mirrors that intent's status in `INDEX.md`. `INDEX.md` is the single writer of intent status;
346
+ on any conflict INDEX wins and the roadmap entry is corrected to match.
347
+
348
+ **Human-comprehension surface.** A roadmap is also written to be read cold. Wave entries render as
349
+ checkboxes (checked once delivered, unchecked otherwise) next to the status token, and each `## Log`
350
+ line is one plain-language sentence, starting `YYYY-MM-DD HH:MM UTC`, written the way an
351
+ engineering manager would brief a non-expert executive: what shipped and why it matters, no jargon
352
+ or codenames, ending with a link
353
+ to that intent's `outcome.md`. The log points at the detail instead of repeating it, so a person
354
+ opening the file with no other context can tell what shipped, what is running now, and what is
355
+ next in under a minute.
356
+
357
+ **Relationship to loop engineering (intent 69).** A roadmap is the planning half of the work; the
358
+ loop is its runtime. Waves lay out the parallelism plan: what can run together, and in what order.
359
+ Loop engineering (intent 69, not yet delivered) is expected to consume that plan and supply the
360
+ running parts, the heartbeat, how many dispatches run at once, checking the goal, and resuming
361
+ after a stop. This section only states the relationship and points to intent 69 as the future
362
+ consumer; it does not change intent 69's own design.
363
+
303
364
  ## Rules for Skills
304
365
 
305
366
  ALL work flows through intents.
@@ -512,3 +573,4 @@ Detailed conventions live inside the skills that use them, not in this file.
512
573
  | Health diagnostics | `plastic-doctor` | three scopes: `--core` (binary install-integrity check, runs on SessionStart), `--store [global\|<slug>]` (per-store check, runs on dashboard load), no flag = full check (runs after every update); gate enforcement, stuck detection |
513
574
  | Authoring skills, agents, hooks | `plastic-creating-skills` | progressive disclosure, agentskills.io spec |
514
575
  | Evaluating skills, evals | `plastic-evaluating-skills` | eval methodology, convention checks |
576
+ | Create, order, and consume a roadmap of intents | `plastic-roadmap` | file format, operations |
@@ -19,7 +19,13 @@ When dispatched in auto mode you receive the standard Plastic spawn preamble (fr
19
19
  1. **Explore the problem** — read the intent's `## Intent` and `## Context`, the linked intents, and the relevant code
20
20
  2. **Decide autonomously** — in auto mode you make the calls yourself, no questions to the human
21
21
  3. **Enrich context** — write findings into `## Context` and record choices in `### Decisions` with rationale
22
- 4. **Hand off** — leave the Why stage ready for the spec-specialist to consolidate into a spec
22
+ 4. **Recommend a tier** — emit a `Tier: S|M|L` recommendation for this intent, using the
23
+ deterministic sizing rule (S = single mechanism or file cluster, hours; M = one subsystem,
24
+ about a day; L = cross-cutting or novel design), and record it in `### Decisions` (or
25
+ `## Insights` with the `(autonomous)` marker) with a one-line rationale. This is a
26
+ recommendation, not the stamp: the orchestrator reads it to pick the topology, and the
27
+ spec-specialist stamps the final `Tier:` line at the top of spec.md.
28
+ 5. **Hand off** — leave the Why stage ready for the spec-specialist to consolidate into a spec
23
29
 
24
30
  ## How You Work
25
31
 
@@ -36,6 +42,7 @@ END your turn with a structured completion report as your final message, per the
36
42
  - Decisions recorded in `### Decisions`, each with its one-line rationale
37
43
  - Context enriched: what was researched and the key findings
38
44
  - Open questions resolved, and any deliberately left for the spec
45
+ - Tier recommendation (`S|M|L`) and its one-line rationale
39
46
 
40
47
  ## Constraints
41
48
 
@@ -21,8 +21,23 @@ subagents keep their pinned tier and never resolve to Fable.
21
21
  ## Your Responsibilities
22
22
 
23
23
  1. **Set scope guards** — establish the intent, branch, and safe-by-default rules for the run
24
- 2. **Arm and verify the gate** — arm the lifecycle gate and confirm it is live before any code edit
25
- 3. **Sequence the team** dispatch ONE specialist per stage (brainstorming, spec-specialist, planner, executor) with a constructed context bundle
24
+ 2. **Size the intent at Why** — deterministically size S/M/L (S = single mechanism or file
25
+ cluster, hours; M = one subsystem, about a day; L = cross-cutting or novel design), then
26
+ pick the per-tier topology BEFORE How begins. For S/M the topology pick happens before
27
+ the single thinker even writes spec.md, so the orchestrator's own deterministic sizing
28
+ (informed by brainstorming's tier recommendation) drives that pre-How pick, not spec.md.
29
+ The `Tier: S|M|L` line stamped at the top of spec.md is the durable record of that
30
+ decision, not its input: convention-only, read by the orchestrator, never validated by
31
+ any gate or by doctor. Deterministic sizing keeps the two in agreement.
32
+ 3. **Arm and verify the gate** — arm the lifecycle gate and confirm it is live before any code edit
33
+ 4. **Sequence the team** — dispatch specialists per the chosen topology with a constructed
34
+ context bundle:
35
+ - S/M: ONE thinker agent, one boot, two stations — it writes spec.md, then plan.md +
36
+ checklist.md, in a single context. Sections may be one line each; plan.md carries the
37
+ checklist rationale inline; `actions/` files appear only for L. S may skip the QMD
38
+ discovery deposit when chain and sources are both empty. A sonnet executor implements.
39
+ - L: today's full team, one specialist per stage (brainstorming, spec-specialist, planner,
40
+ executor), each in a fresh context.
26
41
 
27
42
  **Dispatch-time model contract (belt-and-braces).** Each pinned agent already carries its
28
43
  `model:` in frontmatter, and Claude Code reads it at dispatch. Because read-at-dispatch is a
@@ -32,8 +47,13 @@ agents.models.<basename> --project <repo>`: project override, then global, then
32
47
  tier default) and pass it explicitly as the dispatch call's model parameter, alongside the
33
48
  spawn-preamble live-state injection. Never rely on the dispatched role's frontmatter alone. A
34
49
  resolved subagent model is never Fable.
35
- 4. **Gate each handoff** — check each stage deliverable against its exit criteria before handing to the next stage
36
- 5. **Run the final review** — at the final gate, dispatch an INDEPENDENT reviewer subagent (not a sixth standing role)
50
+ 5. **Gate each handoff** — check each stage deliverable against its exit criteria before handing to the next stage
51
+ 6. **Run the final review** — at the final gate, dispatch an INDEPENDENT reviewer subagent (not a sixth standing role)
52
+
53
+ Never-cut list at any tier: the independent reviewer (a separate agent, fresh context, never
54
+ the maker), `outcome.md` as truth of delivery, the delivery lock, worktree isolation, intent
55
+ creation via skill, INDEX as status truth, the QMD reindex at End. Lightness collapses
56
+ ceremony, never these guarantees.
37
57
 
38
58
  ## How You Work
39
59
 
@@ -23,7 +23,11 @@ When dispatched in auto mode you receive the standard Plastic spawn preamble (fr
23
23
 
24
24
  ## How You Work
25
25
 
26
- 1. Receive (input handoff): `plan.md`, `checklist.md`, and `actions/` from the planner
26
+ 1. Receive (input handoff): `plan.md` and `checklist.md` from the planner (plus
27
+ `ACTION_N.md` files inside `actions/` at L; at S/M the `actions/` directory exists but
28
+ stays empty, so read the tier fork from the inline plan-as-checklist in plan.md
29
+ instead). For S/M intents you run on the sonnet default, the collapsed topology's
30
+ implementer; behavior is otherwise unchanged.
27
31
  2. Work one action at a time, preferring safe, non-destructive routes
28
32
  3. Edit project code (the gate is open now that plan and checklist exist)
29
33
  4. Run the full suite, iterate to zero failures and zero errors
@@ -18,8 +18,14 @@ When dispatched in auto mode you receive the standard Plastic spawn preamble (fr
18
18
 
19
19
  1. **Decompose the spec** — break the approach into ordered, independent actions
20
20
  2. **Write the plan** — produce `plan.md` with numbered tasks and verification
21
- 3. **Write self-contained actions** — one `actions/ACTION_N.md` per task, each runnable on its own
22
- 4. **Write the checklist** — `checklist.md` as the execution registry covering every action
21
+ 3. **Write self-contained actions, tier-forked**:
22
+ - S/M: `plan.md` carries the checklist rationale INLINE; do NOT write
23
+ `actions/ACTION_N.md` files. Sections may be one line each.
24
+ - L: keep today's shape — one self-contained `actions/ACTION_N.md` per task.
25
+ 4. **Write the checklist** — `checklist.md` as the execution registry covering every action.
26
+ `checklist.md` exists at every tier: the file set does not change by tier, only depth
27
+ (inline vs action files) and agent topology do. plan.md + checklist.md are the two files
28
+ that open the code gate at every tier.
23
29
 
24
30
  ## How You Work
25
31
 
@@ -36,6 +42,7 @@ END your turn with a structured completion report as your final message, per the
36
42
  - The ordered actions, one line each: what the action does and how it is verified
37
43
  - Decomposition rationale: why this order, and why the actions are independent
38
44
  - Checklist coverage: the item count, and that every action plus suite-green is covered
45
+ - Which tier shape was produced: inline plan-as-checklist (S/M) or full `actions/` (L)
39
46
 
40
47
  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.
41
48
 
@@ -45,3 +52,5 @@ The plan is an argument; the orchestrator gates on whether that argument is soun
45
52
  - You write only intent-store files (`plan.md`, `actions/`, `checklist.md`); no project code
46
53
  - The code gate stays closed until `plan.md` and `checklist.md` exist, so produce both
47
54
  - Keep each action self-contained so the executor can run them one at a time
55
+ - The `actions/` empty-directory git-tracking edge (present only within one same-session
56
+ local delivery) is out of scope; do not add a `.gitkeep` or a guard for it here
@@ -18,8 +18,16 @@ When dispatched in auto mode you receive the standard Plastic spawn preamble (fr
18
18
 
19
19
  1. **Consolidate the Why** — turn the enriched `## Context` and `### Decisions` into one spec
20
20
  2. **Follow the template** — produce `spec.md` with Problem, Goals, Non-Goals, Approach, Decisions, Acceptance Criteria
21
- 3. **Make it the contract** — the spec is what the planner and executor build against
22
- 4. **Hand off** leave a complete `spec.md` ready for the planner
21
+ 3. **Stamp the tier** — write a `Tier: S|M|L` line as the TOP line of spec.md, above the `#
22
+ Spec:` heading, taking the value from the orchestrator's sizing / the brainstorming
23
+ recommendation. This line is convention-only: read by the orchestrator, never validated by
24
+ any gate or by doctor. It is an extra top line, not a template field, so no template changes.
25
+ 4. **Accept collapsed sections at S/M** — a spec.md whose Problem, Goals, Non-Goals, Approach,
26
+ Decisions, or Acceptance Criteria sections are a single line each is still a complete
27
+ spec.md under the same-structure invariant; do not pad it. The gates check file existence
28
+ and realness, not artifact depth, so a collapsed-but-real spec passes.
29
+ 5. **Make it the contract** — the spec is what the planner and executor build against
30
+ 6. **Hand off** — leave a complete `spec.md` ready for the planner
23
31
 
24
32
  ## How You Work
25
33
 
@@ -36,6 +44,7 @@ END your turn with a structured completion report as your final message, per the
36
44
  - The spec sections produced (Problem, Goals, Non-Goals, Approach, Decisions, Acceptance Criteria)
37
45
  - How the recorded decisions resolved into the chosen approach
38
46
  - The acceptance-criteria count, so the planner knows the surface to cover
47
+ - The stamped `Tier:` value
39
48
 
40
49
  ## Constraints
41
50
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zalom/plastic",
3
- "version": "1.0.0-beta.31",
3
+ "version": "1.0.0-beta.33",
4
4
  "description": "Intent-driven idea development system for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -491,19 +491,45 @@ module Bridge
491
491
  append_savepoint_line(intent_dir, "Done", disposition, now)
492
492
  end
493
493
 
494
+ # --- Tier convenience line (intent 130, D-A) ------------------------------
495
+ #
496
+ # spec.md's top `Tier: S|M|L` line is the single authoritative record of an
497
+ # intent's proportional-auto-sizing tier (see PLASTIC.md `## Tiers`). This
498
+ # reads that line only; it never validates or enforces it (convention-only,
499
+ # matching the skill and agent contracts). Returns nil when spec.md is
500
+ # absent, empty, or its first line does not match, so a missing/malformed
501
+ # Tier line changes nothing about existing rebuild behavior.
502
+ def self.savepoint_tier(intent_dir)
503
+ path = File.join(intent_dir, "spec.md")
504
+ return nil unless File.exist?(path)
505
+ first = File.open(path, &:gets)
506
+ return nil if first.nil?
507
+ m = first.chomp.strip.match(/\ATier:\s*(S|M|L)\z/)
508
+ m && m[1]
509
+ end
510
+
494
511
  # Reconstruct the ledger from files on disk (timestamps from mtimes), in
495
512
  # stage order, overwriting savepoint.md. Returns the number of lines written.
513
+ # When spec.md carries a Tier line, one convenience `Tier <value>` line is
514
+ # echoed right after the spec.md milestone line (same mtime), so the tier
515
+ # survives a rebuild without becoming a new source of truth.
496
516
  def self.rebuild_savepoint(intent_dir)
497
517
  ordered = [
498
518
  File.basename(intent_file(intent_dir)),
499
519
  "spec.md", "plan.md", "checklist.md", "outcome.md",
500
520
  ]
501
- lines = ordered.filter_map do |basename|
521
+ lines = ordered.flat_map do |basename|
502
522
  path = File.join(intent_dir, basename)
503
- next unless stage_file_present?(path)
523
+ next [] unless stage_file_present?(path)
504
524
  stage, milestone = savepoint_milestone(intent_dir, basename)
505
- next unless milestone
506
- "#{File.mtime(path).utc.iso8601} #{stage} #{milestone}\n"
525
+ next [] unless milestone
526
+ stamp = File.mtime(path).utc.iso8601
527
+ entry = "#{stamp} #{stage} #{milestone}\n"
528
+ if basename == "spec.md" && (tier = savepoint_tier(intent_dir))
529
+ [entry, "#{stamp} Tier #{tier}\n"]
530
+ else
531
+ [entry]
532
+ end
507
533
  end
508
534
  File.write(File.join(intent_dir, SAVEPOINT_FILE), lines.join)
509
535
  lines.length
@@ -1003,10 +1029,15 @@ module Bridge
1003
1029
 
1004
1030
  # Redirections: `> path` / `>> path`, but not fd dups (`2>&1`) or /dev/null.
1005
1031
  # A leading digit (fd number) before > is fine; `>&` is a dup and excluded.
1032
+ # Quote- and heredoc-aware: a `>` inside a single/double-quoted span or inside a
1033
+ # heredoc body is NOT a redirect. Fails OPEN (returns []) on an ambiguous parse
1034
+ # (unbalanced quote or unterminated heredoc) rather than guessing a target.
1006
1035
  def self.bash_redirect_targets(command)
1036
+ return [] unless command.is_a?(String)
1037
+ scannable = scannable_redirect_text(command)
1038
+ return [] if scannable.nil? # ambiguous parse -> fail open
1007
1039
  targets = []
1008
- # Match optional leading fd digits, then > or >>, not followed by & , then path.
1009
- command.scan(/\d*>>?(?!&)\s*([^\s;|&<>]+)/) do |m|
1040
+ scannable.scan(/\d*>>?(?!&)\s*([^\s;|&<>]+)/) do |m|
1010
1041
  path = m[0]
1011
1042
  next if path.nil? || path.empty?
1012
1043
  next if dev_null?(path)
@@ -1015,6 +1046,76 @@ module Bridge
1015
1046
  targets
1016
1047
  end
1017
1048
 
1049
+ # Return a copy of `command` in which single-quoted spans, double-quoted spans,
1050
+ # and heredoc bodies are blanked to spaces, so the redirect regex only ever sees
1051
+ # operators that are genuinely outside quotes and heredoc bodies. Returns nil on
1052
+ # an ambiguous parse (a line ends inside a quote, or a heredoc is never closed).
1053
+ def self.scannable_redirect_text(command)
1054
+ out = +""
1055
+ pending = [] # queue of {word:, dash:} heredoc terminators awaiting bodies
1056
+ command.split("\n", -1).each do |line|
1057
+ if pending.any?
1058
+ term = pending.first
1059
+ probe = term[:dash] ? line.sub(/\A\t+/, "") : line
1060
+ pending.shift if probe == term[:word]
1061
+ out << "\n" # heredoc body/terminator line contributes nothing scannable
1062
+ next
1063
+ end
1064
+ masked, openers, balanced = mask_redirect_line(line)
1065
+ return nil unless balanced # unbalanced quote on this line -> ambiguous
1066
+ out << masked << "\n"
1067
+ pending.concat(openers)
1068
+ end
1069
+ return nil if pending.any? # unterminated heredoc -> ambiguous
1070
+ out
1071
+ end
1072
+
1073
+ # Walk one normal (non-heredoc-body) line, masking quoted spans to spaces and
1074
+ # recognizing heredoc openers. Returns [masked_line, [heredoc_openers], balanced?].
1075
+ def self.mask_redirect_line(line)
1076
+ out = +""
1077
+ openers = []
1078
+ state = :normal
1079
+ i = 0
1080
+ n = line.length
1081
+ while i < n
1082
+ c = line[i]
1083
+ case state
1084
+ when :single
1085
+ out << " "
1086
+ state = :normal if c == "'"
1087
+ i += 1
1088
+ when :double
1089
+ if c == "\\" && i + 1 < n
1090
+ out << " "
1091
+ i += 2
1092
+ else
1093
+ out << " "
1094
+ state = :normal if c == '"'
1095
+ i += 1
1096
+ end
1097
+ else # :normal
1098
+ if c == "'"
1099
+ out << " "; state = :single; i += 1
1100
+ elsif c == '"'
1101
+ out << " "; state = :double; i += 1
1102
+ elsif c == "<" && line[i + 1] == "<"
1103
+ m = line[i..].match(/\A<<(-?)\s*("|')?([A-Za-z_][A-Za-z0-9_]*)\2?/)
1104
+ if m
1105
+ openers << { word: m[3], dash: m[1] == "-" }
1106
+ out << (" " * m[0].length)
1107
+ i += m[0].length
1108
+ else
1109
+ out << "<<"; i += 2 # here-string / no valid word: leave as-is
1110
+ end
1111
+ else
1112
+ out << c; i += 1
1113
+ end
1114
+ end
1115
+ end
1116
+ [out, openers, state == :normal]
1117
+ end
1118
+
1018
1119
  def self.bash_utility_targets(segment)
1019
1120
  tokens = segment.strip.split(/\s+/)
1020
1121
  return [] if tokens.empty?
package/scripts/update.rb CHANGED
@@ -53,18 +53,22 @@ class Update < InstallerCore
53
53
  end
54
54
  puts "\u{2b06}\u{fe0f} Updating Plastic #{iv} \u{2192} #{res[:target]}"
55
55
  exit_code = perform_switch(res[:target], agent_args(argv))
56
- run_post_update_doctor if exit_code == 0
56
+ run_post_update_doctor(full: argv.include?("--full-doctor")) if exit_code == 0
57
57
  exit_code
58
58
  end
59
59
  end
60
60
 
61
- # Run the full doctor after a successful update and print a human-readable
62
- # summary. Informational only: does not raise and does not affect the update's
63
- # exit code. Accepts injected `doctor` and `out` for hermetic unit tests.
64
- def run_post_update_doctor(doctor: nil, out: $stdout)
61
+ # Run doctor after a successful update and print a human-readable summary.
62
+ # Defaults to the fast core tier (agent registration + core files + manifest
63
+ # sync, binary pass|fail, no store walk) so a newcomer's first post-update
64
+ # run is not buried in convention warns they cannot act on. `full: true`
65
+ # (via `--full-doctor`) runs the complete store walk instead. Informational
66
+ # only: does not raise and does not affect the update's exit code. Accepts
67
+ # injected `doctor` and `out` for hermetic unit tests.
68
+ def run_post_update_doctor(doctor: nil, out: $stdout, full: false)
65
69
  doctor ||= Doctor.new
66
- out.puts "\nRunning full doctor after update..."
67
- result = doctor.run_checks("claude")
70
+ out.puts full ? "\nRunning full doctor after update..." : "\nRunning core doctor after update..."
71
+ result = full ? doctor.run_checks("claude") : doctor.run_core_checks("claude")
68
72
  s = result[:summary]
69
73
  out.puts " Doctor status: #{result[:status]} " \
70
74
  "(pass: #{s[:pass]}, warn: #{s[:warn]}, fail: #{s[:fail]}, total: #{s[:total]})"
@@ -152,6 +156,11 @@ class Update < InstallerCore
152
156
  Agent options (default: --claude):
153
157
  --claude --codex --hermes --all
154
158
 
159
+ Post-update doctor:
160
+ By default, a successful update runs the fast core doctor sync (agent
161
+ registration, core files, manifest — binary pass|fail, no store walk).
162
+ --full-doctor Run the full doctor (complete store walk) after updating.
163
+
155
164
  Behaviour:
156
165
  No flag advances to the next version on your current channel. Switching toward a
157
166
  more stable channel is frictionless; switching toward bleeding edge is confirmed.
@@ -41,6 +41,27 @@ intents, then open the authoritative intent file for the hit you take over. The
41
41
  when QMD is absent, so fall back to the existing INDEX.md / file scan. (This is discovery; the
42
42
  reindex step under Completion is separate.)
43
43
 
44
+ ## Tiers (proportional auto sizing)
45
+
46
+ Auto mode sizes every intent S/M/L at Why, deterministically, then matches agent topology
47
+ and artifact depth to that size. Extended walkthrough: `references/tiers.md`.
48
+
49
+ 1. **Sizing rule.** S = single mechanism or file cluster (hours). M = one subsystem (a
50
+ day). L = cross-cutting or novel design.
51
+ 2. **Two levers.** Speed comes only from artifact content DEPTH and agent TOPOLOGY. The
52
+ same-structure invariant (same file set, stage order, gates, savepoint ledger) holds at
53
+ every tier and in both modes. A three-line spec.md is still a spec.md, in the same
54
+ place, under the same gate.
55
+ 3. **Per-tier topology.** S/M: one thinker agent, one boot, two stations, sonnet
56
+ executor, `actions/` skipped; S may also skip the QMD discovery deposit when chain and
57
+ sources are both empty. L: today's full team (`## Team Spin-Up` below).
58
+ 4. **Never-cut list**, any tier or mode: the independent reviewer (separate agent, fresh
59
+ context, never the maker), `outcome.md` as truth of delivery, the delivery lock,
60
+ worktree isolation, intent creation via skill, INDEX as status truth, the QMD reindex
61
+ at End. Lightness is about ceremony, never about these guarantees.
62
+ 5. **Tier record.** `Tier: S|M|L` at the top of spec.md. Convention-only: read by the
63
+ orchestrator, never validated by any gate or by doctor.
64
+
44
65
  ## Arm the Lifecycle Gate (do this FIRST)
45
66
 
46
67
  Immediately after selecting the intent — before any other work — arm auto mode. This
@@ -77,6 +98,8 @@ Honor the cycle: What → Why (spec.md) → How (plan.md + actions/ + checklist.
77
98
 
78
99
  ## Team Spin-Up
79
100
 
101
+ This is the L-tier shape (see `## Tiers` above); S/M collapse it to one thinker agent.
102
+
80
103
  Auto mode spins up exactly ONE enforcer-led team per intent. The plastic-enforcer IS this orchestrator (you), not a separately dispatched agent, which avoids the who-gates-the-gater regress.
81
104
 
82
105
  Roster (one role per cycle stage):
@@ -161,9 +184,14 @@ Then proceed to How.
161
184
 
162
185
  ## How Phase
163
186
 
187
+ This is the L-tier shape (see `## Tiers` above); S/M skip step 3 and fold the checklist
188
+ rationale into plan.md inline. The `actions/` directory itself is scaffolded empty at
189
+ intent birth and persists at every tier; only writing `ACTION_N.md` files into it is L
190
+ only (S/M leave the directory empty).
191
+
164
192
  1. If `superpowers:writing-plans` is available as a skill, delegate plan creation to it. Tell it the plan saves to the active intent's directory (not `docs/superpowers/plans/`).
165
193
  2. Otherwise, write `plan.md` directly — implementation plan with numbered tasks
166
- 3. Create `actions/` directory with `ACTION_N.md` files (one per task, self-contained)
194
+ 3. Write `ACTION_N.md` files into the existing `actions/` directory (one per task, self-contained) — L only
167
195
  4. Write `checklist.md` — execution registry with checkboxes covering all actions
168
196
 
169
197
  Then proceed to Exec.
@@ -293,3 +321,4 @@ If the agent gets stuck (can't resolve a gap, dependency is missing, tests fail
293
321
  ## References
294
322
 
295
323
  - Read `references/agent-architecture.md` for the full team model (the 5-role enforcer-led team, per-stage handoffs, gate ownership, headless note, solo fallback) and the orchestrator hierarchy (Main Orchestrator, Project Orchestrators, coordination loop) when spinning up the team or understanding autonomous delivery scope
324
+ - Read `references/tiers.md` for the extended per-tier walkthrough (S/M/L worked examples, the collapsed one-thinker flow, the QMD-skip case for S) and rationale
@@ -0,0 +1,77 @@
1
+ # Tiers — Extended Walkthrough
2
+
3
+ This is the detail behind `## Tiers` in SKILL.md. The five points there (sizing rule, two
4
+ levers, per-tier topology, never-cut list, tier record) are the authoritative contract;
5
+ this file only expands on them with examples and rationale.
6
+
7
+ ## Why sizing exists
8
+
9
+ Auto mode used to run every intent through the same full-ceremony team: brainstorming,
10
+ spec-specialist, planner, executor, and an independent reviewer, each a separate agent
11
+ booting a fresh context. For a large or novel intent that ceremony earns its cost. For a
12
+ small intent (one file, one mechanism, an hour of real work) the ceremony dominates:
13
+ overhead runs about 3 to 4 times the actual work time, roughly flat regardless of size, so
14
+ it hurts small intents the most. Sizing at Why and matching the topology to that size drops
15
+ small-intent ceremony toward about 1.5x work time, without touching structure, gates, or
16
+ the savepoint ledger.
17
+
18
+ ## Sizing rule, worked examples
19
+
20
+ - S: fixing one script's argument parsing, adding one skill section, a single bug fix
21
+ confined to one file. Hours of work.
22
+ - M: adding a new agent role file end to end, a subsystem with a handful of touched files
23
+ and one clear seam. About a day.
24
+ - L: cross-cutting prose or code that spans the skill contract plus multiple agent role
25
+ files (like this intent, 130), or any genuinely novel design with no established pattern
26
+ to follow.
27
+
28
+ ## S/M collapsed topology, in detail
29
+
30
+ One thinker agent boots ONCE and stays in a single context for two stations:
31
+
32
+ 1. Station 1 — writes `spec.md` (collapsed sections allowed, one line each is valid).
33
+ 2. Station 2 — writes `plan.md` + `checklist.md` in the SAME context (no reboot). plan.md
34
+ carries the checklist rationale inline instead of separate `actions/ACTION_N.md` files.
35
+ `actions/` is not created for S/M.
36
+
37
+ Then a sonnet executor (a fresh dispatch, this is the one topology split that always
38
+ happens) implements from plan.md + checklist.md, checks off items, appends `## Insights`,
39
+ and drives the suite green, exactly as it does for L.
40
+
41
+ The independent reviewer still runs at the final gate for S/M, in its own fresh context,
42
+ never the maker. This is on the never-cut list; it does not collapse.
43
+
44
+ S may skip the QMD discovery deposit (normally a `plastic-intent-discovery` pass before
45
+ Why) when the intent's `chain` and `sources` are both empty in frontmatter. With no graph
46
+ edges there is nothing to discover, so the deposit is pure overhead; a one-line context
47
+ note ("no chain/sources, discovery skipped") takes its place.
48
+
49
+ ## L topology, unchanged
50
+
51
+ L keeps today's full multi-agent team as described in `## Team Spin-Up`: brainstorming,
52
+ spec-specialist, planner, executor, each a separate agent in its own fresh context, plus
53
+ the independent reviewer at the final gate. Cross-cutting or novel work benefits from the
54
+ separate perspectives and the handoff discipline; the ceremony is not waste at this size.
55
+
56
+ ## Same-structure invariant, why it is non-negotiable
57
+
58
+ The file set, stage order, gates, and savepoint ledger never change by tier. Renaming or
59
+ skipping files to save time would require new gate logic per tier and would break state
60
+ derivability (the gates and the savepoint rebuild depend on a fixed file set at fixed
61
+ paths). So the only two levers are content depth and agent topology; structure is the
62
+ constant that keeps every tier auditable the same way.
63
+
64
+ ## Tier record, mechanics
65
+
66
+ The tier is recorded as a `Tier: S|M|L` line at the very top of spec.md, above the `#
67
+ Spec:` heading. It is convention-only: the orchestrator reads it to pick topology, and
68
+ nothing else depends on it. No frontmatter schema change, no new file, no doctor rule, no
69
+ gate check. If a later intent wants doctor or a gate to validate the line, that is a
70
+ separate, explicit follow-up; this system deliberately adds no new operational surface.
71
+
72
+ ## Never-cut list, the safety floor
73
+
74
+ At any tier or mode: the independent reviewer (separate agent, fresh context, never the
75
+ maker), `outcome.md` as the truth of delivery, the delivery lock, worktree isolation,
76
+ intent creation via skill, INDEX as status truth, the QMD reindex at End. These are
77
+ predictability and safety guarantees, not ceremony, and lightness never touches them.
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: plastic-roadmap
3
+ description: Use when the user wants to plan a delivery batch, order waves of intents, ship a batch of tickets in one go, track a named collection of intents toward a goal, or asks for a "roadmap". Creates and maintains a roadmap file, a delivery-side collection of intents (the counterpart to a release), separate from INDEX.md status tracking.
4
+ ---
5
+
6
+ # Roadmap
7
+
8
+ A roadmap is a named, ordered, delivery-side collection of intents: the delivery-side counterpart
9
+ to a release (completion-side, `CHANGELOG.md`). It lives at `roadmaps/{slug}.md`, a sibling of
10
+ `INDEX.md` wherever `INDEX.md` lives: the global tier's `~/.plastic/roadmaps/` (beside
11
+ `~/.plastic/INDEX.md`), or a project's root, `~/.plastic/projects/{slug}/roadmaps/` (beside that
12
+ project's `INDEX.md` and `project.yml`). It never sits inside `store/`, which holds intent
13
+ directories, not project artifacts.
14
+
15
+ A roadmap file has four parts: a title/meta header, `## Goal` (prose), `## Waves` (ordered; entries
16
+ inside a wave are parallel-safe, waves run sequentially), and an append-only dated `## Log`. Each
17
+ wave entry mirrors that intent's status in `INDEX.md` (`queued`/`delivering`/`delivered`/
18
+ `abandoned`/`blocked`).
19
+
20
+ **`INDEX.md` is the single writer of intent status; on any conflict INDEX wins and the roadmap
21
+ entry is corrected to match.**
22
+
23
+ The skill operates on the file directly via Read/Edit; no helper script.
24
+
25
+ ## Verbs
26
+
27
+ | Verb | When | Mechanics |
28
+ |------|------|-----------|
29
+ | Create | user wants to start a new roadmap / plan a delivery batch | `references/operations.md#create` |
30
+ | Add / reorder entries | user wants to add intents to a wave or resequence waves | `references/operations.md#add--reorder-entries` |
31
+ | Sync status mirror | an entry's status may be stale against INDEX | `references/operations.md#sync-status-mirror` |
32
+ | Append log line | a roadmap event just happened (created, wave done, closed) | `references/operations.md#append-a-log-line` |
33
+ | Read / consume | a human or a coordinator needs the roadmap's current state | `references/operations.md#read--consume` |
34
+ | Close / archive | the roadmap's `## Goal` is reached | `references/operations.md#close--archive` |
35
+
36
+ See `references/file-format.md` for the exact entry-line shape, status vocabulary, checkbox/log
37
+ format, and a worked example. See `references/operations.md` for step-by-step mechanics of each
38
+ verb above.
39
+
40
+ ## Notes
41
+
42
+ - File location and the four-section shape are identical across tiers; do not invent a different
43
+ layout per project. The general rule: `roadmaps/` is a sibling of `INDEX.md`, wherever `INDEX.md`
44
+ lives.
45
+ - `## Goal` is a checkable prose condition read by a human or agent, not an executable checker.
46
+ - Wave entries render as checkboxes (`- [x] ... — delivered` / `- [ ] ... — <status>`); a human
47
+ reading cold should see shipped/running/next within a minute. `## Log` lines are one-sentence,
48
+ EM-to-CTO-voice, dated, and link each entry-intent's `outcome.md` (lossless-by-reference).
49
+ - Additive: this skill introduces no gate, lock, or hook, and does not change `INDEX.md`'s section
50
+ list or the intent frontmatter schema.
51
+ - Closing a roadmap moves it to `roadmaps/archived/{slug}.md` so `roadmaps/` lists only live ones.
@@ -0,0 +1,91 @@
1
+ # Roadmap File Format
2
+
3
+ ## Location
4
+
5
+ `roadmaps/{slug}.md`, a sibling of `INDEX.md`, wherever `INDEX.md` lives. For the global tier
6
+ that is `~/.plastic/roadmaps/{slug}.md` (beside `~/.plastic/INDEX.md`); for any project it is
7
+ that project's root, `~/.plastic/projects/{slug}/roadmaps/{slug}.md` (beside that project's
8
+ `INDEX.md` and `project.yml`). `roadmaps/` never sits inside `store/`: `store/` holds intent
9
+ directories, not project artifacts. Create the `roadmaps/` directory the first time a tier gets a
10
+ roadmap.
11
+
12
+ `roadmaps/` lists only live (open or in-flight) roadmaps. Once a roadmap's `## Goal` is reached,
13
+ its file moves to `roadmaps/archived/{slug}.md` (see Close/archive in `operations.md`); the
14
+ `archived/` subdirectory is scaffolded once, alongside `roadmaps/`, with a `.gitkeep`.
15
+
16
+ ## The four sections (in order)
17
+
18
+ 1. **Title/meta header** — `# Roadmap: <name>` plus a one-line meta sentence naming what the
19
+ roadmap delivers and which tier (project or global) it lives in.
20
+ 2. **`## Goal`** — a checkable prose condition: one or a few sentences a human or coordinator reads
21
+ to decide the roadmap is done. Not an executable checker, not a list of tasks.
22
+ 3. **`## Waves`** — ordered waves (`### Wave 1`, `### Wave 2`, ...). Entries inside a wave are
23
+ parallel-safe (can be dispatched together); waves run top to bottom, sequentially (wave 2 does
24
+ not start until wave 1's entries are no longer `queued`/`delivering`).
25
+ 4. **`## Log`** — append-only, dated, one line per event. Newest entry at the bottom. Never edit or
26
+ remove an existing log line.
27
+
28
+ ## Entry line shape
29
+
30
+ One line per intent, inside its wave, as a Markdown checkbox:
31
+
32
+ ```
33
+ - [x] <intent-id> <title> — delivered
34
+ - [ ] <intent-id> <title> — <status>
35
+ ```
36
+
37
+ `<intent-id>` and `<title>` match the intent's `INDEX.md` entry (terse, not a summary). The
38
+ checkbox is checked (`[x]`) once `<status>` is `delivered`, unchecked (`[ ]`) for every other
39
+ status. The checkbox is a rendering of the mirrored status token, not a second piece of state: a
40
+ human scanning the file sees at a glance what shipped (checked) and what has not (unchecked),
41
+ while the trailing token still carries the precise state (`queued`/`delivering`/`blocked`/
42
+ `abandoned`) when unchecked.
43
+
44
+ ## Status vocabulary
45
+
46
+ `queued` | `delivering` | `delivered` | `abandoned` | `blocked`
47
+
48
+ Status is a **mirror** of `INDEX.md`. `INDEX.md` is the single writer of intent status; on any
49
+ conflict INDEX wins and the roadmap entry (both its token and its checkbox) is corrected to match
50
+ it. The roadmap never sets a status that INDEX does not already reflect.
51
+
52
+ ## Log line shape
53
+
54
+ One line per event, starting `YYYY-MM-DD HH:MM UTC` (human-readable, sortable, zone-explicit so
55
+ same-day parallel deliveries can still be ordered), in plain-language EM-to-CTO voice: what shipped
56
+ and why it matters to a non-expert reader, no jargon or internal codenames, ending with a link to
57
+ that entry-intent's `outcome.md`:
58
+
59
+ ```
60
+ - <YYYY-MM-DD HH:MM UTC> <one plain-language sentence: what shipped, its impact> — see store/<id>--<slug>/outcome.md
61
+ ```
62
+
63
+ The log line never restates `outcome.md` detail; it points at it (lossless-by-reference). This
64
+ complements, and does not replace, `INDEX.md`'s `## Completed` section or `CHANGELOG.md`.
65
+
66
+ ## Worked example
67
+
68
+ ```
69
+ # Roadmap: Stable 1.0
70
+
71
+ Delivery-side collection of intents that close out the pre-1.0 hardening pass, plastic project store.
72
+
73
+ ## Goal
74
+ All intents below are delivered, the suite is green, and a 1.0.0 release is cut.
75
+
76
+ ## Waves
77
+ Entries in a wave are parallel-safe; waves run top to bottom. The checkbox tracks delivered/not;
78
+ the token after the em-dash carries the precise mirrored status (queued | delivering | delivered |
79
+ abandoned | blocked); INDEX wins on any conflict.
80
+
81
+ ### Wave 1
82
+ - [x] 121 Fix bash gate redirect parsing — delivered
83
+ - [ ] 130 Proportional cycle tiers — delivering
84
+
85
+ ### Wave 2
86
+ - [x] 124 Roadmap feature — delivered
87
+
88
+ ## Log
89
+ - 2026-07-06 14:32 UTC Shipped the bash-gate redirect fix so quoted arrows and heredoc trailers
90
+ stop blocking legitimate commits — see store/121--fix-bash-gate-redirect-parsing/outcome.md.
91
+ ```
@@ -0,0 +1,78 @@
1
+ # Roadmap Operations
2
+
3
+ All six verbs operate on the Markdown file directly (Read/Edit). No helper script exists or is
4
+ needed; the file is small and the edits are mechanical.
5
+
6
+ **Human-comprehension goal.** Every operation below should leave the file such that a cold reader
7
+ (no INDEX.md, no intent directories open) can answer "what's shipped, what's running, what's
8
+ next" in under a minute, just from this one file.
9
+
10
+ ## Create
11
+
12
+ 1. Pick a `slug` (kebab-case, descriptive) and a `title`.
13
+ 2. Resolve the tier root: the directory that holds `INDEX.md` (a project's root, beside
14
+ `project.yml`, or `~/.plastic/` for the global tier). `roadmaps/` is always a sibling of
15
+ `INDEX.md`, never inside `store/`. Create `roadmaps/` there if it does not exist yet.
16
+ 3. Copy `templates/roadmap.md` to `roadmaps/{slug}.md`.
17
+ 4. Fill the header (`# Roadmap: <title>` + the one-line meta) and write a real `## Goal` prose
18
+ condition.
19
+ 5. Add at least one `## Waves` wave with real entries (see Add / reorder below), each entry's
20
+ status mirroring that intent's current `INDEX.md` status.
21
+ 6. Append the first `## Log` line, a short `YYYY-MM-DD HH:MM UTC`-prefixed plain-language note
22
+ that the roadmap was created.
23
+
24
+ ## Add / reorder entries
25
+
26
+ - **Add**: append an entry line (`- <intent-id> <title> — <status>`) to the target wave. Pick the
27
+ intent's title and status straight from `INDEX.md`.
28
+ - **New wave**: add a new `### Wave N` heading after the last wave; entries in it are gated behind
29
+ every earlier wave's entries leaving `queued`/`delivering`.
30
+ - **Reorder**: move an entry line to a different wave, or move a `### Wave` heading (with its
31
+ entries) earlier or later. Reordering never changes an entry's status; it only changes when the
32
+ entry is eligible to run.
33
+ - After any add/reorder, append a `## Log` line describing the change (e.g.
34
+ `- <YYYY-MM-DD HH:MM UTC> added 132 to wave 2`).
35
+
36
+ ## Sync status mirror
37
+
38
+ 1. Read the intent's real status from `INDEX.md` (`## Active`, `## Future`, `## Completed`, or
39
+ `## Abandoned`).
40
+ 2. Compare to the roadmap entry's `<status>` token.
41
+ 3. If they differ, **INDEX wins**: rewrite the roadmap entry's status token to match INDEX, and
42
+ flip its checkbox in the same edit (`[x]` when the new status is `delivered`, `[ ]` otherwise).
43
+ Never edit INDEX.md from the roadmap skill; the roadmap is a mirror, not a second writer.
44
+ 4. Append a `## Log` line recording the change. When the new status is `delivered`, write the
45
+ one-line EM-to-CTO entry described in `file-format.md` (date, what shipped and its impact in
46
+ plain language, then a link to that intent's `outcome.md`). For other transitions, write a
47
+ short dated plain-language line (no codenames, no jargon).
48
+
49
+ ## Append a log line
50
+
51
+ - One line per event, starting `YYYY-MM-DD HH:MM UTC`, appended at the bottom of `## Log`. Never
52
+ edit or delete an existing line (append-only).
53
+ - Every line is plain language a non-expert can read, never a codename or a raw `field -> value`.
54
+ A delivery event follows the EM-to-CTO one-line shape with an `outcome.md` link (see
55
+ `file-format.md`); bookkeeping events (created, an intent added to a wave, a wave completed, a
56
+ roadmap closed) are short dated plain-language lines.
57
+
58
+ ## Read / consume
59
+
60
+ - A human reading the file gets the current picture directly: `## Goal` for the target, `## Waves`
61
+ for what is queued/delivering/delivered per wave (checkboxes give the shipped/not-shipped view at
62
+ a glance), `## Log` for a one-line, plain-language history with a link into each intent's
63
+ `outcome.md` for detail.
64
+ - A future coordinator (for example, an auto-mode dispatcher) reads `## Waves` top to bottom:
65
+ a wave is eligible to dispatch once every entry in the previous wave is no longer
66
+ `queued`/`delivering`; within an eligible wave, entries still `queued` are parallel-dispatchable.
67
+ Always re-sync against `INDEX.md` before dispatch decisions, since INDEX is the source of truth.
68
+
69
+ ## Close / archive
70
+
71
+ 1. Confirm the roadmap's `## Goal` prose condition is met (every entry `delivered` or explicitly
72
+ `abandoned` with a recorded reason, plus whatever else the goal states).
73
+ 2. Create `roadmaps/archived/` beside `roadmaps/` (both siblings of `INDEX.md`) if it does not
74
+ exist yet.
75
+ 3. Move the file: `roadmaps/{slug}.md` -> `roadmaps/archived/{slug}.md`. `roadmaps/` itself then
76
+ lists only live (open or in-flight) roadmaps.
77
+ 4. Append the final `## Log` line before or as part of the move:
78
+ `- <YYYY-MM-DD HH:MM UTC> roadmap closed`.
@@ -0,0 +1,30 @@
1
+ # Roadmap: <name>
2
+
3
+ (one-line meta: what this roadmap delivers, and which tier it lives in. `roadmaps/` is a sibling
4
+ of `INDEX.md` — a project's root or the global `~/.plastic/`, never inside `store/`. When this
5
+ roadmap's goal is reached, move this file from `roadmaps/{slug}.md` to
6
+ `roadmaps/archived/{slug}.md`; `roadmaps/` itself lists only live roadmaps.)
7
+
8
+ ## Goal
9
+ (a checkable prose condition — one or a few sentences a human or coordinator reads to decide the
10
+ roadmap is done. Not an executable checker.)
11
+
12
+ ## Waves
13
+ Entries in a wave are parallel-safe; waves run top to bottom. The checkbox is checked once an entry
14
+ is delivered, unchecked otherwise; the trailing token after the em-dash is the precise mirrored
15
+ status (queued | delivering | delivered | abandoned | blocked) from INDEX.md. INDEX always wins on
16
+ any conflict between the checkbox/token here and INDEX's real status.
17
+
18
+ ### Wave 1
19
+ - [ ] <intent-id> <title> — queued
20
+ - [ ] <intent-id> <title> — queued
21
+
22
+ ### Wave 2
23
+ - [x] <intent-id> <title> — delivered
24
+
25
+ ## Log
26
+ (append-only, dated, one line per event. Each line is one plain-language, EM-to-CTO-voice sentence:
27
+ what shipped and its impact for a non-expert reader, no jargon or internal codenames, ending with a
28
+ link to that entry-intent's `outcome.md`. Never restate outcome detail here; link to it instead.
29
+ Newest at the bottom.)
30
+ - 2026-01-01 00:00 UTC Shipped the first wave of this roadmap; see store/<intent-id>--<slug>/outcome.md.