@zalom/plastic 1.0.0-beta.8 → 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 (116) hide show
  1. package/PLASTIC-reference.md +133 -0
  2. package/PLASTIC.md +407 -84
  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 +404 -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/frontmatter_writer.rb +130 -0
  39. package/scripts/lib/graph_rebuild.rb +328 -0
  40. package/scripts/lib/hook_registry.rb +95 -0
  41. package/scripts/lib/insights.rb +86 -0
  42. package/scripts/lib/installer_core.rb +104 -60
  43. package/scripts/lib/link_suggestions.rb +319 -0
  44. package/scripts/lib/links_projection.rb +160 -0
  45. package/scripts/lib/links_section.rb +207 -0
  46. package/scripts/lib/lock.rb +375 -0
  47. package/scripts/lib/power_tools.rb +22 -21
  48. package/scripts/lib/preflight.rb +79 -0
  49. package/scripts/lib/qmd_sync.rb +15 -0
  50. package/scripts/lib/retrieval_gate.rb +211 -0
  51. package/scripts/lib/worktree.rb +384 -0
  52. package/scripts/link-suggest +213 -0
  53. package/scripts/new-intent +138 -29
  54. package/scripts/plastic-lock +164 -0
  55. package/scripts/project-links +287 -0
  56. package/scripts/read-config +4 -0
  57. package/scripts/rebuild-graph +244 -0
  58. package/scripts/spawn-preamble +11 -3
  59. package/scripts/update.rb +16 -7
  60. package/skills/auto/SKILL.md +126 -19
  61. package/skills/auto/references/agent-architecture.md +7 -4
  62. package/skills/auto/references/agent-report-contract.md +36 -1
  63. package/skills/auto/references/end-tail.md +56 -0
  64. package/skills/auto/references/human-report-contract.md +55 -0
  65. package/skills/auto/references/tiers.md +77 -0
  66. package/skills/brainstorming/SKILL.md +7 -34
  67. package/skills/brainstorming/references/design-principles.md +49 -0
  68. package/skills/continuing/SKILL.md +26 -7
  69. package/skills/creating-intent/SKILL.md +13 -28
  70. package/skills/creating-intent/references/lifecycle.md +9 -4
  71. package/skills/creating-project/SKILL.md +11 -74
  72. package/skills/creating-project/references/project-scaffolding.md +97 -0
  73. package/skills/creating-skills/SKILL.md +65 -0
  74. package/skills/creating-skills/evals/evals.json +108 -0
  75. package/skills/creating-skills/references/agents.md +168 -0
  76. package/skills/creating-skills/references/evals.md +41 -0
  77. package/skills/creating-skills/references/hooks.md +248 -0
  78. package/skills/creating-skills/references/progressive-disclosure.md +176 -0
  79. package/skills/creating-skills/references/scripts.md +166 -0
  80. package/skills/creating-skills/references/skills.md +165 -0
  81. package/skills/creating-skills/scripts/scaffold.rb +313 -0
  82. package/skills/dashboard/SKILL.md +13 -11
  83. package/skills/dashboard/references/classification.md +22 -0
  84. package/skills/doctor/SKILL.md +10 -7
  85. package/skills/executing-plan/SKILL.md +4 -4
  86. package/skills/humanizer/SKILL.md +39 -0
  87. package/skills/humanizer/evals/evals.json +70 -0
  88. package/skills/humanizer/references/always-on-snippet.md +9 -0
  89. package/skills/humanizer/references/examples.md +48 -0
  90. package/skills/install/SKILL.md +75 -84
  91. package/skills/intent-curator/SKILL.md +5 -1
  92. package/skills/intent-discovery/SKILL.md +47 -0
  93. package/skills/intent-starting/SKILL.md +130 -0
  94. package/skills/intent-starting/evals/evals.json +117 -0
  95. package/skills/intent-starting/references/boarding-matrix.md +35 -0
  96. package/skills/linking-intents/SKILL.md +48 -12
  97. package/skills/linking-intents/references/zettelkasten.md +7 -0
  98. package/skills/lock/SKILL.md +41 -0
  99. package/skills/managing-index/SKILL.md +6 -0
  100. package/skills/managing-index/references/zettelkasten-linking.md +6 -1
  101. package/skills/releasing/SKILL.md +44 -29
  102. package/skills/releasing/references/promotion-and-tagging.md +60 -0
  103. package/skills/roadmap/SKILL.md +51 -0
  104. package/skills/roadmap/references/file-format.md +91 -0
  105. package/skills/roadmap/references/operations.md +78 -0
  106. package/skills/uninstall/SKILL.md +29 -11
  107. package/skills/update/SKILL.md +34 -23
  108. package/skills/versions/SKILL.md +27 -12
  109. package/skills/writing-plans/SKILL.md +10 -88
  110. package/skills/writing-plans/references/plan-format.md +102 -0
  111. package/templates/config.yml +8 -0
  112. package/templates/outcome.md +3 -0
  113. package/templates/revisions.md +58 -0
  114. package/templates/roadmap.md +30 -0
  115. package/skills/writing-instructions/SKILL.md +0 -159
  116. package/skills/writing-instructions/references/agentskills-spec.md +0 -135
