@zalom/plastic 1.0.0-beta.9 → 1.0.0

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 (107) hide show
  1. package/PLASTIC-reference.md +133 -0
  2. package/PLASTIC.md +398 -82
  3. package/README.md +99 -82
  4. package/agents/plastic-brainstorming.md +12 -9
  5. package/agents/plastic-enforcer.md +52 -12
  6. package/agents/plastic-executor.md +10 -10
  7. package/agents/plastic-future-intent-researcher.md +4 -8
  8. package/agents/plastic-intent-curator.md +12 -14
  9. package/agents/plastic-intent-discovery.md +35 -0
  10. package/agents/plastic-planner.md +15 -10
  11. package/agents/plastic-spec-specialist.md +15 -10
  12. package/bin/plastic.js +7 -3
  13. package/hooks/code-gate +10 -1
  14. package/hooks/hooks.json +28 -3
  15. package/hooks/lock-gate +21 -0
  16. package/hooks/retrieval-gate +10 -0
  17. package/hooks/savepoint-pre +10 -0
  18. package/hooks/statusline +48 -6
  19. package/package.json +2 -1
  20. package/scripts/agent-report +21 -0
  21. package/scripts/dashboard.rb +98 -23
  22. package/scripts/doctor.rb +232 -5
  23. package/scripts/hook-auto-arm +1 -1
  24. package/scripts/hook-bash-gate +22 -4
  25. package/scripts/hook-code-gate +11 -6
  26. package/scripts/hook-continue +17 -0
  27. package/scripts/hook-create-gate +45 -9
  28. package/scripts/hook-gate-check +24 -23
  29. package/scripts/hook-lock-gate +83 -0
  30. package/scripts/hook-retrieval-gate +148 -0
  31. package/scripts/hook-savepoint-pre +32 -0
  32. package/scripts/hook-session-start +1 -1
  33. package/scripts/insight-append +51 -0
  34. package/scripts/install.rb +44 -7
  35. package/scripts/lib/agent_models.rb +43 -0
  36. package/scripts/lib/bridge.rb +924 -84
  37. package/scripts/lib/dashboard_banner.rb +42 -0
  38. package/scripts/lib/hook_registry.rb +95 -0
  39. package/scripts/lib/insights.rb +86 -0
  40. package/scripts/lib/installer_core.rb +100 -60
  41. package/scripts/lib/link_suggestions.rb +319 -0
  42. package/scripts/lib/lock.rb +375 -0
  43. package/scripts/lib/power_tools.rb +22 -21
  44. package/scripts/lib/preflight.rb +79 -0
  45. package/scripts/lib/qmd_sync.rb +15 -0
  46. package/scripts/lib/retrieval_gate.rb +211 -0
  47. package/scripts/lib/worktree.rb +384 -0
  48. package/scripts/link-suggest +213 -0
  49. package/scripts/new-intent +9 -1
  50. package/scripts/plastic-lock +164 -0
  51. package/scripts/read-config +4 -0
  52. package/scripts/spawn-preamble +11 -3
  53. package/scripts/update.rb +16 -7
  54. package/skills/auto/SKILL.md +126 -19
  55. package/skills/auto/references/agent-architecture.md +7 -4
  56. package/skills/auto/references/agent-report-contract.md +36 -1
  57. package/skills/auto/references/end-tail.md +56 -0
  58. package/skills/auto/references/human-report-contract.md +55 -0
  59. package/skills/auto/references/tiers.md +77 -0
  60. package/skills/brainstorming/SKILL.md +7 -34
  61. package/skills/brainstorming/references/design-principles.md +49 -0
  62. package/skills/continuing/SKILL.md +26 -7
  63. package/skills/creating-intent/SKILL.md +13 -28
  64. package/skills/creating-project/SKILL.md +11 -74
  65. package/skills/creating-project/references/project-scaffolding.md +97 -0
  66. package/skills/creating-skills/SKILL.md +65 -0
  67. package/skills/creating-skills/evals/evals.json +108 -0
  68. package/skills/creating-skills/references/agents.md +168 -0
  69. package/skills/creating-skills/references/evals.md +41 -0
  70. package/skills/creating-skills/references/hooks.md +248 -0
  71. package/skills/creating-skills/references/progressive-disclosure.md +176 -0
  72. package/skills/creating-skills/references/scripts.md +166 -0
  73. package/skills/creating-skills/references/skills.md +165 -0
  74. package/skills/creating-skills/scripts/scaffold.rb +313 -0
  75. package/skills/dashboard/SKILL.md +13 -11
  76. package/skills/dashboard/references/classification.md +22 -0
  77. package/skills/doctor/SKILL.md +10 -7
  78. package/skills/executing-plan/SKILL.md +4 -4
  79. package/skills/humanizer/SKILL.md +39 -0
  80. package/skills/humanizer/evals/evals.json +70 -0
  81. package/skills/humanizer/references/always-on-snippet.md +9 -0
  82. package/skills/humanizer/references/examples.md +48 -0
  83. package/skills/install/SKILL.md +75 -84
  84. package/skills/intent-curator/SKILL.md +5 -1
  85. package/skills/intent-discovery/SKILL.md +47 -0
  86. package/skills/intent-starting/SKILL.md +130 -0
  87. package/skills/intent-starting/evals/evals.json +117 -0
  88. package/skills/intent-starting/references/boarding-matrix.md +35 -0
  89. package/skills/linking-intents/SKILL.md +48 -12
  90. package/skills/lock/SKILL.md +41 -0
  91. package/skills/managing-index/SKILL.md +6 -0
  92. package/skills/releasing/SKILL.md +44 -29
  93. package/skills/releasing/references/promotion-and-tagging.md +60 -0
  94. package/skills/roadmap/SKILL.md +51 -0
  95. package/skills/roadmap/references/file-format.md +91 -0
  96. package/skills/roadmap/references/operations.md +78 -0
  97. package/skills/uninstall/SKILL.md +29 -11
  98. package/skills/update/SKILL.md +34 -23
  99. package/skills/versions/SKILL.md +27 -12
  100. package/skills/writing-plans/SKILL.md +10 -88
  101. package/skills/writing-plans/references/plan-format.md +102 -0
  102. package/templates/config.yml +8 -0
  103. package/templates/outcome.md +3 -0
  104. package/templates/revisions.md +58 -0
  105. package/templates/roadmap.md +30 -0
  106. package/skills/writing-instructions/SKILL.md +0 -159
  107. package/skills/writing-instructions/references/agentskills-spec.md +0 -135
