@zalom/plastic 1.1.0 → 1.1.2

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 (63) hide show
  1. package/PLASTIC.md +12 -9
  2. package/README.md +3 -3
  3. package/agents/plastic-enforcer.md +8 -4
  4. package/agents/plastic-executor.md +5 -5
  5. package/agents/plastic-future-intent-researcher.md +1 -1
  6. package/agents/plastic-planner.md +15 -11
  7. package/hooks/check-update +1 -1
  8. package/hooks/continue +1 -1
  9. package/package.json +1 -1
  10. package/scripts/dashboard.rb +29 -24
  11. package/scripts/doctor.rb +180 -5
  12. package/scripts/hook-continue +3 -3
  13. package/scripts/install.rb +2 -1
  14. package/scripts/lib/bridge.rb +114 -11
  15. package/scripts/lib/dashboard_banner.rb +8 -9
  16. package/scripts/lib/installer_core.rb +12 -3
  17. package/scripts/lib/legacy_bookend_amnesty.rb +35 -0
  18. package/scripts/lib/release_guard.rb +62 -0
  19. package/scripts/lib/roadmap_queue.rb +285 -0
  20. package/scripts/lib/roadmap_savepoint.rb +213 -0
  21. package/scripts/lib/skill_lint.rb +304 -0
  22. package/scripts/lib/worktree.rb +21 -0
  23. package/scripts/new-intent +1 -0
  24. package/scripts/read-config +3 -3
  25. package/scripts/roadmap-next +44 -0
  26. package/scripts/roadmap-savepoint +64 -0
  27. package/scripts/skill-lint +50 -0
  28. package/skills/auto/SKILL.md +32 -11
  29. package/skills/auto/references/tiers.md +4 -3
  30. package/skills/continuing/SKILL.md +34 -0
  31. package/skills/continuing/evals/evals.json +91 -0
  32. package/skills/dashboard/SKILL.md +17 -14
  33. package/skills/dashboard/references/classification.md +3 -3
  34. package/skills/dashboard/templates/dashboard-global.md +8 -23
  35. package/skills/dashboard/templates/dashboard-project.md +7 -26
  36. package/skills/doctor/SKILL.md +1 -1
  37. package/skills/install/SKILL.md +10 -10
  38. package/skills/intent-continuing/SKILL.md +26 -68
  39. package/skills/intent-continuing/evals/evals.json +26 -26
  40. package/skills/intent-continuing/references/context-management.md +15 -19
  41. package/skills/intent-planning/SKILL.md +11 -11
  42. package/skills/intent-planning/evals/evals.json +20 -5
  43. package/skills/intent-planning/references/plan-format.md +9 -5
  44. package/skills/intent-savepoint/SKILL.md +12 -0
  45. package/skills/intent-starting/evals/evals.json +1 -1
  46. package/skills/project-continuing/SKILL.md +104 -0
  47. package/skills/project-continuing/evals/evals.json +100 -0
  48. package/skills/project-continuing/references/board-fill.md +33 -0
  49. package/skills/releasing/SKILL.md +48 -0
  50. package/skills/releasing/references/release-lines.md +105 -0
  51. package/skills/roadmap/SKILL.md +7 -1
  52. package/skills/roadmap/references/file-format.md +30 -1
  53. package/skills/roadmap/references/operations.md +26 -6
  54. package/skills/roadmap-continuing/SKILL.md +85 -0
  55. package/skills/roadmap-continuing/evals/evals.json +82 -0
  56. package/skills/roadmap-continuing/references/liveness-ranking.md +56 -0
  57. package/skills/skill-evaluating/evals/evals.json +1 -1
  58. package/skills/tutorial/references/track-1-guided.md +5 -4
  59. package/skills/tutorial/references/track-2-auto.md +1 -1
  60. package/skills/uninstall/SKILL.md +2 -2
  61. package/skills/update/SKILL.md +2 -2
  62. package/templates/config.yml +2 -1
  63. package/templates/index.md +4 -1
@@ -1,61 +1,42 @@
1
1
  ---
2
2
  name: plastic-intent-continuing
3
- description: 'Use when the user says "continue", "resume", or "pick up where we left off", or when starting a new session. Continues work with the latest project context: lands on the right dashboard, then presents choices. Boot (health check, core context, version, statusline) is owned by the SessionStart hook, not this skill. Does not drive work autonomously (that is plastic-auto).'
3
+ description: >-
4
+ Use when a specific intent is named to resume, by id or by description, or on `continuing
5
+ --intent {id}`. Reads that intent's savepoint ledger and hands off to plastic-intent-starting.
6
+ The general "continue" / new-session triggers belong to the plastic-continuing router, not
7
+ here, so a bare "continue" does not settle on this skill directly. Boot (health check, core
8
+ context, version, statusline) is owned by the SessionStart hook, not this skill. Does not
9
+ drive work autonomously (that is plastic-auto).
4
10
  user-invocable: true
5
11
  ---
6
12
 
7
- # Continuing
13
+ # Continuing (intent route)
8
14
 