@@ -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`.
@@ -6,34 +6,70 @@ description: Use when creating connections between intents, the user says "link"
6
6
  # Linking Intents
7
7
 
8
8
  ## When to Use
9
- - During intent creation (automatic ask about related intents)
9
+ - During intent creation (automatic: ask about related intents)
10
10
  - User says "link", "connect", "relates to"
11
11
  - Agent discovers a relationship between intents during work
12
12
 
13
- ## Connection Types (Ranked by Strength)
13
+ ## Discovery and ranking are separate
14
14
 
15
- ### 1. Direct Links (Strongest)
16
- Explicit wikilinks in the `## Links` section. Bidirectional — add to both intents.
15
+ Two distinct steps, do not conflate them:
17
16
 
18
- ```markdown
19
- ## Links
20
- - [[1a]] research this plan is based on
21
- ```
17
+ 1. **Discovery** (finding candidate related intents) may use any tool: grep, find, ripgrep,
18
+ or QMD/Serena when present (QMD-first per the project rule). Discovery casts a wide net.
19
+ 2. **Ranking** the candidates is a CONTEXT-INFLUENCE judgement: read each candidate's `## Intent`
20
+ and `## Context` and ask whether that context actually informed this intent. Ranking is NOT a
21
+ structural metric (no shared-file or shared-symbol grading: on intent 90, matching whole files
22
+ flagged 35 intents because ~20 touch `bridge.rb`). It is NOT a similarity score either (QMD
23
+ relevance measures topic proximity, not influence). A script cannot make this call; an agent
24
+ does.
25
+
26
+ ## The three tiers (by context influence)
27
+
28
+ - **sources:** the foundational context that shaped this intent's CREATION (a split, an idea born
29
+ during development, a merge). Earns an edge. Decided by origin, never inferred.
30
+ - **chain:** the context that materially helps DELIVER this intent. HIGH bar: only the genuinely
31
+ delivery-moving intents, not everything in the same area. Earns an edge, reflected in `## Links`.
32
+ Worked example (intent 90): 79 created it so 79 is a source; 80 deferred the exact fix 90 makes,
33
+ so its context directly helps delivery and 80 is chain; 49/66/73 are same-area background, so
34
+ they get a shared tag and no link.
35
+ - **tags:** loose theme grouping for search. NOT a link.
36
+
37
+ **Timing.** The influence judgement happens at What/Why (and during upkeep), guided by this rule.
38
+ It does not wait for code to exist; it is reasoning over the candidate's context, not over a diff.
39
+
40
+ **Record the call.** For every edge an agent adds, store a rating (high / medium / low) plus a
41
+ one-line reason as a dated line under the intent file's `## Insights` section (per 96 D3, link
42
+ rationale lives in the intent file, not a side file). It stays out of frontmatter (graph only) and
43
+ out of the projected `## Links` label, so the audit trail never breaks the projection identity.
44
+
45
+ ## `## Links` is derived (never author it by hand)
46
+
47
+ `## Links` is a DERIVED view of `sources` then `chain`, not a place to write links. Never
48
+ hand-write a `## Links` line, and never auto-delete one. To add a link, add the frontmatter
49
+ edge (below), then let the projection regenerate the section (`scripts/project-links`).
50
+
51
+ Run `scripts/link-suggest <id>` to gather candidate intents WITH each one's Intent and Context (the
52
+ evidence you judge influence on) and to flag drift (a `## Links` line with no frontmatter edge
53
+ behind it). To record a confirmed edge plus its rating and reason, run it with
54
+ `--record <id> --edge <sources|chain> --rating <high|medium|low> --reason "..." --confirm`. It never
55
+ grades influence itself, never writes an edge without `--confirm`, and never deletes.
56
+
57
+ ## Connection Types (the frontmatter edges)
22
58
 