@@ -1,24 +1,31 @@
1
1
  ---
2
2
  name: plastic-install
3
- description: Use when initializing Plastic globally (~/.plastic/) or locally in a project, or to re-install/repair a broken installation. Accepts channel flags (--alpha, --beta, --latest) to select release channel. Default is --latest (stable). Global install is recommended creates the global intent store as a git-backed repository. Local install creates .plastic/ in the current project for testing.
3
+ description: Use when initializing Plastic globally (~/.plastic/) or locally in a project, or to re-install/repair a broken installation. Accepts channel flags (--alpha, --beta, --latest) to select release channel. First install defaults to --beta; reinstalls match the already-installed channel. Global install is recommended: it creates the global intent store as a git-backed repository. Local install creates .plastic/ in the current project for testing.
4
4
  ---
5
5
 
6
6
  # Install Plastic
7
7
 
8
- > **Recommended path:** for a first install, run `npx @zalom/plastic@latest install --claude`
9
- > in your shell (or `bunx @zalom/plastic@latest --claude` if you use Bun). This skill
8
+ > **Recommended path:** for a first install, run `npx -y @zalom/plastic@beta install --claude`
9
+ > in your shell (or `bunx -y @zalom/plastic@beta install --claude` if you use Bun). This skill
10
10
  > exists to **re-install or repair** an existing setup from inside the agent, and to
11
11
  > drive interactive global configuration. Whenever this skill performs an install or
12
12
  > re-install, it **runs `/plastic-doctor` afterward** and reports the result.
13
13
 
14
+ ## Channel rule
15
+
16
+ If Plastic is installed, derive `<channel>` from `~/.plastic/VERSION`: a version containing
17
+ `-alpha` means `@alpha`, `-beta` means `@beta`, otherwise `@latest`. If not installed
18
+ (first install), default to `@beta`. The user can always override with
19
+ `--alpha` / `--beta` / `--latest`.
20
+
14
21
  ## Re-install / repair
15
22
 
16
23
  If Plastic is already installed but something is broken (skills missing, hooks not
17
- firing, leftover legacy plugin), re-run the installer it is idempotent, prunes
24
+ firing, leftover legacy plugin), re-run the installer, it is idempotent, prunes
18
25
  files that no longer ship, and removes any legacy plugin/marketplace layout:
19
26
 
20
27
  ```bash
21
- npx @zalom/plastic@latest install --reinstall --claude # or @beta / @alpha to match your channel
28
+ npx -y @zalom/plastic@<channel> install --reinstall --claude
22
29
  ```
23
30
 
24
31
  Then **run `/plastic-doctor`** and report what it found.
@@ -27,22 +34,22 @@ Then **run `/plastic-doctor`** and report what it found.
27
34
 
28
35
  | Flag | Behavior |
29
36
  |------|----------|
30
- | `--latest` | Install from stable channel (default) |
31
- | `--beta` | Install from beta channel |
32
- | `--alpha` | Install from alpha channel |
37
+ | `--latest` | Install from the stable channel |
38
+ | `--beta` | Install from the beta channel (default on a first install) |
39
+ | `--alpha` | Install from the alpha channel |
33
40
 
34
41
  When invoked from within Claude Code (re-install or channel switch), the skill
35
42
  runs the appropriate npx command:
36
43
 
37
44
  ```bash
38
- # Stable (default)
39
- npx @zalom/plastic install --claude
45
+ # Stable
46
+ npx -y @zalom/plastic@latest install --claude
40
47
 
41
- # Beta
42
- npx @zalom/plastic@beta install --claude
48
+ # Beta (default on a first install)
49
+ npx -y @zalom/plastic@beta install --claude
43
50
 
44
51
  # Alpha
45
- npx @zalom/plastic@alpha install --claude
52
+ npx -y @zalom/plastic@alpha install --claude
46
53
  ```
47
54
 
48
55
  The installed version and channel are recorded in `~/.plastic/VERSION`.
