@zalom/plastic 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PLASTIC.md +12 -9
- package/README.md +3 -3
- package/agents/plastic-enforcer.md +8 -4
- package/agents/plastic-executor.md +5 -5
- package/agents/plastic-future-intent-researcher.md +1 -1
- package/agents/plastic-planner.md +15 -11
- package/hooks/check-update +1 -1
- package/hooks/continue +1 -1
- package/package.json +1 -1
- package/scripts/dashboard.rb +29 -24
- package/scripts/doctor.rb +180 -5
- package/scripts/hook-continue +3 -3
- package/scripts/install.rb +2 -1
- package/scripts/lib/bridge.rb +114 -11
- package/scripts/lib/dashboard_banner.rb +8 -9
- package/scripts/lib/installer_core.rb +12 -3
- package/scripts/lib/legacy_bookend_amnesty.rb +35 -0
- package/scripts/lib/release_guard.rb +62 -0
- package/scripts/lib/roadmap_queue.rb +285 -0
- package/scripts/lib/roadmap_savepoint.rb +213 -0
- package/scripts/lib/skill_lint.rb +304 -0
- package/scripts/lib/worktree.rb +21 -0
- package/scripts/new-intent +1 -0
- package/scripts/read-config +3 -3
- package/scripts/roadmap-next +44 -0
- package/scripts/roadmap-savepoint +64 -0
- package/scripts/skill-lint +50 -0
- package/skills/auto/SKILL.md +32 -11
- package/skills/auto/references/tiers.md +4 -3
- package/skills/continuing/SKILL.md +34 -0
- package/skills/continuing/evals/evals.json +91 -0
- package/skills/dashboard/SKILL.md +17 -14
- package/skills/dashboard/references/classification.md +3 -3
- package/skills/dashboard/templates/dashboard-global.md +8 -23
- package/skills/dashboard/templates/dashboard-project.md +7 -26
- package/skills/doctor/SKILL.md +1 -1
- package/skills/install/SKILL.md +10 -10
- package/skills/intent-continuing/SKILL.md +26 -68
- package/skills/intent-continuing/evals/evals.json +26 -26
- package/skills/intent-continuing/references/context-management.md +15 -19
- package/skills/intent-planning/SKILL.md +11 -11
- package/skills/intent-planning/evals/evals.json +20 -5
- package/skills/intent-planning/references/plan-format.md +9 -5
- package/skills/intent-savepoint/SKILL.md +12 -0
- package/skills/intent-starting/evals/evals.json +1 -1
- package/skills/project-continuing/SKILL.md +104 -0
- package/skills/project-continuing/evals/evals.json +100 -0
- package/skills/project-continuing/references/board-fill.md +33 -0
- package/skills/releasing/SKILL.md +48 -0
- package/skills/releasing/references/release-lines.md +105 -0
- package/skills/roadmap/SKILL.md +7 -1
- package/skills/roadmap/references/file-format.md +30 -1
- package/skills/roadmap/references/operations.md +26 -6
- package/skills/roadmap-continuing/SKILL.md +85 -0
- package/skills/roadmap-continuing/evals/evals.json +82 -0
- package/skills/roadmap-continuing/references/liveness-ranking.md +56 -0
- package/skills/skill-evaluating/evals/evals.json +1 -1
- package/skills/tutorial/references/track-1-guided.md +5 -4
- package/skills/tutorial/references/track-2-auto.md +1 -1
- package/skills/uninstall/SKILL.md +2 -2
- package/skills/update/SKILL.md +2 -2
- package/templates/config.yml +2 -1
- package/templates/index.md +4 -1
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
# frozen_string_literal: true
|
|
4
|
+
|
|
5
|
+
# roadmap-savepoint - deterministic CLI over RoadmapSavepoint (intent 134).
|
|
6
|
+
#
|
|
7
|
+
# The plastic-roadmap skill verbs and the coordinator flows call this instead of hand-writing
|
|
8
|
+
# ledger lines. append is idempotent on the (event, detail) pair; rebuild is the one operation
|
|
9
|
+
# allowed to overwrite the ledger, reconstructing it from the roadmap's own `## Log`.
|
|
10
|
+
#
|
|
11
|
+
# Usage:
|
|
12
|
+
# roadmap-savepoint append --roadmap <path> --event <event> --detail "<text>"
|
|
13
|
+
# roadmap-savepoint rebuild --roadmap <path>
|
|
14
|
+
#
|
|
15
|
+
# Exits non-zero with a usage line on stderr for an unknown verb or a missing required flag.
|
|
16
|
+
|
|
17
|
+
require_relative "lib/roadmap_savepoint"
|
|
18
|
+
|
|
19
|
+
def opt(args, name)
|
|
20
|
+
(i = args.index(name)) && args[i + 1]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def usage
|
|
24
|
+
warn "Usage: roadmap-savepoint append --roadmap <path> --event <event> --detail \"<text>\""
|
|
25
|
+
warn " roadmap-savepoint rebuild --roadmap <path>"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
verb = ARGV.shift
|
|
29
|
+
|
|
30
|
+
case verb
|
|
31
|
+
when "append"
|
|
32
|
+
roadmap = opt(ARGV, "--roadmap")
|
|
33
|
+
event = opt(ARGV, "--event")
|
|
34
|
+
detail = opt(ARGV, "--detail")
|
|
35
|
+
if roadmap.nil? || event.nil? || detail.nil?
|
|
36
|
+
warn "append: pass --roadmap <path> --event <event> --detail \"<text>\""
|
|
37
|
+
usage
|
|
38
|
+
exit 2
|
|
39
|
+
end
|
|
40
|
+
begin
|
|
41
|
+
wrote = RoadmapSavepoint.append(roadmap, event, detail)
|
|
42
|
+
puts wrote ? "appended #{event} #{detail}" : "no-op (already recorded): #{event} #{detail}"
|
|
43
|
+
exit 0
|
|
44
|
+
rescue ArgumentError => e
|
|
45
|
+
warn "append: #{e.message}"
|
|
46
|
+
exit 2
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
when "rebuild"
|
|
50
|
+
roadmap = opt(ARGV, "--roadmap")
|
|
51
|
+
if roadmap.nil?
|
|
52
|
+
warn "rebuild: pass --roadmap <path>"
|
|
53
|
+
usage
|
|
54
|
+
exit 2
|
|
55
|
+
end
|
|
56
|
+
count = RoadmapSavepoint.rebuild(roadmap)
|
|
57
|
+
puts "rebuilt #{count} line#{count == 1 ? '' : 's'}"
|
|
58
|
+
exit 0
|
|
59
|
+
|
|
60
|
+
else
|
|
61
|
+
warn "roadmap-savepoint: unknown verb #{verb.inspect}. Use append|rebuild."
|
|
62
|
+
usage
|
|
63
|
+
exit 2
|
|
64
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
# frozen_string_literal: true
|
|
4
|
+
|
|
5
|
+
# skill-lint: deterministic CLI over SkillLint (intent 85b).
|
|
6
|
+
#
|
|
7
|
+
# Runs the five structural skill checks (body-budget, frontmatter-validity,
|
|
8
|
+
# bare-pointer, orphan-files, references-depth) over a directory of Agent
|
|
9
|
+
# Skills and reports every violation. Mirrors `scripts/validate-intent`'s
|
|
10
|
+
# CLI-over-lib shape and exit-code contract.
|
|
11
|
+
#
|
|
12
|
+
# Usage:
|
|
13
|
+
# skill-lint [--skills-dir <path>]
|
|
14
|
+
#
|
|
15
|
+
# Exit codes: 0 (clean), 1 (violations found; reported on stderr), 2 (usage).
|
|
16
|
+
# --skills-dir defaults to the repo skills/ directory next to this script.
|
|
17
|
+
|
|
18
|
+
require_relative "lib/skill_lint"
|
|
19
|
+
|
|
20
|
+
def resolve_skills_dir(args)
|
|
21
|
+
if (i = args.index("--skills-dir"))
|
|
22
|
+
args[i + 1]
|
|
23
|
+
else
|
|
24
|
+
File.expand_path("../skills", __dir__)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
if ARGV.any? { |a| a.start_with?("--") && a != "--skills-dir" }
|
|
29
|
+
warn "usage: skill-lint [--skills-dir <path>]"
|
|
30
|
+
exit 2
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
if ARGV.include?("--skills-dir") && ARGV[ARGV.index("--skills-dir") + 1].nil?
|
|
34
|
+
warn "usage: skill-lint [--skills-dir <path>]"
|
|
35
|
+
exit 2
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
dir = File.expand_path(resolve_skills_dir(ARGV))
|
|
39
|
+
result = SkillLint.new(skills_dir: dir).run
|
|
40
|
+
|
|
41
|
+
if result.ok?
|
|
42
|
+
puts "OK: #{dir}"
|
|
43
|
+
exit 0
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
warn "VIOLATIONS: #{dir}"
|
|
47
|
+
result.violations.each do |v|
|
|
48
|
+
warn "#{v[:check]} #{v[:skill]} #{v[:file]}:#{v[:line].nil? ? "-" : v[:line]} #{v[:message]}"
|
|
49
|
+
end
|
|
50
|
+
exit 1
|
package/skills/auto/SKILL.md
CHANGED
|
@@ -15,7 +15,9 @@ Announce: "Taking over intent [ID] - [name] for autonomous delivery."
|
|
|
15
15
|
orchestrating main session on the best available thinking model (Fable, Opus, or whatever
|
|
16
16
|
supersedes them) for the sharpest gating and synthesis. This is advice only: it changes no
|
|
17
17
|
behavior and blocks nothing if ignored. It concerns the human's MAIN session; dispatched
|
|
18
|
-
subagents keep their pinned tier and never resolve to Fable
|
|
18
|
+
subagents keep their pinned tier and never resolve to Fable, unless an explicit
|
|
19
|
+
`agents.models.<name>` config override names Fable for that role, in which case the override
|
|
20
|
+
is honored as written.
|
|
19
21
|
|
|
20
22
|
## Precondition
|
|
21
23
|
|
|
@@ -24,8 +26,22 @@ An active intent MUST exist in INDEX.md. If none exists, refuse: "No active inte
|
|
|
24
26
|
If multiple active intents exist, ask the user which one to deliver (this is the only question auto asks).
|
|
25
27
|
|
|
26
28
|
**Picking work when no intent is specified.** If the user says "auto" without naming an
|
|
27
|
-
intent and none is active, consult the
|
|
28
|
-
|
|
29
|
+
intent and none is active, consult the roadmap first (the primary planning surface), then
|
|
30
|
+
fall back to the dashboard queue. Read the tier's mid-flight roadmap:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
ruby ~/.plastic/scripts/roadmap-next --roadmaps-dir <tier>/roadmaps
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Branch on `state`:
|
|
37
|
+
- `dispatchable`: work its `dispatchable_queue` in `rank` order (the head is the next batch
|
|
38
|
+
entry). These are the current batch's `queued` intents, parallel-safe within the wave.
|
|
39
|
+
- `in_flight`: the frontier batch is still delivering. Report it and wait. Do NOT dispatch a
|
|
40
|
+
later batch and do NOT fall through to the dashboard, the roadmap is live.
|
|
41
|
+
- `none` or `exhausted`: no roadmap, or nothing left to dispatch. Fall back to the dashboard
|
|
42
|
+
queue below. (The global store has no roadmap, so it always reports `none` and falls back.)
|
|
43
|
+
|
|
44
|
+
Dashboard fallback:
|
|
29
45
|
|
|
30
46
|
```bash
|
|
31
47
|
ruby ~/.plastic/scripts/dashboard.rb all --json
|
|
@@ -54,8 +70,10 @@ and artifact depth to that size. Extended walkthrough: `references/tiers.md`.
|
|
|
54
70
|
every tier and in both modes. A three-line spec.md is still a spec.md, in the same
|
|
55
71
|
place, under the same gate.
|
|
56
72
|
3. **Per-tier topology.** S/M: one thinker agent, one boot, two stations, sonnet
|
|
57
|
-
executor
|
|
58
|
-
|
|
73
|
+
executor; the thinker writes at least one real action file (one consolidated
|
|
74
|
+
`actions/ACTION_1.md`), never an empty `actions/`. S may also skip the QMD discovery
|
|
75
|
+
deposit when chain and sources are both empty. L: today's full team (`## Team Spin-Up`
|
|
76
|
+
below), one `actions/ACTION_N.md` per task.
|
|
59
77
|
4. **Never-cut list**, any tier or mode: the independent reviewer (separate agent, fresh
|
|
60
78
|
context, never the maker), `outcome.md` as truth of delivery, the delivery lock,
|
|
61
79
|
worktree isolation, intent creation via skill, INDEX as status truth, the QMD reindex
|
|
@@ -108,7 +126,9 @@ Dispatch rule: sequential, one specialist per stage on one branch (the deliverab
|
|
|
108
126
|
|
|
109
127
|
Spawn preamble (live-state injection): before dispatching any specialist, run `scripts/spawn-preamble <intent_dir> --role <role>` and PREPEND its output to that specialist's prompt. The preamble is a deterministic, filesystem-only snapshot of the active intent (id, intent line, current stage, and the provisioned code worktree path when one exists on disk) plus the honoring instruction, so every spawned agent boots with accurate live state instead of guessing. This is the authoritative L2 mechanism for harnesses whose sub-agents do not inherit a top-level session event (see `docs/reference/harness-adapters.md`).
|
|
110
128
|
|
|
111
|
-
Dispatch-time model contract (belt-and-braces): alongside the preamble, resolve each specialist's model through the config chain (`read-config agents.models.<basename> --project <repo>`: project override, then global, then the shipped tier default) and pass it explicitly at dispatch. Never rely on the dispatched role's frontmatter alone; a resolved subagent model is never Fable
|
|
129
|
+
Dispatch-time model contract (belt-and-braces): alongside the preamble, resolve each specialist's model through the config chain (`read-config agents.models.<basename> --project <repo>`: project override, then global, then the shipped tier default) and pass it explicitly at dispatch. Never rely on the dispatched role's frontmatter alone; a resolved subagent model is never Fable,
|
|
130
|
+
unless an explicit `agents.models.<name>` config override names Fable for that role, in which
|
|
131
|
+
case the override is honored as written.
|
|
112
132
|
|
|
113
133
|
Completion report (require-then-synthesize): every dispatched specialist MUST end with a structured completion report as its final message. The preamble's `REPORT_CONTRACT` injects this and the role prompts carry the per-role format (see `references/agent-report-contract.md`). Because child-agent honor is best-effort across harnesses, this is decision-shaping, not a hard block. When a specialist returns no usable report (it went idle, emitted only a bare ping, or its message was lost to a mid-run interjection), run `scripts/agent-report <intent_dir> --role <role>` to synthesize a deterministic filesystem-derived report so the handoff account always exists. Use the agent-authored report when present, the synthesized one otherwise.
|
|
114
134
|
|
|
@@ -185,14 +205,15 @@ Then proceed to How.
|
|
|
185
205
|
|
|
186
206
|
## How Phase
|
|
187
207
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
208
|
+
Every tier runs all four steps below (see `## Tiers` above). The `actions/` directory is
|
|
209
|
+
scaffolded (with a `.gitkeep`) at intent birth; the planner then writes at least one REAL
|
|
210
|
+
`ACTION_N.md` into it at every tier. The tier only changes step 3's granularity: S/M write
|
|
211
|
+
one consolidated `actions/ACTION_1.md`, L writes one `actions/ACTION_N.md` per task. A
|
|
212
|
+
`.gitkeep`-only or empty `actions/` fails the How gate.
|
|
192
213
|
|
|
193
214
|
1. If `superpowers:writing-plans` is available as a skill, delegate plan creation to it. Tell it the plan saves to the active intent's directory (not `docs/superpowers/plans/`).
|
|
194
215
|
2. Otherwise, write `plan.md` directly - implementation plan with numbered tasks
|
|
195
|
-
3. Write `ACTION_N.md`
|
|
216
|
+
3. Write at least one real `ACTION_N.md` into the existing `actions/` directory, self-contained (S/M: one consolidated `ACTION_1.md`; L: one per task)
|
|
196
217
|
4. Write `checklist.md` - execution registry with checkboxes covering all actions
|
|
197
218
|
5. Notify user (How briefing): brief per `references/human-report-contract.md`
|
|
198
219
|
(State: the plan shape, task count and what it builds; Risk: the riskiest task or
|
|
@@ -30,9 +30,10 @@ the savepoint ledger.
|
|
|
30
30
|
One thinker agent boots ONCE and stays in a single context for two stations:
|
|
31
31
|
|
|
32
32
|
1. Station 1 — writes `spec.md` (collapsed sections allowed, one line each is valid).
|
|
33
|
-
2. Station 2 — writes `plan.md` + `checklist.md`
|
|
34
|
-
|
|
35
|
-
`actions/` is
|
|
33
|
+
2. Station 2 — writes `plan.md` + `checklist.md` + at least one real action file in the
|
|
34
|
+
SAME context (no reboot). At S/M the thinker consolidates the whole delivery into one
|
|
35
|
+
`actions/ACTION_1.md` (rather than one file per task); `actions/` is populated at every
|
|
36
|
+
tier, and a `.gitkeep`-only or empty `actions/` fails the How gate.
|
|
36
37
|
|
|
37
38
|
Then a sonnet executor (a fresh dispatch, this is the one topology split that always
|
|
38
39
|
happens) implements from plan.md + checklist.md, checks off items, appends `## Insights`,
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plastic-continuing
|
|
3
|
+
description: >-
|
|
4
|
+
Use when the user says "continue", "resume", or "pick up where we left off", starts a new
|
|
5
|
+
session and wants to keep going, asks "what should I work on", or asks a where-was-I question
|
|
6
|
+
that never says "continue" (for example "where was I"). This is the front door for resuming
|
|
7
|
+
work: it dispatches to plastic-intent-continuing (a specific intent named to resume),
|
|
8
|
+
plastic-project-continuing (the default, general board landing), or
|
|
9
|
+
plastic-roadmap-continuing (a roadmap or delivery batch named to resume).
|
|
10
|
+
user-invocable: true
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Continuing - the front door
|
|
14
|
+
|
|
15
|
+
`plastic-continuing` is the front door for resuming work (ruling 96: continuing routes,
|
|
16
|
+
starting does the lock plus resume plus work). It routes to exactly one of three skills and
|
|
17
|
+
does nothing else: no ledger-resume, no dashboard render, no roadmap read happens here.
|
|
18
|
+
|
|
19
|
+
## Route
|
|
20
|
+
|
|
21
|
+
| Args / context | Route to |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `--intent {id}`, or the user names one specific intent (by id or description) to resume | `plastic-intent-continuing` (intent route) |
|
|
24
|
+
| `--roadmap {slug}`, or the user asks to continue/resume a roadmap or delivery batch | `plastic-roadmap-continuing` (roadmap route) |
|
|
25
|
+
| bare "continue" / "resume" / no further target (default) | `plastic-project-continuing` (project route) |
|
|
26
|
+
|
|
27
|
+
## Announce, then hand off
|
|
28
|
+
|
|
29
|
+
State the chosen route in one line before delegating (this is the router's own "present state
|
|
30
|
+
before any ask" - the router asks nothing itself). Example: "Routing to the project board (no
|
|
31
|
+
specific intent or roadmap named)."
|
|
32
|
+
|
|
33
|
+
Then hand off to the chosen skill. Do not inline any of the routed skill's own work here -
|
|
34
|
+
that belongs to the routes.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "plastic-continuing",
|
|
3
|
+
"notes": "Intent 158a1. New bare front-door router restored per intent 96 (D8). Scopes: description triggering (1-5) and routing behavior (6-9), the latter checked as convention against SKILL.md's routing table.",
|
|
4
|
+
"results": {
|
|
5
|
+
"triggering": { "cases": 5, "passed": 5, "run": "2026-07-10, one subagent per case" },
|
|
6
|
+
"behavior": { "cases": 4, "passed": 4, "evidence": "convention checks against skills/continuing/SKILL.md's routing table" }
|
|
7
|
+
},
|
|
8
|
+
"evals": [
|
|
9
|
+
{
|
|
10
|
+
"id": 1, "scope": "triggering", "set": "train",
|
|
11
|
+
"prompt": "continue",
|
|
12
|
+
"expected_output": "Activates plastic-continuing (the bare 'continue' keyword is the router's documented trigger).",
|
|
13
|
+
"files": [],
|
|
14
|
+
"assertions": [
|
|
15
|
+
{ "type": "code", "check": "router CHOICE == plastic-continuing", "observed": "plastic-continuing", "result": "pass" }
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": 2, "scope": "triggering", "set": "train",
|
|
20
|
+
"prompt": "resume where we left off",
|
|
21
|
+
"expected_output": "Activates plastic-continuing.",
|
|
22
|
+
"files": [],
|
|
23
|
+
"assertions": [
|
|
24
|
+
{ "type": "code", "check": "router CHOICE == plastic-continuing", "observed": "plastic-continuing", "result": "pass" }
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": 3, "scope": "triggering", "set": "validation",
|
|
29
|
+
"prompt": "pick up where we left off",
|
|
30
|
+
"expected_output": "Activates plastic-continuing.",
|
|
31
|
+
"files": [],
|
|
32
|
+
"assertions": [
|
|
33
|
+
{ "type": "code", "check": "router CHOICE == plastic-continuing", "observed": "plastic-continuing", "result": "pass" }
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": 4, "scope": "triggering", "set": "validation",
|
|
38
|
+
"prompt": "where was I",
|
|
39
|
+
"expected_output": "Activates plastic-continuing (indirect trigger: a continue request that never says 'continue').",
|
|
40
|
+
"files": [],
|
|
41
|
+
"assertions": [
|
|
42
|
+
{ "type": "code", "check": "router CHOICE == plastic-continuing", "observed": "plastic-continuing", "result": "pass" }
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": 5, "scope": "triggering", "set": "validation",
|
|
47
|
+
"prompt": "continue the for-loop in this function",
|
|
48
|
+
"expected_output": "Does NOT activate plastic-continuing. Near-miss: shares 'continue' but is a code-editing task.",
|
|
49
|
+
"files": [],
|
|
50
|
+
"assertions": [
|
|
51
|
+
{ "type": "code", "check": "router CHOICE != plastic-continuing", "observed": "none", "result": "pass" }
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"id": 6, "scope": "behavior", "set": "train",
|
|
56
|
+
"prompt": "continue",
|
|
57
|
+
"expected_output": "Bare 'continue' with no further target dispatches to the project route (plastic-project-continuing), the routing table's default.",
|
|
58
|
+
"files": ["skills/continuing/SKILL.md"],
|
|
59
|
+
"assertions": [
|
|
60
|
+
{ "type": "convention", "check": "routing table's default row maps bare continue/resume/no target to plastic-project-continuing", "observed": "present", "result": "pass" }
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"id": 7, "scope": "behavior", "set": "train",
|
|
65
|
+
"prompt": "continue --intent 4a",
|
|
66
|
+
"expected_output": "Dispatches to the intent route (plastic-intent-continuing).",
|
|
67
|
+
"files": ["skills/continuing/SKILL.md"],
|
|
68
|
+
"assertions": [
|
|
69
|
+
{ "type": "convention", "check": "routing table maps --intent {id} to plastic-intent-continuing", "observed": "present", "result": "pass" }
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"id": 8, "scope": "behavior", "set": "validation",
|
|
74
|
+
"prompt": "resume the statusline-coloring intent",
|
|
75
|
+
"expected_output": "Dispatches to the intent route (plastic-intent-continuing): a specific intent named by description.",
|
|
76
|
+
"files": ["skills/continuing/SKILL.md"],
|
|
77
|
+
"assertions": [
|
|
78
|
+
{ "type": "convention", "check": "routing table maps a named specific intent (by id or description) to plastic-intent-continuing", "observed": "present", "result": "pass" }
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"id": 9, "scope": "behavior", "set": "validation",
|
|
83
|
+
"prompt": "continue the consistency-dividend roadmap",
|
|
84
|
+
"expected_output": "Dispatches to the roadmap route (plastic-roadmap-continuing).",
|
|
85
|
+
"files": ["skills/continuing/SKILL.md"],
|
|
86
|
+
"assertions": [
|
|
87
|
+
{ "type": "convention", "check": "routing table maps a named roadmap/delivery batch to plastic-roadmap-continuing", "observed": "present", "result": "pass" }
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: plastic-dashboard
|
|
3
|
-
description: Use when the user wants an overview of intents, asks "where are we", "what's next", "what should I work on", "show the dashboard", or invokes /plastic-dashboard. Renders a
|
|
3
|
+
description: Use when the user wants an overview of intents, asks "where are we", "what's next", "what should I work on", "show the dashboard", or invokes /plastic-dashboard. Renders the intent store(s) as Markdown prose, the global board as a narrative of work done, each project board as a short summary plus its most-valuable next work, and emits a machine-readable queue that auto mode consumes.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Dashboard — Plastic Work Cockpit
|
|
8
8
|
|
|
9
9
|
A deterministic overview of the intent store(s). It answers three questions at a glance:
|
|
10
|
-
**where we are** (recently worked), **where we go next** (
|
|
10
|
+
**where we are** (recently worked), **where we go next** (the most-valuable next work), and
|
|
11
11
|
**how to conduct it** (a disposition per intent). The human-facing surface is **Markdown**,
|
|
12
12
|
because the user's UI renders Markdown natively but collapses raw tool-call stdout.
|
|
13
13
|
|
|
@@ -19,7 +19,7 @@ state → byte-identical payload, regardless of model. Do NOT hand-summarize int
|
|
|
19
19
|
|
|
20
20
|
- User invokes `/plastic-dashboard`
|
|
21
21
|
- User asks "where are we", "what's next", "what should I work on", "show me the intents"
|
|
22
|
-
- `plastic-
|
|
22
|
+
- `plastic-project-continuing` lands on the board on resume
|
|
23
23
|
- `plastic-auto` reads `--json` to choose the next dispatchable intent
|
|
24
24
|
|
|
25
25
|
## Procedure (the Markdown board — default human surface)
|
|
@@ -34,9 +34,9 @@ ruby ~/.plastic/scripts/dashboard.rb [continue|project <slug>] --data
|
|
|
34
34
|
- `project <slug>` → that **project** board payload (`mode: "project"`).
|
|
35
35
|
|
|
36
36
|
The payload is read-only JSON. Global-board fields: `date`, `store_health`, `recently_worked`,
|
|
37
|
-
`
|
|
38
|
-
`counts`, `projects`, `project_totals`. Project-board fields: `slug`,
|
|
39
|
-
`description`, `recently_worked`, `
|
|
37
|
+
`next_work` (a flat, rank-ordered list of `{id, intent, scope, lifecycle, value, disposition,
|
|
38
|
+
flags, line}`), `counts`, `projects`, `project_totals`. Project-board fields: `slug`,
|
|
39
|
+
`store_health`, `description`, `recently_worked`, `next_work`, `counts`, `active`, `future`.
|
|
40
40
|
|
|
41
41
|
Each board load runs the scoped store check (`doctor --store <scope>`): the global board runs
|
|
42
42
|
`--store global` and a project board runs `--store <slug>`. The result rides in the payload as
|
|
@@ -51,13 +51,16 @@ Templates live in this skill's `templates/` directory:
|
|
|
51
51
|
`~/.claude/skills/plastic-dashboard/templates/dashboard-global.md` and
|
|
52
52
|
`dashboard-project.md`.
|
|
53
53
|
|
|
54
|
-
Fill mechanically
|
|
55
|
-
- `{{a.b.count}}` → the integer (e.g. `
|
|
54
|
+
Fill mechanically, no rewriting, no re-sorting:
|
|
55
|
+
- `{{a.b.count}}` → the integer (e.g. `counts.active` = that count).
|
|
56
56
|
- `{{...lines}}` → join the list's `.line` strings with **real newlines** (one per line).
|
|
57
|
-
These lines
|
|
58
|
-
`<br
|
|
57
|
+
These are ordinary prose lines, not glyph-led bullets: never add a Markdown `-` bullet,
|
|
58
|
+
never emit `<br>`. If a list is empty, render `_(none)_`.
|
|
59
|
+
- `next_work.lines` → the most-valuable next work, already ranked; each line reads
|
|
60
|
+
`"<id> <intent, truncated>"`. Use each entry's `disposition`/`flags` fields when the prose
|
|
61
|
+
needs to say why an item is next.
|
|
59
62
|
- `projects.lines` → one line per project:
|
|
60
|
-
`- **{slug}
|
|
63
|
+
`- **{slug}**: {description}, active {active}, done {done}, future {future}, last accessed {last_accessed_at[0,10]}`.
|
|
61
64
|
- Scalars (`{{date}}`, `{{slug}}`, `{{description}}`) → substitute verbatim.
|
|
62
65
|
|
|
63
66
|
### Step 3 — Present it (mandatory, every invocation)
|
|
@@ -112,7 +115,7 @@ a raw terminal. The Markdown board (`--data` + template) is the surface for the
|
|
|
112
115
|
## How classification works (deterministic)
|
|
113
116
|
|
|
114
117
|
The script computes Effort/Value/Flags/Override/Caps; the agent never re-derives them.
|
|
115
|
-
To explain or debug a
|
|
118
|
+
To explain or debug a ranking or disposition, read `references/classification.md`.
|
|
116
119
|
|
|
117
120
|
## Eval
|
|
118
121
|
|
|
@@ -123,7 +126,7 @@ intentional change means the skill is broken.
|
|
|
123
126
|
|
|
124
127
|
## Notes
|
|
125
128
|
|
|
126
|
-
-
|
|
127
|
-
|
|
129
|
+
- Board lines are ordinary prose, not a rigid grid: the boards are UI-only and may evolve,
|
|
130
|
+
so they need not be valid Markdown lists. Never emit `<br>`.
|
|
128
131
|
- Clusters (Zettelkasten grouping in INDEX.md) are intentionally not rendered.
|
|
129
132
|
- Additive: changes no core lifecycle, gate, or cycle logic.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# How Classification Works (Deterministic)
|
|
2
2
|
|
|
3
3
|
The script (`dashboard.rb`) computes Effort/Value/Flags/Override/Caps deterministically;
|
|
4
|
-
the agent never re-derives them. Read this to explain or debug a
|
|
4
|
+
the agent never re-derives them. Read this to explain or debug a ranking or disposition.
|
|
5
5
|
|
|
6
6
|
- **Effort** — small for `research`/`exploration`/`bugfix`, for already-scoped intents
|
|
7
7
|
(plan/checklist exists), or a **branch id** (folgezettel depth ≥ 2, e.g. `4a`, `12b3`); big
|
|
@@ -16,7 +16,7 @@ the agent never re-derives them. Read this to explain or debug a quadrant assign
|
|
|
16
16
|
the staleness threshold. All three kept low-noise by design.
|
|
17
17
|
- **Override** — a `value: high|low` frontmatter field always wins (pre-stamped data, never
|
|
18
18
|
model judgment at render time).
|
|
19
|
-
- **Caps
|
|
20
|
-
entries plus a trailing "+N more" line; each entry's text is truncated to 120 characters
|
|
19
|
+
- **Caps**: the next-work list and the project board's `active`/`future` lists are capped at
|
|
20
|
+
8 entries plus a trailing "+N more" line; each entry's text is truncated to 120 characters
|
|
21
21
|
with a trailing ellipsis. Applies to the Markdown board only (the ASCII renderer has its own
|
|
22
22
|
separate `CELL_CAP`).
|
|
@@ -1,31 +1,16 @@
|
|
|
1
|
-
# 🧩 Plastic · Global Board
|
|
1
|
+
# 🧩 Plastic · Global Board, {{date}}
|
|
2
2
|
|
|
3
|
-
**Recently worked**
|
|
3
|
+
**Recently worked** (last 24h)
|
|
4
4
|
{{recently_worked.lines}}
|
|
5
5
|
|
|
6
|
-
## Where we
|
|
6
|
+
## Where we are
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|---|---|---|
|
|
10
|
-
| **High value** | ⚡ **Quick win** · {{matrix.quick_win.count}} | ★ **Next big thing** · {{matrix.next_big.count}} |
|
|
11
|
-
| **Low value** | → **Defer (agent)** · {{matrix.defer.count}} | ⚑ **Triage** · {{matrix.triage.count}} |
|
|
8
|
+
{{counts.active}} intents active, {{counts.done}} done, {{counts.future}} queued for later.
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
{{matrix.quick_win.lines}}
|
|
15
|
-
|
|
16
|
-
**★ Next big thing** — big effort, high value
|
|
17
|
-
{{matrix.next_big.lines}}
|
|
18
|
-
|
|
19
|
-
**→ Defer (agent)** — small effort, low value
|
|
20
|
-
{{matrix.defer.lines}}
|
|
21
|
-
|
|
22
|
-
**⚑ Triage** — big effort, low value
|
|
23
|
-
{{matrix.triage.lines}}
|
|
24
|
-
|
|
25
|
-
🔬 **Research → agent**
|
|
26
|
-
{{matrix.research.lines}}
|
|
27
|
-
|
|
28
|
-
## Projects · active {{project_totals.active}} · done {{project_totals.done}} · future {{project_totals.future}}
|
|
10
|
+
## Projects, active {{project_totals.active}}, done {{project_totals.done}}, future {{project_totals.future}}
|
|
29
11
|
{{projects.lines}}
|
|
30
12
|
|
|
13
|
+
## Most-valuable next work
|
|
14
|
+
{{next_work.lines}}
|
|
15
|
+
|
|
31
16
|
**What would you like to work on next?** (type an **intent id**, a **project name**, or anything **new** you'd like to start)
|
|
@@ -1,33 +1,11 @@
|
|
|
1
|
-
# 📦 {{slug}} · Project Board
|
|
1
|
+
# 📦 {{slug}} · Project Board, {{date}}
|
|
2
2
|
|
|
3
3
|
{{description}}
|
|
4
4
|
|
|
5
|
-
**Recently worked**
|
|
5
|
+
**Recently worked** (last active work, last 24h)
|
|
6
6
|
{{recently_worked.lines}}
|
|
7
7
|
|
|
8
|
-
##
|
|
9
|
-
|
|
10
|
-
| | Small effort | Big effort |
|
|
11
|
-
|---|---|---|
|
|
12
|
-
| **High value** | ⚡ **Quick win** · {{matrix.quick_win.count}} | ★ **Next big thing** · {{matrix.next_big.count}} |
|
|
13
|
-
| **Low value** | → **Defer (agent)** · {{matrix.defer.count}} | ⚑ **Triage** · {{matrix.triage.count}} |
|
|
14
|
-
|
|
15
|
-
**⚡ Quick win** — small effort, high value
|
|
16
|
-
{{matrix.quick_win.lines}}
|
|
17
|
-
|
|
18
|
-
**★ Next big thing** — big effort, high value
|
|
19
|
-
{{matrix.next_big.lines}}
|
|
20
|
-
|
|
21
|
-
**→ Defer (agent)** — small effort, low value
|
|
22
|
-
{{matrix.defer.lines}}
|
|
23
|
-
|
|
24
|
-
**⚑ Triage** — big effort, low value
|
|
25
|
-
{{matrix.triage.lines}}
|
|
26
|
-
|
|
27
|
-
🔬 **Research → agent**
|
|
28
|
-
{{matrix.research.lines}}
|
|
29
|
-
|
|
30
|
-
## Intents · active {{counts.active}} · done {{counts.done}} · future {{counts.future}}
|
|
8
|
+
## Intents, active {{counts.active}}, done {{counts.done}}, future {{counts.future}}
|
|
31
9
|
|
|
32
10
|
**Active**
|
|
33
11
|
{{active.lines}}
|
|
@@ -35,6 +13,9 @@
|
|
|
35
13
|
**Future**
|
|
36
14
|
{{future.lines}}
|
|
37
15
|
|
|
38
|
-
|
|
16
|
+
## Most-valuable next work
|
|
17
|
+
{{next_work.lines}}
|
|
18
|
+
|
|
19
|
+
**Legend** · ○ What ◔ Why ◑ How ◕ Exec ● Done
|
|
39
20
|
|
|
40
21
|
**What would you like to work on next?** (type an **intent id**, or **global** to go back)
|
package/skills/doctor/SKILL.md
CHANGED
|
@@ -13,7 +13,7 @@ Doctor has three scopes. Pick the right one for the situation:
|
|
|
13
13
|
| Scope | Flag | When it runs | States |
|
|
14
14
|
|-------|------|--------------|--------|
|
|
15
15
|
| Core check | `--core` | SessionStart hook (automatic), also available on demand | Binary: pass or error |
|
|
16
|
-
| Store check | `--store [global\|<slug>]` | Dashboard load, `plastic-
|
|
16
|
+
| Store check | `--store [global\|<slug>]` | Dashboard load, `plastic-project-continuing` | Three-state: pass / warn / fail |
|
|
17
17
|
| Full check | (no flag) | After every update (automatic), or `/plastic-doctor` | Three-state: pass / warn / fail |
|
|
18
18
|
|
|
19
19
|
### `--core` (binary, manifest-backed)
|
package/skills/install/SKILL.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
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. First install defaults to --
|
|
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 --latest (stable); 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
|
user-invocable: true
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Install Plastic
|
|
8
8
|
|
|
9
|
-
> **Recommended path:** for a first install, run `npx -y @zalom/plastic@
|
|
10
|
-
> in your shell (or `bunx -y @zalom/plastic@
|
|
9
|
+
> **Recommended path:** for a first install, run `npx -y @zalom/plastic@latest install --claude`
|
|
10
|
+
> in your shell (or `bunx -y @zalom/plastic@latest install --claude` if you use Bun). This skill
|
|
11
11
|
> exists to **re-install or repair** an existing setup from inside the agent, and to
|
|
12
12
|
> drive interactive global configuration. Whenever this skill performs an install or
|
|
13
13
|
> re-install, it **runs `/plastic-doctor` afterward** and reports the result.
|
|
@@ -16,7 +16,7 @@ user-invocable: true
|
|
|
16
16
|
|
|
17
17
|
If Plastic is installed, derive `<channel>` from `~/.plastic/VERSION`: a version containing
|
|
18
18
|
`-alpha` means `@alpha`, `-beta` means `@beta`, otherwise `@latest`. If not installed
|
|
19
|
-
(first install), default to `@
|
|
19
|
+
(first install), default to `@latest`. The user can always override with
|
|
20
20
|
`--alpha` / `--beta` / `--latest`.
|
|
21
21
|
|
|
22
22
|
## Re-install / repair
|
|
@@ -35,18 +35,18 @@ Then **run `/plastic-doctor`** and report what it found.
|
|
|
35
35
|
|
|
36
36
|
| Flag | Behavior |
|
|
37
37
|
|------|----------|
|
|
38
|
-
| `--latest` | Install from the stable channel |
|
|
39
|
-
| `--beta` | Install from the beta channel
|
|
38
|
+
| `--latest` | Install from the stable channel (default on a first install) |
|
|
39
|
+
| `--beta` | Install from the beta channel |
|
|
40
40
|
| `--alpha` | Install from the alpha channel |
|
|
41
41
|
|
|
42
42
|
When invoked from within Claude Code (re-install or channel switch), the skill
|
|
43
43
|
runs the appropriate npx command:
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
# Stable
|
|
46
|
+
# Stable (default on a first install)
|
|
47
47
|
npx -y @zalom/plastic@latest install --claude
|
|
48
48
|
|
|
49
|
-
# Beta
|
|
49
|
+
# Beta
|
|
50
50
|
npx -y @zalom/plastic@beta install --claude
|
|
51
51
|
|
|
52
52
|
# Alpha
|
|
@@ -68,10 +68,10 @@ Run `/plastic-install` with no arguments.
|
|
|
68
68
|
Check if `~/.plastic/VERSION` exists.
|
|
69
69
|
- If yes: announce "Plastic is already installed at ~/.plastic/. Run `/plastic-update` to
|
|
70
70
|
sync core files, or use the re-install command above to repair in place."
|
|
71
|
-
- If no: run the fresh install command (default `@
|
|
71
|
+
- If no: run the fresh install command (default `@latest`, or the channel the user named):
|
|
72
72
|
|
|
73
73
|
```bash
|
|
74
|
-
npx -y @zalom/plastic@
|
|
74
|
+
npx -y @zalom/plastic@latest install --claude
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
This single command, via `install.rb` (`bootstrap` + `distribute`), creates `store/`,
|