9
- `plastic-intent-continuing` continues work. It presents the latest state via the dashboard and offers
10
- choices, then stops. It does NOT execute work autonomously (that is `plastic-auto`) and does
11
- NOT render the dashboard itself (it only invokes it).
15
+ `plastic-intent-continuing` is the intent route of `plastic-continuing`. It resumes ONE
16
+ specific intent by its savepoint ledger, then hands off to `plastic-intent-starting`. It does
17
+ NOT land on a dashboard and does NOT execute work autonomously (that is `plastic-auto`); both
18
+ of those are other routes' jobs.
12
19
 
13
20
  **Boot is not this skill's job.** The `hook-session-start` hook already runs by construction on
14
21
  every session start: it runs the core health check (`doctor --core`), primes `PLASTIC.md` +
15
- store/project state, and prints the `Plastic Core loaded v{version}` banner. The
22
+ store/project state, and prints the `Plastic Core loaded - v{version}` banner. The
16
23
  `plastic-statusline` hook sets the statusline. So by the time this skill runs, core is loaded
17
24
  and healthy (or the banner already warned otherwise). This skill picks up from there and
18
- continues work. This is the seam future continue-flags build on (see [[39]]).
25
+ resumes the named intent. This is the seam future continue-flags build on (see [[39]]).
19
26
 
20
27
  ## When to Use
21
- - UserPromptSubmit hook detects "continue" (automatic)
22
- - User says "continue", "resume", or "pick up where we left off"
23
- - Starting a new session and you want to resume work with the latest context
28
+ - A specific intent is named to resume, by id or by description
29
+ - `continuing --intent {id}`
24
30
 
25
31
  ## Determine Store
26
32
 
27
- 1. **Global store** `~/.plastic/INDEX.md` exists → global mode.
28
- 2. **Local store** a project store under `~/.plastic/projects/{slug}/` whose registered
33
+ 1. **Global store** - `~/.plastic/INDEX.md` exists → global mode.
34
+ 2. **Local store** - a project store under `~/.plastic/projects/{slug}/` whose registered
29
35
  path (in `~/.plastic/projects.yml`) matches the current working directory → project mode.
30
36
  The SessionStart hook already detects this; here you only need the slug to scope the
31
- dashboard.
37
+ named intent's store.
32
38
  3. If neither exists → announce "No Plastic store found. Run /plastic-install."
33
39
 
34
- ## Continue (present the dashboard)
35
-
36
- Land on the Markdown board via the `plastic-dashboard` skill. Rendering belongs there, not
37
- here — run the data payload and fill + present the matching template:
38
- - Project loaded → `ruby ~/.plastic/scripts/dashboard.rb project <slug> --data`
39
- - Otherwise → `ruby ~/.plastic/scripts/dashboard.rb continue --data`
40
-
41
- Fill the matching template from this skill's `templates/` and **present the filled Markdown
42
- in your reply** (every time, non-optional). If the reply does not contain the filled Markdown,
43
- the user sees nothing — tool-call stdout and hook `additionalContext` are both invisible to
44
- them. `hook-continue` also emits a one-line `systemMessage` summary as a hook-owned fallback;
45
- treat it as a floor only, never as a substitute for presenting the full board here. See
46
- `plastic-dashboard` for the fill rules and entry flow.
47
-
48
- The board load runs the scoped store check on every load (`doctor --store <scope>`): the
49
- global board runs `--store global` and a project board runs `--store <slug>`. The result
50
- arrives in the payload as `store_health`; surface it as a one-line store-health note. It is
51
- non-fatal (a warn or fail is shown as data, it does not block continuing).
52
-
53
- ### Then stop
54
- Present "here is the state, what next?" and wait. Offer active intents first, then future
55
- intents. Do not start executing work. The branches below are the only follow-ups:
56
- - User/agent names a specific intent to continue → **Conditional ledger-resume** (below).
57
- - User says "auto" / an agent is instructed to deliver → hand to `plastic-auto`.
58
-
59
40
  ## Conditional Ledger-Resume
60
41
 
61
42
  Fires ONLY when the user explicitly asks to continue a SPECIFIC intent, or an agent is
@@ -98,44 +79,21 @@ For that intent's directory:
98
79
  - "advance to the next lifecycle stage" (e.g. ledger shows Why/spec.md → next is How).
99
80
  - The newest `## Insights` entry supplies human-readable context (Insights are
100
81
  append-only, newest at the bottom).
101
- 5. **Announce and stop:**
82
+ 5. **Announce, then hand off to `plastic-intent-starting`:**
102
83
  ```
103
- Resuming intent [ID] [name]
84
+ Resuming intent [ID] - [name]
104
85
  Store: [global | project:<slug> | local]
105
86
  Stage: [from ledger last line]
106
87
  Next step: [first unchecked checklist item | advance to <stage>]
107
88
  Context: [newest ## Insights entry]
108
89
  Drift: [none | ledger rebuilt from filesystem]
109
90
  ```