@@ -55,105 +62,80 @@ Run `/plastic-install` with no arguments.
55
62
 
56
63
  #### Procedure
57
64
 
58
- **Step 1: Check for existing installation**
59
-
60
- Check if `~/.plastic/INDEX.md` exists.
61
- - If yes: announce "Plastic is already installed at ~/.plastic/. Run `/plastic-update` to sync core files."
62
- - If no: proceed with fresh install.
65
+ **Step 1: Run the installer**
63
66
 
64
- **Step 2: Create ~/.plastic/ as a git repo**
67
+ Check if `~/.plastic/VERSION` exists.
68
+ - If yes: announce "Plastic is already installed at ~/.plastic/. Run `/plastic-update` to
69
+ sync core files, or use the re-install command above to repair in place."
70
+ - If no: run the fresh install command (default `@beta`, or the channel the user named):
65
71
 
66
72
  ```bash
67
- mkdir -p ~/.plastic/store ~/.plastic/projects
73
+ npx -y @zalom/plastic@beta install --claude
68
74
  ```
69
75
 
70
- Copy templates from the plugin:
71
- - `config.yml` from `${CLAUDE_PLUGIN_ROOT}/templates/config.yml`
72
- - `projects.yml` from `${CLAUDE_PLUGIN_ROOT}/templates/projects.yml`
73
- - `INDEX.md` from `${CLAUDE_PLUGIN_ROOT}/templates/index.md`
74
- - `PLASTIC.md` from `${CLAUDE_PLUGIN_ROOT}/PLASTIC.md`
76
+ This single command, via `install.rb` (`bootstrap` + `distribute`), creates `store/`,
77
+ `projects/`, `config.yml`, `projects.yml`, `INDEX.md`, and `AGENTS.md` under `~/.plastic/`,
78
+ and copies the utility scripts (`folgezettel-id`, `read-config`, and the rest of
79
+ `scripts/`). This skill does none of that itself; it wraps the command with the
80
+ interactive steps the CLI does not yet own, plus reporting and a doctor pass.
75
81
 
76
- Create `AGENTS.md` (user-editable, not overwritten on updates):
77
- ```markdown
78
- # Plastic — Agent Instructions
82
+ **Statusline**
79
83
 
80
- Read `PLASTIC.md` in this directory. It contains all Plastic conventions.
81
- Follow it exactly. Never modify it it is overwritten on plugin updates.
84
+ On install, if an existing statusline is already configured, Plastic asks whether to
85
+ keep it or switch to Plastic's (interactive sessions only). The choice is honored via
86
+ `--statusline keep` or `--statusline plastic`, which skips the prompt. Non-interactive
87
+ sessions (no tty) default to keeping the user's line: nothing is silently overwritten.
88
+ A fresh system with no statusline configured gets Plastic's line with no prompt.
82
89
 
83
- This file (`AGENTS.md`) is where project-specific rules live. Users and agents
84
- may add content below.
85
-
86
- ---
87
- ```
90
+ **Step 2: Initialize git (retained)**
88
91
 
89
- Add `.gitkeep` to `store/` and `projects/`.
92
+ Only if `~/.plastic/.git` is absent (a fresh bootstrap does not init git):
90
93
 
91
- Initialize git:
92
94
  ```bash
93
95
  cd ~/.plastic && git init && git add . && git commit -m "chore: initialize Plastic global intent store"
94
96
  ```
95
97
 
96
- **Step 2b: Copy utility scripts**
98
+ Retained here because the CLI does not git-init the store yet (follow-up).
97
99
 
98
- ```bash
99
- mkdir -p ~/.plastic/scripts
100
- cp "${CLAUDE_PLUGIN_ROOT}/scripts/folgezettel-id" ~/.plastic/scripts/folgezettel-id
101
- cp "${CLAUDE_PLUGIN_ROOT}/scripts/read-config" ~/.plastic/scripts/read-config
102
- chmod +x ~/.plastic/scripts/folgezettel-id ~/.plastic/scripts/read-config
103
- ```
104
-
105
- This ensures project agents can generate hashes via `~/.plastic/scripts/folgezettel-id` without depending on a specific agent's plugin cache path.
106
-
107
- **Step 2c: Detect agent type and set preferences**
100
+ **Step 3: Personalize config (retained)**
108
101
 
109
102
  Detect which agent is running:
110
- - If `CLAUDE_CODE` env var is set or we're running inside Claude Code `agent.type: claude-code`
111
- - If `HERMES_HOME` env var is set `agent.type: hermes`
112
- - Otherwise ask the user: "Which AI agent are you using? (claude-code / hermes / other)"
103
+ - If `CLAUDE_CODE` env var is set or we're running inside Claude Code -> `agent.type: claude-code`
104
+ - If `HERMES_HOME` env var is set -> `agent.type: hermes`
105
+ - Otherwise -> ask the user: "Which AI agent are you using? (claude-code / hermes / other)"
113
106
 
114
107
  Ask the user:
115
- > "Enable Agent Teams? (experimental parallel project work with teammates)"
116
- > - Yes set `parallel_mode: agent-teams`
117
- > - No set `parallel_mode: linear` (subagents only)
118
-
119
- Update `~/.plastic/config.yml` with detected/chosen values using `read-config --migrate` first to ensure v3 schema, then write the agent-specific values.
120
-
121
- Auto-commit the config change.
122
-
123
- **Step 2d: Configure GitHub and push preferences**
108
+ > "Enable Agent Teams? (experimental: parallel project work with teammates)"
109
+ > - Yes -> set `parallel_mode: agent-teams`
110
+ > - No -> set `parallel_mode: linear` (subagents only)
124
111
 
125
112
  Inform the user:
126
- > "Plastic agents can create GitHub repositories for new projects.
127
- > By default, all agent-created repos are **private**. Your global
128
- > intent store (~/.plastic/) is never pushed it stays local-only."
113
+ > "Plastic agents can create GitHub repositories for new projects. By default, all
114
+ > agent-created repos are **private**. Your global intent store (~/.plastic/) is never
115
+ > pushed, it stays local-only."
129
116
 
130
117
  Ask the user:
131
118
  > "Default visibility for agent-created repos?"
132
- > - Private (recommended) set `github.default_visibility: private`
133
- > - Public set `github.default_visibility: public`
134
-
119
+ > - Private (recommended) -> set `github.default_visibility: private`
120
+ > - Public -> set `github.default_visibility: public`
121
+ >
135
122
  > "Allow agents to push to GitHub without asking?"
136
- > - No (recommended) set `github.auto_push: false`
137
- > - Yes set `github.auto_push: true`
138
-
139
- Update `config.yml` with chosen values. Auto-commit.
140
-
141
- **Step 3: Configure project roots**
142
-
143
- Ask the user:
123
+ > - No (recommended) -> set `github.auto_push: false`
124
+ > - Yes -> set `github.auto_push: true`
125
+ >
144
126
  > "Where do you keep your projects? Default: ~/.plastic/projects/"
145
127
  > "Add additional roots? (e.g., ~/apps/personal/, ~/apps/companies/)"
146
128
 
147
- Update `config.yml` with any additional roots.
148
-
149
- Auto-commit the config change.
129
+ Write each answer via `read-config --migrate` first (ensures the v3 schema), then the
130
+ chosen values; auto-commit each change. Retained here because the CLI writes only
131
+ hardcoded defaults, so these interactive choices stay in the skill.
150
132
 
151
133
  **Step 4: Verify with doctor**
152
134
 
153
135
  Run `/plastic-doctor` and report the result. Resolve any fixable findings before
154
136
  announcing success.
155
137
 
156
- **Step 5: Register stores with QMD (optional)**
138
+ **Step 5: Register stores with QMD (retained)**
157
139
 
158
140
  QMD is an optional search layer. If it is installed, register the Plastic stores so
159
141
  they are searchable:
@@ -165,19 +147,27 @@ ruby ~/.plastic/scripts/qmd-sync detect && ruby ~/.plastic/scripts/qmd-sync regi
165
147
  `qmd-sync` no-ops cleanly when QMD is absent, so this is safe to run unconditionally.
166
148
  It registers `plastic-global` and every project store from `projects.yml`, then indexes
167
149
  them. Report what was registered, or that QMD was not detected and the step was skipped.
150
+ Retained here because the CLI does not register at install time (follow-up).
151
+
152
+ **Step 6: Report + announce**
168
153
 
169
- **Step 6: Announce**
154
+ ```
155
+ Plastic install (<channel>)
156
+ Command: npx -y @zalom/plastic@<channel> install --claude <flags>
157
+ Version: none -> <installed>
158
+ Doctor: <summary or "all clear">
159
+ ```
170
160
 
171
- > "Plastic installed globally at ~/.plastic/. Health check: [doctor summary].
172
- > Create your first intent with `/plastic-creating-intent`."
161
+ Then: "Read `docs/guides/your-first-intent-in-10-minutes.md` for your first intent, start to finish."
173
162
 
174
163
  ### Local Install (testing/legacy)
175
164
 
176
- Run `/plastic-install --local`.
165
+ Run `/plastic-install --local`. `install.rb` has no `--local` verb, so this mode is
166
+ genuinely skill-owned.
177
167
 
178
168
  #### Procedure
179
169
 
180
- **Step 1:** Check if `.plastic/` exists in CWD if so, warn and exit.
170
+ **Step 1:** Check if `.plastic/` exists in CWD, if so, warn and exit.
181
171
 
182
172
  **Step 2:** Create `.plastic/` in CWD:
183
173
  - `config.yml` from templates
@@ -192,4 +182,5 @@ Run `/plastic-install --local`.
192
182
 
193
183
  **Step 4:** Commit in project: `git add .plastic/ && git commit -m "chore: initialize Plastic local store"`
194
184
 
195
- **Step 5:** Announce: "Plastic initialized locally. This is a testing/legacy mode. Consider `/plastic-install` for global mode."
185
+ **Step 5:** Announce: "Plastic initialized locally. This is a testing/legacy mode. Consider
186
+ `/plastic-install` for global mode."
@@ -38,6 +38,10 @@ The agent handles:
38
38
  - Cluster management (create, merge, rename)
39
39
  - Orphan detection
40
40
 