23
- ### 2. Sources (Backward)
59
+ ### 1. Sources (Backward)
24
60
  The `sources` array in frontmatter. The direct ascendant(s) this intent was created from / emerged from the lifecycle of (formation, not topic similarity), backward links to the work it was built out of:
25
61
  ```yaml
26
62
  sources: ["1a", "1a2"]
27
63
  ```
28
64
 
29
- ### 3. Chain (Forward)
65
+ ### 2. Chain (Forward)
30
66
  The `chain` array in frontmatter. What this intent spawned AND related-but-not-spawned successors it leads to, forward links to children, follow-on, and related work:
31
67
  ```yaml
32
68
  chain: ["1b1", "1b2"]
33
69
  ```
34
70
 
35
- ### 4. Tags (Weakest)
36
- Shared tags in frontmatter enable filtered discovery. Use `project-<name>` tags for project membership.
71
+ ### 3. Tags (for discovery, not links)
72
+ Shared tags in frontmatter enable filtered discovery. Use `project-<name>` tags for project membership. A shared tag is a loose theme grouping: it earns NO edge.
37
73
  ```yaml
38
74
  tags: [plastic, project-reddit-kb]
39
75
  ```
@@ -10,6 +10,13 @@ Plastic implements three Zettelkasten structures:
10
10
 
11
11
  INDEX.md is a structure note (hub), not a table of contents.
12
12
 
13
+ `## Links` mirrors the frontmatter graph exactly. Each entry is
14
+ `- [[id--slug|<target's full intent: text>]]` (cross-store: `- [[store:id--slug|...]]`),
15
+ a clickable `id--slug` target with the target's full `intent:` text as the label.
16
+ Ordering is mandatory: all `sources` first (top), then all `chain`, frontmatter order
17
+ preserved within each group. Sources never appear at the end. No source/chain tags, no
18
+ sub-grouping. An intent with empty `sources` and `chain` carries the empty-state comment.
19
+
13
20
  ## Folgezettel IDs
14
21
 