110
- Then proceed with the next step. Autonomy is `plastic-auto`'s job if the intent's
111
- `## Insights` contains `(autonomous)` entries, it was being delivered autonomously; hand
112
- to `plastic-auto` to continue from the current stage.
113
-
114
- ## Priority Order
115
-
116
- 1. **Active intents first** — surface work in progress.
117
- 2. **Project context** — if in a registered project, show governing + tactical intents.
118
- 3. **Stale future intents** — surface for triage (see below).
119
- 4. **Fresh future intents** — offer as next work.
120
-
121
- ## Stale Future Intents
122
-
123
- If a future intent's `created` date is older than the configured `stale_threshold_days`
124
- (default 3), surface it for triage without taking action:
125
-
126
- ```
127
- Stale future intents (no action taken):
128
-
129
- - [ID — name] (X days old)
130
- a) Activate — start working on it now
131
- b) Abandon — mark as abandoned
132
- c) Defer to agent: implement | research | ideate
133
- d) Auto — go fully autonomous (invokes plastic-auto)
134
- ```
135
-
136
- When the user activates a future intent, move it to `## Active` in INDEX.md and auto-commit.
91
+ Hand off to `plastic-intent-starting`: it takes the lock, boards at this station, and is
92
+ where the single "auto or guided?" ask for the intent route lives, asked there exactly
93
+ once and never duplicated here. Its auto branch is the one that hands off to `plastic-auto`;
94
+ this skill never hands to `plastic-auto` directly.
137
95
 
138
96
  ## References
139
97
 
140
- - Read `references/context-management.md` for the full save/continue protocol and for
98
+ - Read `references/context-management.md` for the save/continue protocol and for
141
99
  debugging the resume flow.
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "skill_name": "plastic-intent-continuing",
3
- "notes": "Intent 36, updated for 36a (boot moved into hook-session-start; the skill is now work-continuation only). Scopes: description triggering (1-8) and behavior/convention compliance of the work-continuation skill (9-14). Triggering assertions follow the plastic-auto eval style (one subagent router per case). Behavior assertions are convention checks against the SKILL.md.",
3
+ "notes": "Intent 158a1: slimmed to the specific-intent resume route of plastic-continuing (D8, extract not duplicate). Bare 'continue' now belongs to the router; triggering evals 1-4 were recast so this skill's positives always name a specific intent, and eval 4 asserts bare 'continue' does NOT settle here directly. Behavior eval 11 (dashboard selection) was removed, relocated to plastic-project-continuing's evals. Behavior eval 15 is new: the terminal handoff goes to plastic-intent-starting, not directly to plastic-auto. Scopes: description triggering (1-8) and behavior/convention compliance of the ledger-resume skill (9-15).",
4
4
  "results": {
5
- "triggering": { "cases": 8, "passed": 8, "run": "2026-06-16, one subagent per case" },
6
- "behavior": { "cases": 6, "passed": 6, "evidence": "convention checks against skills/intent-continuing/SKILL.md after the intent-36 rewrite; doctor --core verified at 0.07s with 9 liveness checks and full doctor unchanged at 30 checks" }
5
+ "triggering": { "cases": 8, "passed": 8, "run": "2026-07-10, one subagent per case" },
6
+ "behavior": { "cases": 7, "passed": 7, "evidence": "convention checks against skills/intent-continuing/SKILL.md after the 158a1 extraction" }
7
7
  },