41
- When an intent reaches a terminal state — moved to Completed OR Abandoned — refresh the QMD index for the affected store (no-op when QMD absent), running in the background so it never blocks: `ruby ~/.plastic/scripts/qmd-sync reindex --store <store-root> --async`.
41
+ When an intent reaches a terminal state — moved to Completed OR Abandoned — do these things as the closing act of the transfer, in the canonical End-tail order (see PLASTIC.md `## Delivery Isolation and the Single-Owner Lock`):
42
+
43
+ 1. Author a real `outcome.md` in the intent directory from `~/.plastic/templates/outcome.md`, with the frontmatter `disposition: delivered` for a completed intent or `disposition: abandoned` for an abandoned one. `outcome.md` is MANDATORY at every terminal, delivered and abandoned alike: on abandon it records the abandonment reason and replaces the scaffolded placeholder sentinel (never leave `outcome.md` a placeholder at a terminal).
44
+ 2. Stamp the terminal savepoint bookend (intent 81), so the ledger's last line records the disposition: `ruby -r ~/.plastic/scripts/lib/bridge -e 'Bridge.append_terminal_savepoint("<intent_dir>", "delivered")'` (use `"abandoned"` for an abandoned intent). Idempotent.
45
+ 3. Refresh the QMD index for the affected store LAST, after the terminal move and savepoint (no-op when QMD absent), running in the background so it never blocks: `ruby ~/.plastic/scripts/qmd-sync reindex --store <store-root> --async`.
42
46
 