15
22
  IDs encode lineage using Luhmann's alternating convention:
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: lock
3
+ description: Inspect, repair, release, or reclaim an intent's delivery lock. Use when a lock-gate deny names /plastic-lock, when resuming interrupted work after a crash, reboot, or /tmp wipe, when a lock reads held or stale, or when the user says "fix the lock", "who holds the lock", or "reclaim the lock".
4
+ ---
5
+
6
+ # Plastic Lock
7
+
8
+ Command-only wrapper around `~/.plastic/scripts/plastic-lock`. The durable
9
+ delivery lock is a `delivery.lock` file in the intent directory: ownership is
10
+ session-keyed, liveness is a lease (the owner's hooks refresh the file mtime;
11
+ stale means the heartbeat is older than the TTL). The /tmp bridge is only a
12
+ cache; the lock file wins every disagreement.
13
+
14
+ ## Verbs
15
+
16
+ Run from the project (the intent resolves from this session's bridge), or pass
17
+ `--intent-dir` explicitly:
18
+
19
+ | Verb | What it does | When |
20
+ |---|---|---|
21
+ | `status` | Report the lock file, bridge cache, freshness, agreement | Always safe; run first |
22
+ | `fix` | Idempotent repair: rebuild lock + bridge from disk truth for THIS session. Never touches a fresh foreign lock | Interrupted work, corrupted state, /tmp wiped, legacy pid locks |
23
+ | `release` | Owner clears the lock | Ending or abandoning a boarding |
24
+ | `reclaim` | Explicit takeover of a STALE lock; appends an audit line to savepoint.md | The owner is gone and the lease expired |
25
+ | `delegate` | Owner registers a subagent session under the lock (`--delegate <session-id>`) | Auto-mode orchestration |
26
+
27
+ ```
28
+ ruby ~/.plastic/scripts/plastic-lock status
29
+ ruby ~/.plastic/scripts/plastic-lock fix --intent-dir <store>/<id>--<slug>
30
+ ruby ~/.plastic/scripts/plastic-lock reclaim --intent-dir <store>/<id>--<slug>
31
+ ruby ~/.plastic/scripts/plastic-lock delegate --delegate <subagent-session-id>
32
+ ```
33
+
34
+ ## Rules
35
+
36
+ - `fix` exits non-zero when another session holds a FRESH lock: back off, do
37
+ not retry in a loop. `status` shows the owner.
38
+ - `reclaim` refuses a fresh lock. There is no silent reclaim anywhere; every
39
+ takeover is audited in the intent's savepoint.md.
40
+ - Acquiring a lock for new work is NOT this skill's job: board through
41
+ `/plastic-intent-starting`, which calls the same repair internally.
@@ -41,6 +41,12 @@ Topic-based groupings. Manually curated. Create a new cluster when 3+ intents sh
41
41
  ### Completed
42
42
  All completed intents with dates. Links preserved, never deleted.
43
43
 
44
+ When you move an intent INTO Completed or Abandoned, run the closing acts of the transfer in the canonical End-tail order (see PLASTIC.md `## Delivery Isolation and the Single-Owner Lock`):
45
+
46
+ 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).
47
+ 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.
48
+ 3. Refresh the QMD index for that store LAST, after the terminal move and savepoint (no-op when QMD is absent), in the background so it never blocks: `ruby ~/.plastic/scripts/qmd-sync reindex --store <store-root> --async`.
49
+
44
50
  ## Workflow
45
51
 
