@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.
- package/PLASTIC-reference.md +133 -0
- package/PLASTIC.md +398 -82
- package/README.md +99 -82
- package/agents/plastic-brainstorming.md +12 -9
- package/agents/plastic-enforcer.md +52 -12
- package/agents/plastic-executor.md +10 -10
- package/agents/plastic-future-intent-researcher.md +4 -8
- package/agents/plastic-intent-curator.md +12 -14
- package/agents/plastic-intent-discovery.md +35 -0
- package/agents/plastic-planner.md +15 -10
- package/agents/plastic-spec-specialist.md +15 -10
- package/bin/plastic.js +7 -3
- package/hooks/code-gate +10 -1
- package/hooks/hooks.json +28 -3
- package/hooks/lock-gate +21 -0
- package/hooks/retrieval-gate +10 -0
- package/hooks/savepoint-pre +10 -0
- package/hooks/statusline +48 -6
- package/package.json +2 -1
- package/scripts/agent-report +21 -0
- package/scripts/dashboard.rb +98 -23
- package/scripts/doctor.rb +232 -5
- package/scripts/hook-auto-arm +1 -1
- package/scripts/hook-bash-gate +22 -4
- package/scripts/hook-code-gate +11 -6
- package/scripts/hook-continue +17 -0
- package/scripts/hook-create-gate +45 -9
- package/scripts/hook-gate-check +24 -23
- package/scripts/hook-lock-gate +83 -0
- package/scripts/hook-retrieval-gate +148 -0
- package/scripts/hook-savepoint-pre +32 -0
- package/scripts/hook-session-start +1 -1
- package/scripts/insight-append +51 -0
- package/scripts/install.rb +44 -7
- package/scripts/lib/agent_models.rb +43 -0
- package/scripts/lib/bridge.rb +924 -84
- package/scripts/lib/dashboard_banner.rb +42 -0
- package/scripts/lib/hook_registry.rb +95 -0
- package/scripts/lib/insights.rb +86 -0
- package/scripts/lib/installer_core.rb +100 -60
- package/scripts/lib/link_suggestions.rb +319 -0
- package/scripts/lib/lock.rb +375 -0
- package/scripts/lib/power_tools.rb +22 -21
- package/scripts/lib/preflight.rb +79 -0
- package/scripts/lib/qmd_sync.rb +15 -0
- package/scripts/lib/retrieval_gate.rb +211 -0
- package/scripts/lib/worktree.rb +384 -0
- package/scripts/link-suggest +213 -0
- package/scripts/new-intent +9 -1
- package/scripts/plastic-lock +164 -0
- package/scripts/read-config +4 -0
- package/scripts/spawn-preamble +11 -3
- package/scripts/update.rb +16 -7
- package/skills/auto/SKILL.md +126 -19
- package/skills/auto/references/agent-architecture.md +7 -4
- package/skills/auto/references/agent-report-contract.md +36 -1
- package/skills/auto/references/end-tail.md +56 -0
- package/skills/auto/references/human-report-contract.md +55 -0
- package/skills/auto/references/tiers.md +77 -0
- package/skills/brainstorming/SKILL.md +7 -34
- package/skills/brainstorming/references/design-principles.md +49 -0
- package/skills/continuing/SKILL.md +26 -7
- package/skills/creating-intent/SKILL.md +13 -28
- package/skills/creating-project/SKILL.md +11 -74
- package/skills/creating-project/references/project-scaffolding.md +97 -0
- package/skills/creating-skills/SKILL.md +65 -0
- package/skills/creating-skills/evals/evals.json +108 -0
- package/skills/creating-skills/references/agents.md +168 -0
- package/skills/creating-skills/references/evals.md +41 -0
- package/skills/creating-skills/references/hooks.md +248 -0
- package/skills/creating-skills/references/progressive-disclosure.md +176 -0
- package/skills/creating-skills/references/scripts.md +166 -0
- package/skills/creating-skills/references/skills.md +165 -0
- package/skills/creating-skills/scripts/scaffold.rb +313 -0
- package/skills/dashboard/SKILL.md +13 -11
- package/skills/dashboard/references/classification.md +22 -0
- package/skills/doctor/SKILL.md +10 -7
- package/skills/executing-plan/SKILL.md +4 -4
- package/skills/humanizer/SKILL.md +39 -0
- package/skills/humanizer/evals/evals.json +70 -0
- package/skills/humanizer/references/always-on-snippet.md +9 -0
- package/skills/humanizer/references/examples.md +48 -0
- package/skills/install/SKILL.md +75 -84
- package/skills/intent-curator/SKILL.md +5 -1
- package/skills/intent-discovery/SKILL.md +47 -0
- package/skills/intent-starting/SKILL.md +130 -0
- package/skills/intent-starting/evals/evals.json +117 -0
- package/skills/intent-starting/references/boarding-matrix.md +35 -0
- package/skills/linking-intents/SKILL.md +48 -12
- package/skills/lock/SKILL.md +41 -0
- package/skills/managing-index/SKILL.md +6 -0
- package/skills/releasing/SKILL.md +44 -29
- package/skills/releasing/references/promotion-and-tagging.md +60 -0
- package/skills/roadmap/SKILL.md +51 -0
- package/skills/roadmap/references/file-format.md +91 -0
- package/skills/roadmap/references/operations.md +78 -0
- package/skills/uninstall/SKILL.md +29 -11
- package/skills/update/SKILL.md +34 -23
- package/skills/versions/SKILL.md +27 -12
- package/skills/writing-plans/SKILL.md +10 -88
- package/skills/writing-plans/references/plan-format.md +102 -0
- package/templates/config.yml +8 -0
- package/templates/outcome.md +3 -0
- package/templates/revisions.md +58 -0
- package/templates/roadmap.md +30 -0
- package/skills/writing-instructions/SKILL.md +0 -159
- package/skills/writing-instructions/references/agentskills-spec.md +0 -135
|
@@ -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
|
|
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
|
-
##
|
|
13
|
+
## Discovery and ranking are separate
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
Explicit wikilinks in the `## Links` section. Bidirectional — add to both intents.
|
|
15
|
+
Two distinct steps, do not conflate them:
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
###
|
|
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
|
-
###
|
|
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
|
-
###
|
|
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
|
```
|
|
@@ -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
|
|
@@ -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).
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plastic-roadmap
|
|
3
|
+
description: Use when the user wants to plan a delivery batch, order waves of intents, ship a batch of tickets in one go, track a named collection of intents toward a goal, or asks for a "roadmap". Creates and maintains a roadmap file, a delivery-side collection of intents (the counterpart to a release), separate from INDEX.md status tracking.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Roadmap
|
|
7
|
+
|
|
8
|
+
A roadmap is a named, ordered, delivery-side collection of intents: the delivery-side counterpart
|
|
9
|
+
to a release (completion-side, `CHANGELOG.md`). It lives at `roadmaps/{slug}.md`, a sibling of
|
|
10
|
+
`INDEX.md` wherever `INDEX.md` lives: the global tier's `~/.plastic/roadmaps/` (beside
|
|
11
|
+
`~/.plastic/INDEX.md`), or a project's root, `~/.plastic/projects/{slug}/roadmaps/` (beside that
|
|
12
|
+
project's `INDEX.md` and `project.yml`). It never sits inside `store/`, which holds intent
|
|
13
|
+
directories, not project artifacts.
|
|
14
|
+
|
|
15
|
+
A roadmap file has four parts: a title/meta header, `## Goal` (prose), `## Waves` (ordered; entries
|
|
16
|
+
inside a wave are parallel-safe, waves run sequentially), and an append-only dated `## Log`. Each
|
|
17
|
+
wave entry mirrors that intent's status in `INDEX.md` (`queued`/`delivering`/`delivered`/
|
|
18
|
+
`abandoned`/`blocked`).
|
|
19
|
+
|
|
20
|
+
**`INDEX.md` is the single writer of intent status; on any conflict INDEX wins and the roadmap
|
|
21
|
+
entry is corrected to match.**
|
|
22
|
+
|
|
23
|
+
The skill operates on the file directly via Read/Edit; no helper script.
|
|
24
|
+
|
|
25
|
+
## Verbs
|
|
26
|
+
|
|
27
|
+
| Verb | When | Mechanics |
|
|
28
|
+
|------|------|-----------|
|
|
29
|
+
| Create | user wants to start a new roadmap / plan a delivery batch | `references/operations.md#create` |
|
|
30
|
+
| Add / reorder entries | user wants to add intents to a wave or resequence waves | `references/operations.md#add--reorder-entries` |
|
|
31
|
+
| Sync status mirror | an entry's status may be stale against INDEX | `references/operations.md#sync-status-mirror` |
|
|
32
|
+
| Append log line | a roadmap event just happened (created, wave done, closed) | `references/operations.md#append-a-log-line` |
|
|
33
|
+
| Read / consume | a human or a coordinator needs the roadmap's current state | `references/operations.md#read--consume` |
|
|
34
|
+
| Close / archive | the roadmap's `## Goal` is reached | `references/operations.md#close--archive` |
|
|
35
|
+
|
|
36
|
+
See `references/file-format.md` for the exact entry-line shape, status vocabulary, checkbox/log
|
|
37
|
+
format, and a worked example. See `references/operations.md` for step-by-step mechanics of each
|
|
38
|
+
verb above.
|
|
39
|
+
|
|
40
|
+
## Notes
|
|
41
|
+
|
|
42
|
+
- File location and the four-section shape are identical across tiers; do not invent a different
|
|
43
|
+
layout per project. The general rule: `roadmaps/` is a sibling of `INDEX.md`, wherever `INDEX.md`
|
|
44
|
+
lives.
|
|
45
|
+
- `## Goal` is a checkable prose condition read by a human or agent, not an executable checker.
|
|
46
|
+
- Wave entries render as checkboxes (`- [x] ... — delivered` / `- [ ] ... — <status>`); a human
|
|
47
|
+
reading cold should see shipped/running/next within a minute. `## Log` lines are one-sentence,
|
|
48
|
+
EM-to-CTO-voice, dated, and link each entry-intent's `outcome.md` (lossless-by-reference).
|
|
49
|
+
- Additive: this skill introduces no gate, lock, or hook, and does not change `INDEX.md`'s section
|
|
50
|
+
list or the intent frontmatter schema.
|
|
51
|
+
- Closing a roadmap moves it to `roadmaps/archived/{slug}.md` so `roadmaps/` lists only live ones.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Roadmap File Format
|
|
2
|
+
|
|
3
|
+
## Location
|
|
4
|
+
|
|
5
|
+
`roadmaps/{slug}.md`, a sibling of `INDEX.md`, wherever `INDEX.md` lives. For the global tier
|
|
6
|
+
that is `~/.plastic/roadmaps/{slug}.md` (beside `~/.plastic/INDEX.md`); for any project it is
|
|
7
|
+
that project's root, `~/.plastic/projects/{slug}/roadmaps/{slug}.md` (beside that project's
|
|
8
|
+
`INDEX.md` and `project.yml`). `roadmaps/` never sits inside `store/`: `store/` holds intent
|
|
9
|
+
directories, not project artifacts. Create the `roadmaps/` directory the first time a tier gets a
|
|
10
|
+
roadmap.
|
|
11
|
+
|
|
12
|
+
`roadmaps/` lists only live (open or in-flight) roadmaps. Once a roadmap's `## Goal` is reached,
|
|
13
|
+
its file moves to `roadmaps/archived/{slug}.md` (see Close/archive in `operations.md`); the
|
|
14
|
+
`archived/` subdirectory is scaffolded once, alongside `roadmaps/`, with a `.gitkeep`.
|
|
15
|
+
|
|
16
|
+
## The four sections (in order)
|
|
17
|
+
|
|
18
|
+
1. **Title/meta header** — `# Roadmap: <name>` plus a one-line meta sentence naming what the
|
|
19
|
+
roadmap delivers and which tier (project or global) it lives in.
|
|
20
|
+
2. **`## Goal`** — a checkable prose condition: one or a few sentences a human or coordinator reads
|
|
21
|
+
to decide the roadmap is done. Not an executable checker, not a list of tasks.
|
|
22
|
+
3. **`## Waves`** — ordered waves (`### Wave 1`, `### Wave 2`, ...). Entries inside a wave are
|
|
23
|
+
parallel-safe (can be dispatched together); waves run top to bottom, sequentially (wave 2 does
|
|
24
|
+
not start until wave 1's entries are no longer `queued`/`delivering`).
|
|
25
|
+
4. **`## Log`** — append-only, dated, one line per event. Newest entry at the bottom. Never edit or
|
|
26
|
+
remove an existing log line.
|
|
27
|
+
|
|
28
|
+
## Entry line shape
|
|
29
|
+
|
|
30
|
+
One line per intent, inside its wave, as a Markdown checkbox:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
- [x] <intent-id> <title> — delivered
|
|
34
|
+
- [ ] <intent-id> <title> — <status>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`<intent-id>` and `<title>` match the intent's `INDEX.md` entry (terse, not a summary). The
|
|
38
|
+
checkbox is checked (`[x]`) once `<status>` is `delivered`, unchecked (`[ ]`) for every other
|
|
39
|
+
status. The checkbox is a rendering of the mirrored status token, not a second piece of state: a
|
|
40
|
+
human scanning the file sees at a glance what shipped (checked) and what has not (unchecked),
|
|
41
|
+
while the trailing token still carries the precise state (`queued`/`delivering`/`blocked`/
|
|
42
|
+
`abandoned`) when unchecked.
|
|
43
|
+
|
|
44
|
+
## Status vocabulary
|
|
45
|
+
|
|
46
|
+
`queued` | `delivering` | `delivered` | `abandoned` | `blocked`
|
|
47
|
+
|
|
48
|
+
Status is a **mirror** of `INDEX.md`. `INDEX.md` is the single writer of intent status; on any
|
|
49
|
+
conflict INDEX wins and the roadmap entry (both its token and its checkbox) is corrected to match
|
|
50
|
+
it. The roadmap never sets a status that INDEX does not already reflect.
|
|
51
|
+
|
|
52
|
+
## Log line shape
|
|
53
|
+
|
|
54
|
+
One line per event, starting `YYYY-MM-DD HH:MM UTC` (human-readable, sortable, zone-explicit so
|
|
55
|
+
same-day parallel deliveries can still be ordered), in plain-language EM-to-CTO voice: what shipped
|
|
56
|
+
and why it matters to a non-expert reader, no jargon or internal codenames, ending with a link to
|
|
57
|
+
that entry-intent's `outcome.md`:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
- <YYYY-MM-DD HH:MM UTC> <one plain-language sentence: what shipped, its impact> — see store/<id>--<slug>/outcome.md
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The log line never restates `outcome.md` detail; it points at it (lossless-by-reference). This
|
|
64
|
+
complements, and does not replace, `INDEX.md`'s `## Completed` section or `CHANGELOG.md`.
|
|
65
|
+
|
|
66
|
+
## Worked example
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
# Roadmap: Stable 1.0
|
|
70
|
+
|
|
71
|
+
Delivery-side collection of intents that close out the pre-1.0 hardening pass, plastic project store.
|
|
72
|
+
|
|
73
|
+
## Goal
|
|
74
|
+
All intents below are delivered, the suite is green, and a 1.0.0 release is cut.
|
|
75
|
+
|
|
76
|
+
## Waves
|
|
77
|
+
Entries in a wave are parallel-safe; waves run top to bottom. The checkbox tracks delivered/not;
|
|
78
|
+
the token after the em-dash carries the precise mirrored status (queued | delivering | delivered |
|
|
79
|
+
abandoned | blocked); INDEX wins on any conflict.
|
|
80
|
+
|
|
81
|
+
### Wave 1
|
|
82
|
+
- [x] 121 Fix bash gate redirect parsing — delivered
|
|
83
|
+
- [ ] 130 Proportional cycle tiers — delivering
|
|
84
|
+
|
|
85
|
+
### Wave 2
|
|
86
|
+
- [x] 124 Roadmap feature — delivered
|
|
87
|
+
|
|
88
|
+
## Log
|
|
89
|
+
- 2026-07-06 14:32 UTC Shipped the bash-gate redirect fix so quoted arrows and heredoc trailers
|
|
90
|
+
stop blocking legitimate commits — see store/121--fix-bash-gate-redirect-parsing/outcome.md.
|
|
91
|
+
```
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Roadmap Operations
|
|
2
|
+
|
|
3
|
+
All six verbs operate on the Markdown file directly (Read/Edit). No helper script exists or is
|
|
4
|
+
needed; the file is small and the edits are mechanical.
|
|
5
|
+
|
|
6
|
+
**Human-comprehension goal.** Every operation below should leave the file such that a cold reader
|
|
7
|
+
(no INDEX.md, no intent directories open) can answer "what's shipped, what's running, what's
|
|
8
|
+
next" in under a minute, just from this one file.
|
|
9
|
+
|
|
10
|
+
## Create
|
|
11
|
+
|
|
12
|
+
1. Pick a `slug` (kebab-case, descriptive) and a `title`.
|
|
13
|
+
2. Resolve the tier root: the directory that holds `INDEX.md` (a project's root, beside
|
|
14
|
+
`project.yml`, or `~/.plastic/` for the global tier). `roadmaps/` is always a sibling of
|
|
15
|
+
`INDEX.md`, never inside `store/`. Create `roadmaps/` there if it does not exist yet.
|
|
16
|
+
3. Copy `templates/roadmap.md` to `roadmaps/{slug}.md`.
|
|
17
|
+
4. Fill the header (`# Roadmap: <title>` + the one-line meta) and write a real `## Goal` prose
|
|
18
|
+
condition.
|
|
19
|
+
5. Add at least one `## Waves` wave with real entries (see Add / reorder below), each entry's
|
|
20
|
+
status mirroring that intent's current `INDEX.md` status.
|
|
21
|
+
6. Append the first `## Log` line, a short `YYYY-MM-DD HH:MM UTC`-prefixed plain-language note
|
|
22
|
+
that the roadmap was created.
|
|
23
|
+
|
|
24
|
+
## Add / reorder entries
|
|
25
|
+
|
|
26
|
+
- **Add**: append an entry line (`- <intent-id> <title> — <status>`) to the target wave. Pick the
|
|
27
|
+
intent's title and status straight from `INDEX.md`.
|
|
28
|
+
- **New wave**: add a new `### Wave N` heading after the last wave; entries in it are gated behind
|
|
29
|
+
every earlier wave's entries leaving `queued`/`delivering`.
|
|
30
|
+
- **Reorder**: move an entry line to a different wave, or move a `### Wave` heading (with its
|
|
31
|
+
entries) earlier or later. Reordering never changes an entry's status; it only changes when the
|
|
32
|
+
entry is eligible to run.
|
|
33
|
+
- After any add/reorder, append a `## Log` line describing the change (e.g.
|
|
34
|
+
`- <YYYY-MM-DD HH:MM UTC> added 132 to wave 2`).
|
|
35
|
+
|
|
36
|
+
## Sync status mirror
|
|
37
|
+
|
|
38
|
+
1. Read the intent's real status from `INDEX.md` (`## Active`, `## Future`, `## Completed`, or
|
|
39
|
+
`## Abandoned`).
|
|
40
|
+
2. Compare to the roadmap entry's `<status>` token.
|
|
41
|
+
3. If they differ, **INDEX wins**: rewrite the roadmap entry's status token to match INDEX, and
|
|
42
|
+
flip its checkbox in the same edit (`[x]` when the new status is `delivered`, `[ ]` otherwise).
|
|
43
|
+
Never edit INDEX.md from the roadmap skill; the roadmap is a mirror, not a second writer.
|
|
44
|
+
4. Append a `## Log` line recording the change. When the new status is `delivered`, write the
|
|
45
|
+
one-line EM-to-CTO entry described in `file-format.md` (date, what shipped and its impact in
|
|
46
|
+
plain language, then a link to that intent's `outcome.md`). For other transitions, write a
|
|
47
|
+
short dated plain-language line (no codenames, no jargon).
|
|
48
|
+
|
|
49
|
+
## Append a log line
|
|
50
|
+
|
|
51
|
+
- One line per event, starting `YYYY-MM-DD HH:MM UTC`, appended at the bottom of `## Log`. Never
|
|
52
|
+
edit or delete an existing line (append-only).
|
|
53
|
+
- Every line is plain language a non-expert can read, never a codename or a raw `field -> value`.
|
|
54
|
+
A delivery event follows the EM-to-CTO one-line shape with an `outcome.md` link (see
|
|
55
|
+
`file-format.md`); bookkeeping events (created, an intent added to a wave, a wave completed, a
|
|
56
|
+
roadmap closed) are short dated plain-language lines.
|
|
57
|
+
|
|
58
|
+
## Read / consume
|
|
59
|
+
|
|
60
|
+
- A human reading the file gets the current picture directly: `## Goal` for the target, `## Waves`
|
|
61
|
+
for what is queued/delivering/delivered per wave (checkboxes give the shipped/not-shipped view at
|
|
62
|
+
a glance), `## Log` for a one-line, plain-language history with a link into each intent's
|
|
63
|
+
`outcome.md` for detail.
|
|
64
|
+
- A future coordinator (for example, an auto-mode dispatcher) reads `## Waves` top to bottom:
|
|
65
|
+
a wave is eligible to dispatch once every entry in the previous wave is no longer
|
|
66
|
+
`queued`/`delivering`; within an eligible wave, entries still `queued` are parallel-dispatchable.
|
|
67
|
+
Always re-sync against `INDEX.md` before dispatch decisions, since INDEX is the source of truth.
|
|
68
|
+
|
|
69
|
+
## Close / archive
|
|
70
|
+
|
|
71
|
+
1. Confirm the roadmap's `## Goal` prose condition is met (every entry `delivered` or explicitly
|
|
72
|
+
`abandoned` with a recorded reason, plus whatever else the goal states).
|
|
73
|
+
2. Create `roadmaps/archived/` beside `roadmaps/` (both siblings of `INDEX.md`) if it does not
|
|
74
|
+
exist yet.
|
|
75
|
+
3. Move the file: `roadmaps/{slug}.md` -> `roadmaps/archived/{slug}.md`. `roadmaps/` itself then
|
|
76
|
+
lists only live (open or in-flight) roadmaps.
|
|
77
|
+
4. Append the final `## Log` line before or as part of the move:
|
|
78
|
+
`- <YYYY-MM-DD HH:MM UTC> roadmap closed`.
|
|
@@ -9,15 +9,21 @@ The installer tracks every file it writes in a manifest, so uninstall is exact a
|
|
|
9
9
|
leaves no orphans. Prefer running it through the CLI; this skill wraps the same
|
|
10
10
|
underlying uninstaller and adds reporting + verification.
|
|
11
11
|
|
|
12
|
+
## Channel rule
|
|
13
|
+
|
|
14
|
+
If Plastic is installed, derive `<channel>` from `~/.plastic/VERSION`: a version containing
|
|
15
|
+
`-alpha` means `@alpha`, `-beta` means `@beta`, otherwise `@latest`. If not installed,
|
|
16
|
+
default to `@beta`. The user can always override with `--alpha` / `--beta` / `--latest`.
|
|
17
|
+
|
|
12
18
|
## Procedure
|
|
13
19
|
|
|
14
20
|
### Step 1: Run the uninstaller
|
|
15
21
|
|
|
16
22
|
```bash
|
|
17
|
-
npx @zalom/plastic
|
|
23
|
+
npx -y @zalom/plastic@<channel> uninstall --claude
|
|
18
24
|
```
|
|
19
25
|
|
|
20
|
-
(Use `--codex` / `--hermes` / `--all` to target other agents. `bunx` works too.)
|
|
26
|
+
(Use `--codex` / `--hermes` / `--all` to target other agents. `bunx -y @zalom/plastic@<channel> uninstall --claude` works too.)
|
|
21
27
|
|
|
22
28
|
This removes, for the targeted agent:
|
|
23
29
|
- all `~/.claude/skills/plastic-*/` skills
|
|
@@ -29,8 +35,8 @@ This removes, for the targeted agent:
|
|
|
29
35
|
|
|
30
36
|
### Step 2: Report removed vs left
|
|
31
37
|
|
|
32
|
-
Relay the uninstaller's output to the user
|
|
33
|
-
**left in place
|
|
38
|
+
Relay the uninstaller's output to the user: what was **removed** and what was
|
|
39
|
+
**left in place**.
|
|
34
40
|
- **Left:** `~/.plastic/` (intent store, history, projects) and any non-Plastic
|
|
35
41
|
settings.json entries.
|
|
36
42
|
|
|
@@ -39,21 +45,33 @@ Relay the uninstaller's output to the user — what was **removed** and what was
|
|
|
39
45
|
Tell the user to confirm:
|
|
40
46
|
|
|
41
47
|
```bash
|
|
42
|
-
ls ~/.claude/skills | grep '^plastic-' #
|
|
43
|
-
ls ~/.claude/hooks | grep '^plastic-' #
|
|
44
|
-
grep -n plastic ~/.claude/settings.json #
|
|
48
|
+
ls ~/.claude/skills | grep '^plastic-' # -> no output
|
|
49
|
+
ls ~/.claude/hooks | grep '^plastic-' # -> no output
|
|
50
|
+
grep -n plastic ~/.claude/settings.json # -> no plastic hook/plugin refs
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Step 4: Report + offer the data decision
|
|
54
|
+
|
|
55
|
+
Emit the reporting block, using the Step 3 checks for the verification line:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
Plastic uninstall (<channel>)
|
|
59
|
+
Command: npx -y @zalom/plastic@<channel> uninstall --claude <flags>
|
|
60
|
+
Version: removed
|
|
61
|
+
Verification: <Step 3 results, or "clean">
|
|
45
62
|
```
|
|
46
63
|
|
|
47
|
-
|
|
64
|
+
Then:
|
|
48
65
|
|
|
49
66
|
```
|
|
50
67
|
Plastic is uninstalled from [agent].
|
|
51
68
|
Your intent store at ~/.plastic/ is untouched.
|
|
52
69
|
|
|
53
70
|
Delete it too?
|
|
54
|
-
a) Keep everything (recommended)
|
|
55
|
-
b) Delete everything now
|
|
71
|
+
a) Keep everything (recommended): re-install anytime with npx
|
|
72
|
+
b) Delete everything now: removes ~/.plastic/ entirely (irreversible)
|
|
56
73
|
```
|
|
57
74
|
|
|
58
|
-
- **Keep:** "Your data is at ~/.plastic/. Re-install anytime with
|
|
75
|
+
- **Keep:** "Your data is at ~/.plastic/. Re-install anytime with
|
|
76
|
+
`npx -y @zalom/plastic@beta install --claude` (or your channel)."
|
|
59
77
|
- **Delete:** run `rm -rf ~/.plastic/` and confirm.
|