8
8
  "evals": [
9
9
  {
10
10
  "id": 1, "scope": "triggering", "set": "train",
11
- "prompt": "continue",
12
- "expected_output": "Activates plastic-intent-continuing (the bare 'continue' keyword is the documented trigger).",
11
+ "prompt": "continue intent 4a",
12
+ "expected_output": "Activates plastic-intent-continuing (a specific intent named by id).",
13
13
  "files": [],
14
14
  "assertions": [
15
15
  { "type": "code", "check": "router CHOICE == plastic-intent-continuing", "observed": "plastic-intent-continuing", "result": "pass" }
@@ -17,8 +17,8 @@
17
17
  },
18
18
  {
19
19
  "id": 2, "scope": "triggering", "set": "train",
20
- "prompt": "resume where we left off",
21
- "expected_output": "Activates plastic-intent-continuing.",
20
+ "prompt": "resume the statusline-coloring intent",
21
+ "expected_output": "Activates plastic-intent-continuing (a specific intent named by description).",
22
22
  "files": [],
23
23
  "assertions": [
24
24
  { "type": "code", "check": "router CHOICE == plastic-intent-continuing", "observed": "plastic-intent-continuing", "result": "pass" }
@@ -26,8 +26,8 @@
26
26
  },
27
27
  {
28
28
  "id": 3, "scope": "triggering", "set": "validation",
29
- "prompt": "pick up where we left off in this project",
30
- "expected_output": "Activates plastic-intent-continuing.",
29
+ "prompt": "continuing --intent 96",
30
+ "expected_output": "Activates plastic-intent-continuing (the --intent form).",
31
31
  "files": [],
32
32
  "assertions": [
33
33
  { "type": "code", "check": "router CHOICE == plastic-intent-continuing", "observed": "plastic-intent-continuing", "result": "pass" }
@@ -35,11 +35,11 @@
35
35
  },
36
36
  {
37
37
  "id": 4, "scope": "triggering", "set": "train",
38
- "prompt": "boot plastic and show me where things stand",
39
- "expected_output": "Activates plastic-intent-continuing (continuing work + presenting state is the skill's purpose; boot itself is hook-owned).",
38
+ "prompt": "continue",
39
+ "expected_output": "Does NOT settle on plastic-intent-continuing directly. Bare 'continue' with no specific intent named belongs to the plastic-continuing router, which defaults to plastic-project-continuing.",
40
40
  "files": [],
41
41
  "assertions": [
42
- { "type": "code", "check": "router CHOICE == plastic-intent-continuing", "observed": "plastic-intent-continuing", "result": "pass" }
42
+ { "type": "code", "check": "router CHOICE != plastic-intent-continuing", "observed": "plastic-continuing", "result": "pass" }
43
43
  ]
44
44
  },
45
45
  {
@@ -72,7 +72,7 @@
72
72
  {
73
73
  "id": 8, "scope": "triggering", "set": "validation",
74
74
  "prompt": "what's the dashboard look like right now",
75
- "expected_output": "May activate plastic-dashboard rather than plastic-intent-continuing; an overview request without 'continue/resume' is a dashboard task.",
75
+ "expected_output": "Does NOT activate plastic-intent-continuing directly; an overview request without a specific intent named is a dashboard/project-board task.",
76
76
  "files": [],
77
77
  "assertions": [
78
78
  { "type": "code", "check": "router CHOICE != plastic-intent-continuing", "observed": "plastic-dashboard", "result": "pass" }
@@ -97,16 +97,7 @@
97
97
  ]
98
98
  },
99
99
  {
100
- "id": 11, "scope": "behavior", "set": "train",
101
- "prompt": "Is dashboard selection project-aware?",
102
- "expected_output": "Project loaded -> `dashboard.rb project <slug>`; otherwise -> `dashboard.rb continue`. Skill only invokes, does not render.",
103
- "files": ["skills/intent-continuing/SKILL.md"],
104
- "assertions": [
105
- { "type": "convention", "check": "both dashboard invocations present and gated on project detection", "observed": "'dashboard.rb project <slug>' and 'dashboard.rb continue' in the 'Continue (present the dashboard)' section", "result": "pass" }
106
- ]
107
- },
108
- {
109
- "id": 12, "scope": "behavior", "set": "validation",
100
+ "id": 11, "scope": "behavior", "set": "validation",
110
101
  "prompt": "Is ledger-resume conditional and ledger-driven?",
111
102
  "expected_output": "Resume fires only when a specific intent is named; reads savepoint.md last line as stage, verifies the stage file, rebuilds on drift, derives next step from first unchecked checklist item.",
112
103
  "files": ["skills/intent-continuing/SKILL.md"],
@@ -115,7 +106,7 @@
115
106
  ]
116
107
  },
117
108
  {
118
- "id": 13, "scope": "behavior", "set": "validation",
109
+ "id": 12, "scope": "behavior", "set": "validation",
119
110
  "prompt": "Are the stale prose-savepoint fields gone?",
120
111
  "expected_output": "No 'In progress' / 'Blockers' fields read from a prose savepoint remain; the ledger model is used instead.",
121
112
  "files": ["skills/intent-continuing/SKILL.md"],
@@ -124,7 +115,7 @@
124
115
  ]
125
116
  },
126
117
  {
127
- "id": 14, "scope": "behavior", "set": "validation",
118
+ "id": 13, "scope": "behavior", "set": "validation",
128
119
  "prompt": "Is the 'Determine Store' local-store gap filled?",
129
120
  "expected_output": "Step 2 of Determine Store describes local/project-store detection (no empty step).",
130
121
  "files": ["skills/intent-continuing/SKILL.md"],
@@ -133,13 +124,22 @@
133
124
  ]
134
125
  },
135
126
  {
136
- "id": 15, "scope": "behavior", "set": "validation",
127
+ "id": 14, "scope": "behavior", "set": "validation",
137
128
  "prompt": "QMD is present. The user says: continue the work on the statusline coloring (names the intent by description, not id).",
138
129
  "expected_output": "Before scanning the store with grep/Read to locate the named intent, runs `ruby ~/.plastic/scripts/qmd-sync search \"statusline coloring\"` to surface the candidate intent, then opens the authoritative intent file for the hit it resumes. No-op fallback to INDEX.md / file scan when QMD is absent.",
139
130
  "files": ["skills/intent-continuing/SKILL.md"],
140
131
  "assertions": [
141
132
  { "type": "human", "check": "qmd-sync search is run before grep/Read when the intent is named by description; authoritative file opened for the hit", "observed": "Conditional Ledger-Resume carries the QMD-first step: run qmd-sync search before grep/Read, then open the authoritative file; no-op fallback when QMD is absent", "result": "pass" }
142
133
  ]
134
+ },
135
+ {
136
+ "id": 15, "scope": "behavior", "set": "train",
137
+ "prompt": "Does the ledger-resume's terminal handoff go to plastic-intent-starting or directly to plastic-auto?",
138
+ "expected_output": "Step 5 announces state then hands off to plastic-intent-starting, which takes the lock and asks 'auto or guided?' exactly once; plastic-intent-starting's own auto branch is the one that hands to plastic-auto. This skill never hands to plastic-auto directly.",
139
+ "files": ["skills/intent-continuing/SKILL.md"],
140
+ "assertions": [
141
+ { "type": "convention", "check": "step 5 hands off to plastic-intent-starting, not plastic-auto; the single ask is attributed to plastic-intent-starting", "observed": "present in 'Conditional Ledger-Resume' step 5", "result": "pass" }
142
+ ]
143
143
  }
144
144
  ]
145
145
  }