46
52
  QMD-first (when available): when you need to locate a specific intent (to reclassify, flag, or
@@ -8,7 +8,12 @@
8
8
 
9
9
  ## Three Connection Types (Ranked)
10
10
 
11
- 1. **Direct links** (strongest) wikilinks in `## Links` section
11
+ 1. **Direct links** (strongest): wikilinks in the `## Links` section, the projection of the
12
+ frontmatter graph. Each entry is `- [[id--slug|<target's full intent: text>]]` (cross-store:
13
+ `- [[store:id--slug|...]]`), a clickable `id--slug` target labeled with the target's full
14
+ `intent:` text. Ordering is mandatory: all `sources` first (top), then all `chain`,
15
+ frontmatter order preserved within each group. Sources never appear at the end. No
16
+ source/chain tags, no sub-grouping.
12
17
  2. **Sources/Chain** (knowledge graph): `sources` = direct ascendants this was created from (formation, acyclic, must-load); `chain` = forward continuations and related successors (may cycle, lighter context). See `docs/concepts/how-plastic-sources-and-chains-intents.md` for the full model.
13
18
  3. **Tags** (weakest) — shared tags, `project-<name>` for project membership
14
19
 
@@ -20,6 +20,7 @@ Project configuration drives the workflow - no hardcoded assumptions.
20
20
  - [ ] Run post-push actions (GitHub release, npm publish, etc.)
21
21
  - [ ] Verify release sync (npm dist-tag, GitHub "Latest", git tag all show the new version)
22
22
  - [ ] Complete active intent
23
+ - [ ] Clean up the intent's worktrees (merge-then-remove)
23
24
 
24
25
  ## Workflow
25
26
 
@@ -84,6 +85,12 @@ git merge <branch-name> --no-ff -m "feat: merge intent [ID] - [description]"
84
85
 
85
86
  Always `--no-ff` to preserve branch history in the merge commit.
86
87
 
88
+ **Worktree-isolated intents (intent 73c3).** A worktree-delivered intent's code lives on
89
+ `plastic/{id}--{slug}`, merged together with cleanup in step 9, not on a hand-made feature
90
+ branch. Do not delete the worktree before its branch is merged, or the work is lost. For
91
+ the full rationale and the already-merged-by-hand no-op case, read
92
+ `references/promotion-and-tagging.md`.
93
+
87
94
  ### 4. Bump Version
88
95
 
89
96
  Determine which files to update from project.yml:
@@ -94,8 +101,20 @@ Determine which files to update from project.yml:
94
101
 
95
102
  Update the version string in each file, then commit:
96
103
 
104
+ **Cut the CHANGELOG entry.** Before committing, edit `CHANGELOG.md` at the repo root so
105
+ the changelog change rides this same version-bump commit and reaches the tag. Write one
106
+ line in the existing shape:
107
+
108
+ `` `<version>` - shipped <date>; collected <intent-id> (<one-line summary>) ``
109
+
110
+ Prepend it as the first bullet under `## Released` (newest-first). If this version was
111
+ sitting under `## Unreleased`, move it out of that section and into `## Released`. Keep
112
+ the line intent-centric narrative (which intents the cut collected and why), NOT commit
113
+ detail: step 5's tag-message changelog and step 7's `gh release create --generate-notes`
114
+ already own the commit-level detail, so do not duplicate it here.
115
+
97
116
  ```bash
98
- git add <version-files>
117
+ git add <version-files> CHANGELOG.md
99
118
  git commit -m "chore: bump version to X.Y.Z - [one-line summary]"
100
119
  ```
101
120
 
@@ -207,6 +226,27 @@ A release IS a delivery. The active intent that drove this work must be complete
207
226
 
208
227
  **If no active intent exists for this release**, that itself is a problem - work happened outside the intent system. Log it and move on, but flag it.
209
228
 
229
+ ### 9. Clean Up the Intent's Worktrees (merge-then-remove)
230
+
231
+ A release is the merge-then-remove path for the intent's worktrees (intent 73c3): the
232
+ intent's code branch is merged back into the default branch BEFORE the worktree is removed.
233
+ Drive it through `Worktree.finish` with `merge: true`, which merges the code branch, then
234
+ removes both worktrees (code + paired store), prunes both repos, and clears the worktree block
235
+ from the bridge:
236
+
237
+ ```bash
238
+ ruby -r ~/.plastic/scripts/lib/worktree -r ~/.plastic/scripts/lib/bridge -e \
239
+ 'b = Bridge.discover_bridge(session: ENV["CLAUDE_CODE_SESSION_ID"], cwd: Dir.pwd); Worktree.finish(b, merge: true) if b'
240
+ ```
241
+
242
+ (Uses `discover_bridge`, not a bare session-keyed `Bridge.read`, because a session can own more
243
+ than one live bridge now — intent 131 — and `discover_bridge` resolves the right one for this cwd.)
244
+
245
+ Honor the worktree-cleanup rule: never leave an orphaned worktree, and run `git worktree
246
+ prune` in the affected repo if you hit a stale reference. For why this is the one place the
247
+ merge-vs-remove policy lands on merge, and the fail-open/idempotent guarantees of `finish`,
248
+ read `references/promotion-and-tagging.md`.
249
+
210
250
  ## Conventions
211
251
 
212
252
  - **Annotated tags only** - `git tag -a`, never lightweight tags
@@ -219,34 +259,9 @@ A release IS a delivery. The active intent that drove this work must be complete
219
259
  - **Verify sync** - after pushing, confirm npm dist-tag, GitHub "Latest", and the git tag all show the new version
220
260
  - **Branch cleanup** - delete merged feature branches: `git branch -d <branch>`
221
261
 
222
- ## Promotion
223
-
224
- To promote a release across channels, use `--promote`:
225
-
226
- ```bash
227
- plastic-releasing --promote beta # promotes current alpha → beta
228
- plastic-releasing --promote stable # promotes current beta → stable
229
- ```
230
-
231
- **Promotion rules:**
232
- - Linear only: alpha → beta → stable. Cannot skip channels.
233
- - `--promote beta`: reads version from `package.json`, changes `-alpha.N` suffix
234
- to `-beta.1`, publishes with `--tag beta`.
235
- - `--promote stable`: reads version from `package.json`, strips pre-release suffix
236
- entirely (e.g., `1.0.0-beta.3` → `1.0.0`), publishes to `latest`.
237
- - Version files are bumped and committed as in a normal release.
238
- - An annotated tag is created for the promoted version.
239
-
240
- ## Retroactive Tagging
241
-
242
- For repos without prior tags, tag historical releases:
243
-
244
- ```bash
245
- git tag -a v0.1.0 <commit-sha> -m "v0.1.0 - [description]"
246
- ```
247
-
248
- Use `git log --oneline` to find the right commits (look for version bump commits or major feature merges).
249
-
250
262
  ## References
251
263
 
264
+ - When promoting a pre-release across channels (`--promote beta`/`--promote stable`) or
265
+ tagging a historical release retroactively, read `references/promotion-and-tagging.md`
266
+ for the exact commands and rules first
252
267
  - Read `references/deprecations.md` for the full deprecation process, severity levels, deprecations.yml schema, and dismissal rules when adding or managing deprecations
@@ -0,0 +1,60 @@
1
+ # Promotion, Retroactive Tagging, and Worktree Merge Rationale
2
+
3
+ Occasional variant paths off the main release workflow: promoting a pre-release
4
+ across channels, tagging historical releases retroactively, and the deep rationale
5
+ for why the intent's worktree is merged before removal.
6
+
7
+ ## Table of Contents
8
+
9
+ - [Worktree merge-then-remove rationale](#worktree-merge-then-remove-rationale)
10
+ - [Promotion](#promotion)
11
+ - [Retroactive Tagging](#retroactive-tagging)
12
+
13
+ ## Worktree merge-then-remove rationale
14
+
15
+ **Worktree-isolated intents (intent 73c3).** When the intent was delivered in a Plastic
16
+ worktree (the bridge has a provisioned `worktree` block), its code lives on the branch
17
+ `plastic/{id}--{slug}` inside `<repo>/.claude/worktrees/{id}--{slug}`, not on a hand-made
18
+ feature branch. The merge-then-remove of that worktree is handled together with cleanup in
19
+ Workflow step 9, which merges `plastic/{id}--{slug}` into the default branch BEFORE removing the
20
+ worktree. If you already merged here by hand, step 9 is a clean no-op merge ("Already up to
21
+ date") and proceeds straight to removal. Do not delete the worktree before its branch is
22
+ merged, or the work is lost.
23
+
24
+ A release is the merge-then-remove path for the intent's worktrees. This is the one place
25
+ the merge-vs-remove policy lands on "merge": the intent's code branch (`plastic/{id}--{slug}`)
26
+ is merged back into the repo's default branch BEFORE the worktree is removed, so the
27
+ integrated work is never lost. (The disarm path in `plastic-auto`, by contrast, is a plain
28
+ remove because no release is merging the branch.)
29
+
30
+ `Worktree.finish` is fail-open and idempotent: a conflicting merge is aborted and logged (the
31
+ worktree is still removed rather than stranded), and a second call with the block already
32
+ cleared is a no-op.
33
+
34
+ ## Promotion
35
+
36
+ To promote a release across channels, use `--promote`:
37
+
38
+ ```bash
39
+ plastic-releasing --promote beta # promotes current alpha → beta
40
+ plastic-releasing --promote stable # promotes current beta → stable
41
+ ```
42
+
43
+ **Promotion rules:**
44
+ - Linear only: alpha → beta → stable. Cannot skip channels.
45
+ - `--promote beta`: reads version from `package.json`, changes `-alpha.N` suffix
46
+ to `-beta.1`, publishes with `--tag beta`.
47
+ - `--promote stable`: reads version from `package.json`, strips pre-release suffix
48
+ entirely (e.g., `1.0.0-beta.3` → `1.0.0`), publishes to `latest`.
49
+ - Version files are bumped and committed as in a normal release.
50
+ - An annotated tag is created for the promoted version.
51
+
52
+ ## Retroactive Tagging
53
+
54
+ For repos without prior tags, tag historical releases:
55
+
56
+ ```bash
57
+ git tag -a v0.1.0 <commit-sha> -m "v0.1.0 - [description]"
58
+ ```
59
+
60
+ Use `git log --oneline` to find the right commits (look for version bump commits or major feature merges).