43
47
  After the agent completes, report what changed.
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: plastic-intent-discovery
3
+ description: >-
4
+ What-stage context deposit at intent activation: run QMD discovery over the
5
+ intent's chain/sources and related parked intents, and write findings to
6
+ resources/discovery--<slug>.md for the Why stage to consume. Use when an intent
7
+ is activated (moved from Future to Active), after the lock is armed, under it,
8
+ and before Why begins. Never writes the intent file itself.
9
+ ---
10
+
11
+ # Intent Discovery — What-stage context deposit
12
+
13
+ Announce: "Discovering context for intent [ID] — [name]."
14
+
15
+ Runs once, at intent activation, after the lock is armed and before Why. It gathers what is
16
+ already known so Why does not start cold, and deposits it as a resource the
17
+ Why-stage brainstorming agent reads.
18
+
19
+ ## When it fires
20
+ Inside `plastic-intent-starting`, right after the bridge is armed, under the
21
+ lock. Dispatched as the `plastic-intent-discovery` background agent.
22
+
23
+ ## What it does
24
+ 1. **Read the intent's links.** Load the activating intent file's `chain` and
25
+ `sources` frontmatter fields.
26
+ 2. **QMD-first discovery.** Search the Plastic stores with
27
+ `scripts/qmd-sync search "<terms>"` (or the `qmd` skill), scoped to the
28
+ relevant `plastic-*` collections, across completed predecessor work named in
29
+ `chain`/`sources` and any related parked/future intents in INDEX.md. Fall back
30
+ to ripgrep over the stores only when QMD is absent.
31
+ 3. **Deposit, never author.** Write findings to
32
+ `resources/discovery--<slug>.md` in the intent directory ONLY. Do not write
33
+ the intent file, spec.md, or any lifecycle deliverable. The lock-owner-only
34
+ write rule stays intact; the Why-stage `plastic-brainstorming` agent reads the
35
+ deposit and enriches `## Context`.
36
+
37
+ ## Stage coverage
38
+ This is the What-stage agent in the one-agent-per-stage table (What:
39
+ intent-discovery, Why: brainstorming + spec-specialist, How: planner, Exec:
40
+ executor, Done: intent-curator).
41
+
42
+ ## Boundaries
43
+ - Single output: `resources/discovery--<slug>.md`.
44
+ - Does not ACQUIRE the delivery lock itself; it runs under the lock the
45
+ orchestrator armed, as the owner session (inherited session id), and is not
46
+ blocked by it.
47
+ - Advisory input to Why, not a gate.
@@ -0,0 +1,130 @@
1
+ ---
2
+ name: plastic-intent-starting
3
+ description: >-
4
+ Board a session onto an intent: take the lock FIRST, confirm savepoint state, ask auto or
5
+ guided ONCE, then resume at the latest delivered station and run the cycle to Done. Use on
6
+ `continuing --intent {id}`, when a new intent is registered and the user asks to work it,
7
+ or when the user picks an intent to work. Requires the intent in INDEX `## Active`.
8
+ ---
9
+
10
+ # Intent Starting — board a session onto an intent
11
+
12
+ Announce: "Boarding intent [ID] — [name]."
13
+
14
+ `plastic-intent-starting` is the Start procedure. It boards a session onto one intent: take
15
+ the lock FIRST, confirm the delivery state, ask **auto or guided ONCE**, board at the latest
16
+ delivered station, then run the cycle to Done. The What → Why → How → Exec stations are the
17
+ train track; Start boards the train, the ending procedure (~93) exits it.
18
+
19
+ ## Precondition + trigger
20
+
21
+ Fires when the user picks an intent to work, when an agent is told to continue a SPECIFIC
22
+ intent, or on `continuing --intent {id}` (the `continuing` → `starting` router is 106's job;
23
+ this skill is invokable standalone now).
24
+
25
+ If the intent is **terminal** (Done / Abandoned in INDEX): report only. Take NO lock, run NO
26
+ resume, do NOT reopen it. Summarize the outcome and ask what is next. Stop here.
27
+
28
+ ## Lock FIRST (the spine)
29
+
30
+ The lock is non-negotiable and comes before any mutating work. The ACTION-3 lock-gate
31
+ enforces it: without a held lock, mutating writes to this active intent's dir are denied with
32
+ "run /plastic-intent-starting to lock and begin".
33
+
34
+ 1. **Ensure the intent is in INDEX `## Active`.** If it sits in `## Future`, activate it
35
+ (move it to `## Active`, auto-commit) before arming. Creation precedes activation, so a
36
+ brand-new What intent is activated here, then locked.
37
+ 2. **Self-heal the lock state first.** Run:
38
+ `ruby ~/.plastic/scripts/plastic-lock fix --intent-dir <STORE>/<dir>`
39
+ This is the one repair function (same one /plastic-lock exposes): it removes
40
+ corrupt or legacy lock state and rebuilds the lock and bridge from disk for
41
+ this session. If it reports `held`, another session owns the intent: STOP
42
+ and tell the user who holds it. If it reports `stale`, ask the user before
43
+ running `plastic-lock reclaim` (takeover is audited).
44
+ 3. **Arm the bridge.** Which arm is chosen by the mode answer (below), but the lock itself is
45
+ taken first. Reuse the arm one-liner shape from `plastic-auto`:
46
+ ```bash
47
+ # guided (lock only):
48
+ ruby -r ~/.plastic/scripts/lib/bridge -e \
49
+ 'Bridge.arm_guided(ENV["CLAUDE_CODE_SESSION_ID"], intent_id: "<ID>", intent_dir: "<STORE>/<dir>", store: "<STORE>", name: "<name>")'
50
+ # auto (lock + auto), then hand to plastic-auto:
51
+ ruby -r ~/.plastic/scripts/lib/bridge -e \
52
+ 'Bridge.arm_auto(ENV["CLAUDE_CODE_SESSION_ID"], intent_id: "<ID>", intent_dir: "<STORE>/<dir>", store: "<STORE>", name: "<name>")'
53
+ ```
54
+ Replace `<ID>`, `<STORE>` (`~/.plastic/projects/<slug>/store` or `~/.plastic/store`),
55
+ `<dir>` (the `ID--slug` directory), and `<name>`.
56
+ 4. **Dispatch What-stage discovery (under the lock).** Right after arming, when the intent
57
+ was just activated in step 1 (on a resume that already has
58
+ `resources/discovery--<slug>.md`, skip: discovery runs once per intent, at activation
59
+ only), dispatch the `plastic-intent-discovery` agent (see the `plastic-intent-discovery`
60
+ skill), now that this session owns the lock, deposit authorized as the owner session. Resolve its
61
+ model explicitly and pass it at dispatch time (belt-and-braces): `read-config
62
+ agents.models.plastic-intent-discovery --project <repo>`. The agent runs QMD discovery
63
+ over the intent's `chain`/`sources` and deposits findings to
64
+ `resources/discovery--<slug>.md` only; it never writes the intent file, so the
65
+ lock-owner-only rule is untouched. This is advisory context for Why, not a gate: if
66
+ discovery yields nothing, proceed to Why normally.
67
+
68
+ **Session id resolution (verbatim from `plastic-auto`).** The first argument is the session
69
+ id the bridge is keyed by: pass the hook stdin `session_id` when you have it, otherwise
70
+ `ENV["CLAUDE_CODE_SESSION_ID"]`, otherwise `nil`. Both arms call `resolve_session`, which
71
+ picks the first non-empty of: the explicit id you pass → `CLAUDE_CODE_SESSION_ID` → a
72
+ deterministic derived key (a hash of the store and intent id). It never returns nil, so the
73
+ lock is taken even when every session env var is empty; arming prints a one-line stderr
74
+ notice when it falls through to the derived key.
75
+
76
+ **What the lock IS.** Ownership is session-keyed and lease-based: arming writes a durable
77
+ `delivery.lock` file in the intent dir naming this session as owner, and the owner's hooks
78
+ refresh the file mtime on tool activity (the lease heartbeat). The /tmp bridge is only a
79
+ cache of that file; on any disagreement the lock file wins, so a wiped /tmp never strands
80
+ the owner. Idempotent re-arm: arming again with the same owner just refreshes the lock; it
81
+ is not an error to re-board an intent this session already owns. A failed arm raises with
82
+ a message naming the resolving `plastic-lock` verb (`status`, `reclaim`, or `fix`): follow
83
+ that message, never delete a lock file by hand.
84
+
85
+ ## Confirm delivery state
86
+
87
+ Read `savepoint.md` and classify from the **last line** alone, then verify ONLY that line's
88
+ artifact is real (sentinel-aware via `Bridge.stage_file_present?`). On drift (the last line
89
+ disagrees with files on disk), rebuild the ledger from disk and note the correction. Do not
90
+ inline the rebuild; the `plastic-savepoint` skill owns it:
91
+ ```bash
92
+ ruby -r ~/.plastic/scripts/lib/bridge -e 'Bridge.rebuild_savepoint("<intent_dir>")'
93
+ ```
94
+
95
+ ## Report + ask "auto or guided?" ONCE
96
+
97
+ Report: the intent, the station it lands at (the matrix below), what is delivered, the next
98
+ step. Then ask the user **"auto or guided?"** — exactly ONCE, whatever station it lands at.
99
+ Never re-ask at a later station.
100
+
101
+ - **guided** → `arm_guided` (lock only); continue step by step with the user through the
102
+ station's work below.
103
+ - **auto** → `arm_auto` (lock + auto), then hand off to `plastic-auto`. The auto branch's
104
+ only remaining job is the handoff; `plastic-auto` runs the cycle from here.
105
+
106
+ ## Board at the latest delivered station
107
+
108
+ The station is derived from `savepoint.md` last line + real artifacts on disk. See
109
+ `references/boarding-matrix.md` for the full table (last line → latest delivered → boards at →
110
+ continue with) and the per-station notes. Summary of what "continue" means per station:
111
+
112
+ - **What** → do what What requires (106-expanded), then brainstorm → `spec.md`.
113
+ - **Why** → continue brainstorming → `spec.md`.
114
+ - **How** → continue `plan.md` + `actions/` + `checklist.md`.
115
+ - **Exec** → verify what has been delivered, then continue (or restart) the delivery /
116
+ research; tick the checklist.
117
+ - **ready to complete** (`Exec outcome.md created`) → exit at Done.
118
+ - **Done** → report only, ask what is next, never reopen.
119
+
120
+ ## Disarm / release on done
121
+
122
+ When delivery finishes, disarm and release per the `plastic-auto` disarm/release prose (do
123
+ not duplicate it here). The guided branch releases the lock via `disarm_auto`, which is
124
+ mode-agnostic (it sets `auto = false` and calls `Worktree.release`), so it releases a guided
125
+ lock too. When the work ships through a release, the release path merges the branch before the
126
+ worktree is removed; the plain disarm remove is only for the no-release case.
127
+
128
+ ## References
129
+
130
+ - `references/boarding-matrix.md` — the full boarding table and per-station behaviour.
@@ -0,0 +1,117 @@
1
+ {
2
+ "skill_name": "plastic-intent-starting",
3
+ "notes": "Intent 96. Scopes: description triggering (1-5) and behavior (6-10: lock-first spine, ask-mode-once, terminal report-only, mode->arm mapping, boarding matrix). The lock-first and gate behaviors are also proven by Ruby tests (test/bridge_guided_test.rb, test/lock_gate_test.rb, test/lock_gate_hook_test.rb).",
4
+ "evals": [
5
+ {
6
+ "id": 1,
7
+ "scope": "triggering",
8
+ "set": "train",
9
+ "prompt": "start work on intent 96",
10
+ "expected_output": "Activates plastic-intent-starting (board a session onto the named intent).",
11
+ "files": [],
12
+ "assertions": [
13
+ { "type": "code", "check": "router CHOICE == plastic-intent-starting", "result": "expect-pass" }
14
+ ]
15
+ },
16
+ {
17
+ "id": 2,
18
+ "scope": "triggering",
19
+ "set": "train",
20
+ "prompt": "continuing --intent 96",
21
+ "expected_output": "Activates plastic-intent-starting (the --intent form boards a specific intent).",
22
+ "files": [],
23
+ "assertions": [
24
+ { "type": "code", "check": "router CHOICE == plastic-intent-starting", "result": "expect-pass" }
25
+ ]
26
+ },
27
+ {
28
+ "id": 3,
29
+ "scope": "triggering",
30
+ "set": "validation",
31
+ "prompt": "work this intent",
32
+ "expected_output": "Activates plastic-intent-starting when an intent is in context to be worked.",
33
+ "files": [],
34
+ "assertions": [
35
+ { "type": "code", "check": "router CHOICE == plastic-intent-starting", "result": "expect-pass" }
36
+ ]
37
+ },
38
+ {
39
+ "id": 4,
40
+ "scope": "triggering",
41
+ "set": "validation",
42
+ "prompt": "continue",
43
+ "expected_output": "Does NOT activate plastic-intent-starting; bare 'continue' is plastic-continuing (no specific intent named).",
44
+ "files": [],
45
+ "assertions": [
46
+ { "type": "code", "check": "router CHOICE != plastic-intent-starting", "result": "expect-pass" }
47
+ ]
48
+ },
49
+ {
50
+ "id": 5,
51
+ "scope": "triggering",
52
+ "set": "validation",
53
+ "prompt": "create a new intent for the uploader retry policy",
54
+ "expected_output": "Does NOT activate plastic-intent-starting; activates plastic-creating-intent.",
55
+ "files": [],
56
+ "assertions": [
57
+ { "type": "code", "check": "router CHOICE != plastic-intent-starting", "result": "expect-pass" }
58
+ ]
59
+ },
60
+ {
61
+ "id": 6,
62
+ "scope": "behavior",
63
+ "set": "train",
64
+ "prompt": "Active intent X exists at the Why station. Start work on it (guided).",
65
+ "expected_output": "Takes the lock FIRST via Bridge.arm_guided (auto stays false) before any mutating work, confirms savepoint, then boards at Why and continues brainstorming toward spec.md.",
66
+ "files": [],
67
+ "assertions": [
68
+ { "type": "human", "check": "lock acquired before any mutating write; SKILL.md 'Lock FIRST' section precedes station work", "result": "expect-pass" },
69
+ { "type": "code", "check": "Bridge.arm_guided stamps the lock with auto=false (test/bridge_guided_test.rb green); lock-gate denies a no-lock write to the active intent dir (test/lock_gate_hook_test.rb green)", "result": "pass" }
70
+ ]
71
+ },
72
+ {
73
+ "id": 7,
74
+ "scope": "behavior",
75
+ "set": "train",
76
+ "prompt": "Start work on an active intent without saying auto or guided.",
77
+ "expected_output": "Asks 'auto or guided?' exactly once after reporting the station; never re-asks at later stations.",
78
+ "files": [],
79
+ "assertions": [
80
+ { "type": "human", "check": "SKILL.md asks the mode exactly once and states 'never re-asked at a later station'", "result": "expect-pass" }
81
+ ]
82
+ },
83
+ {
84
+ "id": 8,
85
+ "scope": "behavior",
86
+ "set": "train",
87
+ "prompt": "Start work on an intent that is Done in INDEX.",
88
+ "expected_output": "Reports only: no lock, no resume, no reopen. Summarizes the outcome and asks what is next.",
89
+ "files": [],
90
+ "assertions": [
91
+ { "type": "human", "check": "terminal intent -> report only, no arm call", "result": "expect-pass" }
92
+ ]
93
+ },
94
+ {
95
+ "id": 9,
96
+ "scope": "behavior",
97
+ "set": "validation",
98
+ "prompt": "Start work and choose auto.",
99
+ "expected_output": "guided -> Bridge.arm_guided; auto -> Bridge.arm_auto then hand off to plastic-auto (auto branch's only remaining job is the handoff).",
100
+ "files": [],
101
+ "assertions": [
102
+ { "type": "human", "check": "SKILL.md maps guided->arm_guided and auto->arm_auto+handoff to plastic-auto", "result": "expect-pass" }
103
+ ]
104
+ },
105
+ {
106
+ "id": 10,
107
+ "scope": "behavior",
108
+ "set": "validation",
109
+ "prompt": "Start an intent whose savepoint last line is 'How checklist.md created'.",
110
+ "expected_output": "Boards at Exec (verify plan + checklist real), per references/boarding-matrix.md, and continues delivery/ticks the checklist.",
111
+ "files": [],
112
+ "assertions": [
113
+ { "type": "human", "check": "boarding matrix lands 'How checklist.md created' / 'Exec started' at Exec", "result": "expect-pass" }
114
+ ]
115
+ }
116
+ ]
117
+ }
@@ -0,0 +1,35 @@
1
+ # Boarding matrix — which station Start drops you at
2
+
3
+ The station is derived from `savepoint.md`'s last line plus the real artifacts on disk.
4
+ Classify from the last line alone, then verify ONLY that line's artifact is real
5
+ (sentinel-aware). On drift, rebuild the ledger from disk and note it.
6
+
7
+ | savepoint last line | latest delivered | boards at | continue with |
8
+ |---|---|---|---|
9
+ | `What {id}--{slug}.md` (born) | What | **What / Why** | What work (106-expanded), then brainstorm → `spec.md` |
10
+ | `Why started` (spec still sentinel) | What | **Why** | continue brainstorming → `spec.md` |
11
+ | `Why spec.md created` | Why | **How** | `plan.md` + `actions/` + `checklist.md` |
12
+ | `How started` / `How plan.md created` | (How in progress) | **How** | finish `plan.md` → `checklist.md` |
13
+ | `How checklist.md created` / `Exec started` | How | **Exec** | implement, tick the checklist |
14
+ | `Exec outcome.md created` | Exec | **ready to complete** | exit at Done |
15
+ | `Done delivered` / `Done abandoned` | terminal | **report only** | immutable; ask what is next |
16
+
17
+ ## Per-station behaviour (what "continue" means)
18
+
19
+ - **What** → do what What requires (to be expanded in 106), then brainstorm → `spec.md`.
20
+ - **Why** → continue brainstorming; deliver `spec.md`.
21
+ - **How** → continue `plan.md` + `actions/` + `checklist.md`.
22
+ - **Exec** → verify what has been delivered, then continue (or restart) the delivery /
23
+ research. The first unchecked `checklist.md` item is the next step; the newest `## Insights`
24
+ entry supplies human-readable context.
25
+ - **ready to complete** → `outcome.md` is real; run the ending procedure (~93).
26
+ - **Done** → terminal. Report the outcome, ask what is next. Never reopen; INDEX is
27
+ authoritative.
28
+
29
+ ## Notes
30
+
31
+ - The mode (auto / guided) is asked exactly ONCE, whatever station Start lands at. It is never
32
+ re-asked at a later station. The lock is taken FIRST regardless of station (terminal intents
33
+ excepted: they get no lock and no resume).
34
+ - An `## Insights` entry marked `(autonomous)` means the intent was being delivered
35
+ autonomously; in guided mode, surface that and offer to hand back to `plastic-auto`.