@@ -1,4 +1,4 @@
1
- # Context Management (Start-Save-Continue)
1
+ # Context Management (Save, then resume-flow debugging)
2
2
 
3
3
  ## Save Point
4
4
  Triggered by PreCompact hook or manually:
@@ -7,26 +7,22 @@ Triggered by PreCompact hook or manually:
7
7
  3. Update active intent's `savepoint.md` (in-progress, next steps, blockers, discoveries)
8
8
  4. Add observations to `## Insights`
9
9
  5. Update INDEX.md
10
- 6. Commit: `cd ~/.plastic && git add . && git commit -m "chore: savepoint [intent name]"`
10
+ 6. Commit: `cd ~/.plastic && git add . && git commit -m "chore: savepoint - [intent name]"`
11
11
  7. Notify user to `/clear`
12
12
 
13
- ## Continue
14
- Triggered by UserPromptSubmit hook when user says "continue". Priority order:
13
+ ## Debugging the resume flow
15
14
 
16
- **1. Active intents first (resume work):**
17
- 1. Read INDEX.md → find active intent(s)
18
- 2. Read active intent's `intent.md` → what and why
19
- 3. Read active intent's `savepoint.md` → where we left off
20
- 4. Read active intent's `checklist.md` → what's next
21
- 5. Announce: intent name, current state, next step, blockers
22
- 6. Resume
15
+ When a resume looks wrong (the announced stage does not match what is on disk, or the next
16
+ step looks stale):
23
17
 
24
- **2. No active intents offer future intents:**
25
- 1. List all future intents from INDEX.md
26
- 2. Present them as options
27
- 3. When user picks one, move to Active in INDEX.md
18
+ 1. Read `savepoint.md`'s last line directly; that line alone is the source of truth for stage
19
+ (see `SKILL.md`'s `## Conditional Ledger-Resume` for the full state table).
20
+ 2. Confirm the artifact that line implies (`plan.md`, `checklist.md`, `outcome.md`, ...) is
21
+ present and non-empty on disk.
22
+ 3. If the two disagree, the ledger has drifted: rebuild it rather than hand-editing:
23
+ `ruby -r ~/.plastic/scripts/lib/bridge -e 'Bridge.rebuild_savepoint("<intent_dir>")'`
24
+ 4. Re-read the rebuilt last line and re-derive the next step from `checklist.md`'s first
25
+ unchecked item.
28
26
 
29
- **3. Stale future intents (untouched 3+ days) → triage:**
30
- - **activate** start working on it now
31
- - **abandon** — mark as abandoned
32
- - **defer to agent** — implement, research, or ideate
27
+ The general "land on the board / priority order / stale future intents" flow now lives in
28
+ `plastic-project-continuing`; this file no longer duplicates it.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: plastic-intent-planning
3
- description: "Write implementation plans from a spec. Produces plan.md, checklist.md, and (L tier only) actions/ in the active intent directory."
3
+ description: "Write implementation plans from a spec. Produces plan.md, checklist.md, and at least one real actions/ACTION_N.md (every tier) in the active intent directory."
4
4
  user-invocable: true
5
5
  ---
6
6
 
@@ -31,12 +31,12 @@ If the spec covers multiple independent subsystems, it should have been broken i
31
31
 
32
32
  ## Tier shapes
33
33
 
34
- Read the spec's stamped `Tier:` line (written by intent-speccing) and pick the plan shape it calls for:
34
+ Read the spec's stamped `Tier:` line (written by intent-speccing) and pick the action shape it calls for. Every tier produces at least one REAL action file in `actions/`; the tier only changes how many:
35
35
 
36
- - **S or M (default):** an inline plan-as-checklist. Tasks live directly in `plan.md` with rationale inline; `checklist.md` mirrors the task list. Do NOT create any `actions/` files. Leave the `actions/` directory empty (or absent).
36
+ - **S or M (default):** write ONE consolidated `actions/ACTION_1.md` that carries the whole ordered delivery (the steps plus the exact changes). `plan.md` still holds the overall map and `checklist.md` still mirrors the task list. You may split into a few action files when that reads cleaner, but one real action file is the floor.
37
37
  - **L (many independent tasks, dispatched in parallel):** self-contained `actions/ACTION_N.md`, one per task, each readable without the plan (see `references/plan-format.md`).
38
38
 
39
- Default to inline for S and M. Reserve `actions/` for L, where tasks are independent enough to hand to separate subagents in parallel. When in doubt, prefer inline; creating unnecessary `actions/` files is a plan failure at S/M tier.
39
+ A `.gitkeep` never counts as an action, and an empty `actions/` fails the How gate at every tier. At S/M, keep it to a single consolidated action file rather than one-per-task; over-splitting a small intent is the S/M failure mode, an empty `actions/` is the tier-wide one.
40
40
 
41
41
  ## File Structure
42
42
 
@@ -97,11 +97,11 @@ If you find issues, fix them inline. No need to re-review, just fix and move on.
97
97
  ## Plastic Artifacts
98
98
 
99
99
  After writing `plan.md`, create `checklist.md` (execution registry following the
100
- FORM: `## In Progress`, `## Completed`, `## Session Log`) in the intent directory.
101
- For L tier only, also create `actions/ACTION_N.md` (one self-contained file per
102
- task, in an `actions/` directory inside the intent directory). For S/M tier, do
103
- not create `actions/` files at all (see Tier shapes above). For the exact format
104
- of both, read `references/plan-format.md`.
100
+ FORM: `## In Progress`, `## Completed`, `## Session Log`) and at least one real
101
+ `actions/ACTION_N.md` (self-contained, in an `actions/` directory inside the intent
102
+ directory). At S/M write one consolidated `actions/ACTION_1.md`; at L write one
103
+ `actions/ACTION_N.md` per task (see Tier shapes above). For the exact format of
104
+ both, read `references/plan-format.md`.
105
105
 
106
106
  ## Owner-decision hard-gate items
107
107
 
@@ -118,12 +118,12 @@ When collecting owner rulings for `[ORCHESTRATOR]` hard-gate items, read
118
118
  ## Gate position
119
119
 
120
120
  - **Before:** `spec.md` exists.
121
- - **Produces:** `plan.md` and `checklist.md` (plus `actions/` for L tier only).
121
+ - **Produces:** `plan.md`, `checklist.md`, and at least one real `actions/ACTION_N.md` (every tier; one consolidated file at S/M, one per task at L).
122
122
  - **Next:** /plastic-intent-executing.
123
123
 
124
124
  ## Git Commit
125
125
 
126
- After writing all artifacts (plan.md, checklist.md, actions/ for L tier), commit to the store:
126
+ After writing all artifacts (plan.md, checklist.md, and the actions/ACTION_N.md files), commit to the store:
127
127
 
128
128
  ```bash
129
129
  cd {store_root} && git add . && git commit -m "docs: plan for intent {id}: {name}"
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "skill_name": "plastic-intent-planning",
3
- "notes": "Intent 164. New evals.json for the writing-plans skill: tier-shape enforcement (S/M inline vs L actions/) and the checklist FORM plus [ORCHESTRATOR] hard-gate item convention. All assertions are pending a real observed run per the plastic-evaluating-skills convention.",
3
+ "notes": "Intent 164, updated by 133a. Evals for the writing-plans skill: action-file enforcement at every tier (S/M consolidate the delivery into one real actions/ACTION_1.md, L writes one actions/ACTION_N.md per task) and the checklist FORM plus [ORCHESTRATOR] hard-gate item convention. All assertions are pending a real observed run per the plastic-evaluating-skills convention.",
4
4
  "evals": [
5
5
  {
6
6
  "id": 1,
7
7
  "scope": "behavior",
8
8
  "set": "train",
9
9
  "prompt": "spec.md is stamped Tier: M and describes a single subsystem change touching four files across two tasks. Write the plan.",
10
- "expected_output": "Produces an inline plan-as-checklist: all tasks with rationale live directly in plan.md, and checklist.md mirrors the task list. No actions/ACTION_N.md files are created; the actions/ directory stays empty or absent.",
10
+ "expected_output": "Produces plan.md plus checklist.md plus at least one real actions/ACTION_N.md. At M the planner consolidates the whole delivery into a single actions/ACTION_1.md (it may split into a few files if that reads cleaner); the actions/ directory is never left empty or .gitkeep-only. checklist.md mirrors plan.md's task list.",
11
11
  "files": [],
12
12
  "assertions": [
13
13
  {
14
14
  "type": "code",
15
- "check": "no files created under actions/ for this intent; checklist.md exists and mirrors plan.md's task list",
15
+ "check": "at least one real (non-empty, non-.gitkeep) file exists under actions/ for this intent; checklist.md exists and mirrors plan.md's task list",
16
16
  "result": "expect-pass"
17
17
  }
18
18
  ]
@@ -22,12 +22,12 @@
22
22
  "scope": "behavior",
23
23
  "set": "train",
24
24
  "prompt": "spec.md is stamped Tier: S and describes a single-file config change. Write the plan.",
25
- "expected_output": "Produces an inline plan-as-checklist. No actions/ files are created, matching the S/M default.",
25
+ "expected_output": "Produces plan.md plus checklist.md plus one consolidated actions/ACTION_1.md carrying the whole ordered delivery (the steps plus the exact changes). The actions/ directory is never left empty or .gitkeep-only, matching the every-tier action-file rule.",
26
26
  "files": [],
27
27
  "assertions": [
28
28
  {
29
29
  "type": "code",
30
- "check": "no files created under actions/ for this intent",
30
+ "check": "at least one real (non-empty, non-.gitkeep) actions/ACTION_N.md exists under actions/ for this intent; no empty or .gitkeep-only actions/ dir remains",
31
31
  "result": "expect-pass"
32
32
  }
33
33
  ]
@@ -61,6 +61,21 @@
61
61
  "result": "expect-pass"
62
62
  }
63
63
  ]
64
+ },
65
+ {
66
+ "id": 5,
67
+ "scope": "behavior",
68
+ "set": "validation",
69
+ "prompt": "spec.md is stamped Tier: S. A prior draft left actions/ with only a .gitkeep. Write the plan and its actions.",
70
+ "expected_output": "Writes at least one real actions/ACTION_1.md (non-empty, not the placeholder sentinel, not a .gitkeep) that consolidates the whole S-tier delivery. Leaving actions/ empty or .gitkeep-only is a plan failure that would block the How gate; the planner never does this at any tier.",
71
+ "files": [],
72
+ "assertions": [
73
+ {
74
+ "type": "code",
75
+ "check": "actions/ contains at least one real action file (non-empty *.md, first line not the placeholder sentinel); no .gitkeep-only or empty actions/ dir remains",
76
+ "result": "expect-pass"
77
+ }
78
+ ]
64
79
  }
65
80
  ]
66
81
  }
@@ -28,8 +28,9 @@ plan.md so the shape matches on the first pass.
28
28
 
29
29
  **Intent:** {id}: {name}
30
30
 
31
- **Tier:** S|M|L, copied from the spec's stamped `Tier:` line. S and M plans are
32
- inline plan-as-checklist (no `actions/`); L plans use `actions/ACTION_N.md`.
31
+ **Tier:** S|M|L, copied from the spec's stamped `Tier:` line. Every tier produces at
32
+ least one real `actions/ACTION_N.md`; S and M consolidate the delivery into one action
33
+ file, L uses one `actions/ACTION_N.md` per task.
33
34
 
34
35
  ---
35
36
  ```
@@ -112,10 +113,13 @@ of tier (S, M, or L):
112
113
 
113
114
  ## actions/ACTION_N.md format
114
115
 
115
- L tier only. S and M plans skip this file type entirely; their tasks live
116
- inline in `plan.md` (see the parent SKILL.md's `## Tier shapes`).
116
+ Every tier writes at least one real action file here (see the parent SKILL.md's
117
+ `## Tier shapes`): S and M consolidate the whole delivery into a single
118
+ `actions/ACTION_1.md`, L writes one file per task.
117
119
 
118
- One file per task. Each action is self-contained: a subagent can execute it without reading the plan.
120
+ Each action is self-contained: a subagent (or a solo executor) can execute it without
121
+ reading the plan. It carries the ordered steps to deliver the task plus the exact changes
122
+ to make (for code, the anchor or `file:line` and the old/new text).
119
123
 
120
124
  ```markdown
121
125
  # Action {N}: {task title}
@@ -42,6 +42,18 @@ Read the active store's `INDEX.md` and extract intents under `## Active`.
42
42
  - Confirm the **last line's stage** matches the stage derived from files-on-disk
43
43
  (`Bridge.derive_stage`). If they disagree, or the file is missing/empty, the ledger has
44
44
  drifted.
45
+ - Run `Bridge.savepoint_phantom_lines(intent_dir)` (pure, disk-only, no bridge or session
46
+ resolution; intent 134). It flags a line disk evidence contradicts: a file-landing milestone
47
+ whose file is absent or still a sentinel placeholder, a duplicate `(stage, milestone)` pair, or
48
+ a state line (`How started` / `Exec started`) whose stage prerequisites are absent. If it
49
+ returns any lines:
50
+ - **LIVE intent (INDEX `## Active`):** rebuild via step 3 below.
51
+ - **INDEX `## Completed`/`## Abandoned` intent:** REPORT the phantom lines and STOP. Do not
52
+ rewrite. Completed intents are immutable. A repair is available only under an explicit human
53
+ grant, following the 124a precedent: rebuild the file-landing skeleton (step 3), then
54
+ re-append the terminal `Done <disposition>` bookend with the disposition read from
55
+ `outcome.md`'s `disposition:` frontmatter and the timestamp recovered from the merge commit or
56
+ the file's mtime, never invented.
45
57
 
46
58
  ### 3. Rebuild on drift
47
59
  Reconstruct from the filesystem rather than hand-editing:
@@ -40,7 +40,7 @@
40
40
  "scope": "triggering",
41
41
  "set": "validation",
42
42
  "prompt": "continue",
43
- "expected_output": "Does NOT activate plastic-intent-starting; bare 'continue' is plastic-intent-continuing (no specific intent named).",
43
+ "expected_output": "Does NOT activate plastic-intent-starting; bare 'continue' is plastic-continuing (the router, no specific intent named).",
44
44
  "files": [],
45
45
  "assertions": [
46
46
  { "type": "code", "check": "router CHOICE != plastic-intent-starting", "result": "expect-pass" }
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: plastic-project-continuing
3
+ description: >-
4
+ Use when the user wants to land on the project board, asks "what should I work on" in this
5
+ project, or wants active intents plus the most-valuable next work surfaced. This is the
6
+ default route of plastic-continuing for a bare "continue" with no specific intent or roadmap
7
+ named. It presents state and stops without asking how to proceed - that single mode question
8
+ lives in plastic-intent-starting, once the user names a specific intent to work.
9
+ user-invocable: true
10
+ ---
11
+
12
+ # Project Continuing - land on the board
13
+
14
+ `plastic-project-continuing` is the project route of `plastic-continuing`. It lands on the
15
+ Markdown board, presents active work and the most-valuable next work, and stops. It does not
16
+ resume a specific intent by ledger (that is `plastic-intent-continuing`) and it asks nothing.
17
+
18
+ ## Continue (present the board)
19
+
20
+ Land on the Markdown board via the `plastic-dashboard` skill. Rendering belongs there, not
21
+ here - run the data payload and fill + present the matching template:
22
+ - Project loaded -> `ruby ~/.plastic/scripts/dashboard.rb project <slug> --data`
23
+ - Otherwise (no project loaded, the global fallback) -> `ruby ~/.plastic/scripts/dashboard.rb continue --data`
24
+
25
+ Fill the matching template from `plastic-dashboard`'s `templates/` and **present the filled
26
+ Markdown in your reply** (every time, non-optional). If the reply does not contain the filled
27
+ Markdown, the user sees nothing - tool-call stdout and hook `additionalContext` are both
28
+ invisible to them. `hook-continue` also emits a one-line `systemMessage` summary as a
29
+ hook-owned fallback; treat it as a floor only, never as a substitute for presenting the full
30
+ board here. See `plastic-dashboard` for the fill mechanics (`references/board-fill.md` has the
31
+ scoped detail).
32
+
33
+ The board load runs the scoped store check on every load (`doctor --store <scope>`): the
34
+ global board runs `--store global` and a project board runs `--store <slug>`. The result
35
+ arrives in the payload as `store_health`; surface it as a one-line store-health note. It is
36
+ non-fatal (a warn or fail is shown as data, it does not block continuing).
37
+
38
+ ## Priority Order
39
+
40
+ 1. **Active intents first** - surface work in progress.
41
+ 2. **Project context** - if in a registered project, show governing + tactical intents.
42
+ 3. **Stale future intents** - surface for triage (see below).
43
+ 4. **Fresh future intents** - offer as next work.
44
+
45
+ ## Stale Future Intents
46
+
47
+ If a future intent's `created` date is older than the configured `stale_threshold_days`
48
+ (default 3), surface it for triage without taking action:
49
+
50
+ ```
51
+ Stale future intents (no action taken):
52
+
53
+ - [ID - name] (X days old)
54
+ a) Activate - start working on it now
55
+ b) Abandon - mark as abandoned
56
+ c) Defer to agent: implement | research | ideate
57
+ d) Auto - go fully autonomous (invokes plastic-auto)
58
+ ```
59
+
60
+ When the user activates a future intent, move it to `## Active` in INDEX.md and auto-commit.
61
+
62
+ **Defer to agent: research.** Selecting `research` is a real dispatch, not a label. Resolve
63
+ `plastic-future-intent-researcher`'s model via `read-config agents.models.<basename> --project
64
+ <repo>` (project override, then global, then the shipped tier default) rather than relying on
65
+ bare frontmatter, which also honors a sanctioned `agents.models.<name>` override if one is
66
+ configured. Dispatch the agent (Agent tool, `subagent_type: "plastic-future-intent-researcher"`)
67
+ on the selected stale future intent, passing the resolved model explicitly. The agent writes its
68
+ findings into that intent's `## Context` (see `agents/plastic-future-intent-researcher.md`); it
69
+ does not itself dispatch further sub-agents. Once it returns, re-present the stale-future-intent
70
+ triage so the user can act on the fresh findings now on record.
71
+
72
+ ## Deciding rules
73
+
74
+ The board's ranked next-work order is deterministic, computed by `dashboard.rb`; this skill
75
+ never re-derives it. Cite the rule NAMES only when explaining a ranking or disposition: Effort,
76
+ Value, Flags, Override, Caps. Read `plastic-dashboard`'s `references/classification.md` for the
77
+ definitions; do not restate or copy them here.
78
+
79
+ ## Then stop
80
+
81
+ Present "here is the state, what next?" and wait. Offer active intents first, then future
82
+ intents. Do not start executing work. The only follow-up from here:
83
+ - User/agent names a specific intent to continue -> hand to `plastic-intent-continuing`
84
+ (which reads the ledger and, in turn, hands to `plastic-intent-starting` for the single
85
+ auto-or-guided ask).
86
+
87
+ ## Coordination
88
+
89
+ Intent 149 has landed: the dashboard is demoted to prose (no Value x Effort grid). This skill
90
+ was built against the live INDEX.md-parsing `--data` path (147, the DB cutover, has not
91
+ landed). Its rule-name citations (`classification.md`, cited by name, not logic) and the
92
+ `dashboard.rb project <slug> --data` -> `dashboard-project.md` path still resolve.
93
+
94
+ Intent 148 landed: roadmaps are the primary planning surface. When the tier has a mid-flight
95
+ roadmap (`ruby ~/.plastic/scripts/roadmap-next --roadmaps-dir <tier>/roadmaps` reports a `state`
96
+ other than `none`), the roadmap route (`plastic-roadmap-continuing`) is the live surface for
97
+ "what to work next", and `plastic-continuing` routes there. This board still presents project
98
+ state and stops, asking nothing (unchanged): it does not itself dispatch, re-rank, or resume a
99
+ roadmap. The global store and any project with no roadmap report `none`, so this board stays the
100
+ default route for them.
101
+
102
+ ## References
103
+
104
+ - `references/board-fill.md` - the template-fill mechanics and store-health surfacing detail.