@zalom/plastic 1.0.0-alpha.9 → 1.0.0-beta.10

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 (115) hide show
  1. package/PLASTIC.md +170 -469
  2. package/README.md +95 -58
  3. package/agents/plastic-brainstorming.md +45 -0
  4. package/agents/plastic-enforcer.md +36 -0
  5. package/agents/plastic-executor.md +47 -0
  6. package/agents/{future-intent-researcher.md → plastic-future-intent-researcher.md} +1 -1
  7. package/agents/{intent-curator.md → plastic-intent-curator.md} +8 -6
  8. package/agents/plastic-planner.md +47 -0
  9. package/agents/plastic-spec-specialist.md +45 -0
  10. package/bin/plastic.js +57 -0
  11. package/bin/test +28 -0
  12. package/deprecations.yml +1 -10
  13. package/hooks/auto-arm +5 -0
  14. package/hooks/bash-gate +3 -0
  15. package/hooks/check-update +12 -8
  16. package/hooks/code-gate +12 -0
  17. package/hooks/create-gate +3 -0
  18. package/hooks/gate-check +3 -1
  19. package/hooks/hooks.json +52 -0
  20. package/hooks/qmd-search +8 -0
  21. package/hooks/statusline +150 -41
  22. package/package.json +2 -2
  23. package/scripts/agent-report +142 -0
  24. package/scripts/dashboard.rb +687 -0
  25. package/scripts/doctor.rb +1219 -621
  26. package/scripts/hook-auto-arm +51 -0
  27. package/scripts/hook-bash-gate +41 -0
  28. package/scripts/hook-code-gate +27 -0
  29. package/scripts/hook-continue +15 -114
  30. package/scripts/hook-create-gate +59 -0
  31. package/scripts/hook-gate-check +47 -32
  32. package/scripts/hook-qmd-search +44 -0
  33. package/scripts/hook-session-start +106 -38
  34. package/scripts/install.rb +91 -529
  35. package/scripts/lib/boot_banner.rb +28 -0
  36. package/scripts/lib/bridge.rb +452 -19
  37. package/scripts/lib/frontmatter_writer.rb +130 -0
  38. package/scripts/lib/graph_rebuild.rb +328 -0
  39. package/scripts/lib/installer_core.rb +812 -0
  40. package/scripts/lib/intent_validator.rb +235 -0
  41. package/scripts/lib/links_projection.rb +160 -0
  42. package/scripts/lib/links_section.rb +207 -0
  43. package/scripts/lib/power_tools.rb +76 -0
  44. package/scripts/lib/qmd_hook.rb +57 -0
  45. package/scripts/lib/qmd_sync.rb +230 -0
  46. package/scripts/lib/store_provisioning.rb +100 -0
  47. package/scripts/migrate-to-global +1 -1
  48. package/scripts/new-intent +327 -0
  49. package/scripts/project-links +287 -0
  50. package/scripts/provision-project-store +53 -0
  51. package/scripts/qmd-sync +139 -0
  52. package/scripts/rebuild-graph +244 -0
  53. package/scripts/select-update-target +93 -0
  54. package/scripts/spawn-preamble +138 -0
  55. package/scripts/uninstall.rb +53 -0
  56. package/scripts/update.rb +164 -0
  57. package/scripts/validate-intent +54 -0
  58. package/scripts/versions.rb +141 -0
  59. package/skills/_active-intent-gate.md +1 -1
  60. package/skills/add-project-store/SKILL.md +54 -0
  61. package/skills/auto/SKILL.md +87 -7
  62. package/skills/auto/evals/evals.json +255 -0
  63. package/skills/auto/references/agent-architecture.md +155 -0
  64. package/skills/auto/references/agent-report-contract.md +86 -0
  65. package/skills/brainstorming/SKILL.md +10 -9
  66. package/skills/brainstorming/evals/evals.json +22 -0
  67. package/skills/brainstorming-grill-me/SKILL.md +6 -6
  68. package/skills/continuing/SKILL.md +99 -82
  69. package/skills/continuing/evals/evals.json +145 -0
  70. package/skills/continuing/references/context-management.md +32 -0
  71. package/skills/creating-intent/SKILL.md +82 -36
  72. package/skills/creating-intent/evals/evals.json +72 -0
  73. package/skills/creating-intent/references/lifecycle.md +81 -0
  74. package/skills/creating-intent/references/wikilinks.md +8 -0
  75. package/skills/creating-project/SKILL.md +40 -8
  76. package/skills/creating-project/references/hubs-projects.md +55 -0
  77. package/skills/dashboard/SKILL.md +126 -0
  78. package/skills/dashboard/evals/evals.json +22 -0
  79. package/skills/dashboard/templates/dashboard-global.md +31 -0
  80. package/skills/dashboard/templates/dashboard-project.md +40 -0
  81. package/skills/doctor/SKILL.md +51 -4
  82. package/skills/doctor/references/gates-stuck-detection.md +38 -0
  83. package/skills/doctor/report.md +4 -0
  84. package/skills/evaluating-skills/SKILL.md +140 -0
  85. package/skills/evaluating-skills/assets/eval-template.json +12 -0
  86. package/skills/evaluating-skills/evals/evals.json +75 -0
  87. package/skills/evaluating-skills/references/convention-checks.md +76 -0
  88. package/skills/evaluating-skills/references/eval-methodology.md +154 -0
  89. package/skills/executing-plan/SKILL.md +5 -3
  90. package/skills/install/SKILL.md +69 -8
  91. package/skills/intent-curator/SKILL.md +6 -4
  92. package/skills/intent-curator/evals/evals.json +22 -0
  93. package/skills/linking-intents/SKILL.md +22 -7
  94. package/skills/linking-intents/evals/evals.json +22 -0
  95. package/skills/linking-intents/references/zettelkasten.md +45 -0
  96. package/skills/managing-index/SKILL.md +11 -1
  97. package/skills/managing-index/evals/evals.json +22 -0
  98. package/skills/managing-index/references/zettelkasten-linking.md +7 -2
  99. package/skills/releasing/SKILL.md +80 -23
  100. package/skills/releasing/references/deprecations.md +60 -0
  101. package/skills/research/SKILL.md +10 -2
  102. package/skills/research/evals/evals.json +22 -0
  103. package/skills/savepoint/SKILL.md +46 -37
  104. package/skills/savepoint/references/context-management.md +32 -0
  105. package/skills/uninstall/SKILL.md +39 -28
  106. package/skills/update/SKILL.md +41 -44
  107. package/skills/versions/SKILL.md +65 -0
  108. package/skills/writing-instructions/SKILL.md +159 -0
  109. package/skills/writing-instructions/references/agentskills-spec.md +135 -0
  110. package/skills/writing-plans/SKILL.md +5 -5
  111. package/templates/agents.md +7 -7
  112. package/templates/outcome.md +13 -0
  113. package/templates/savepoint.md +14 -13
  114. package/templates/spec.md +25 -0
  115. package/bin/install.js +0 -29
@@ -1,104 +1,121 @@
1
1
  ---
2
- name: plastic:continuing
3
- description: Use when the user says "continue" after a /clear, or when resuming work in a new session. Reads intent state from global store (~/.plastic/) or local store, offers active intents first, then future intents, and surfaces stale intents for triage.
2
+ name: plastic-continuing
3
+ description: Use when the user says "continue", "resume", or "pick up where we left off", or when starting a new session. Continues work with the latest project context: lands on the right dashboard, then presents choices. Boot (health check, core context, version, statusline) is owned by the SessionStart hook, not this skill. Does not drive work autonomously (that is plastic-auto).
4
4
  ---
5
5
 
6
6
  # Continuing
7
7
 
8
+ `plastic-continuing` continues work. It presents the latest state via the dashboard and offers
9
+ choices, then stops. It does NOT execute work autonomously (that is `plastic-auto`) and does
10
+ NOT render the dashboard itself (it only invokes it).
11
+
12
+ **Boot is not this skill's job.** The `hook-session-start` hook already runs by construction on
13
+ every session start: it runs the core health check (`doctor --core`), primes `PLASTIC.md` +
14
+ store/project state, and prints the `Plastic Core loaded — v{version}` banner. The
15
+ `plastic-statusline` hook sets the statusline. So by the time this skill runs, core is loaded
16
+ and healthy (or the banner already warned otherwise). This skill picks up from there and
17
+ continues work. This is the seam future continue-flags build on (see [[39]]).
18
+
8
19
  ## When to Use
9
20
  - UserPromptSubmit hook detects "continue" (automatic)
10
21
  - User says "continue", "resume", or "pick up where we left off"
11
- - Starting a new session with existing active intents
22
+ - Starting a new session and you want to resume work with the latest context
12
23
 
13
24
  ## Determine Store
14
25
 
15
- 1. Check `~/.plastic/INDEX.md` → global mode
16
- 2.
17
- 3. If neither exists → announce "No Plastic store found. Run /plastic:install."
18
-
19
- ## Workflow
20
-
21
- ### 1. Read INDEX.md
22
- Read the INDEX.md from the active store. Extract intents under `## Active` and `## Future`.
23
-
24
- ### 2. Detect Current Project (global mode only)
25
- Read `~/.plastic/projects.yml`, match CWD against registered project paths. If in a project:
26
- - Load the governing intent (from `parent` in projects.yml)
27
- - Load tactical intents from `~/.plastic/projects/{slug}/store/`
28
-
29
- ### 3. If Active Intents Exist → Resume
30
-
31
- For each active intent in the store:
32
-
33
- **a. Read `{ID}--{slug}.md`:**
34
- - What we're doing (`## Intent`)
35
- - Why (`## Context`)
36
- - What insights have emerged (`## Insights`)
37
-
38
- **b. Read savepoint.md** (if exists):
39
- - What was in progress, what's next, blockers
40
-
41
- **c. Read checklist.md** (if exists):
42
- - What's completed, what's next
43
-
44
- **d. Announce:**
45
- ```
46
- Resuming intent [ID] — [name]
47
- Store: [global | project:<slug> | local]
48
- Status: active
49
- Last session: [date from savepoint]
50
- In progress: [from savepoint]
51
- Next step: [from checklist or savepoint]
52
- Blockers: [from savepoint, or "none"]
53
- ```
54
-
55
- **e. Resume** — proceed with the next step.
56
-
57
- ### 3b. Detect Autonomous Resume
58
-
59
- When resuming an active intent, check `## Insights` for entries containing `(autonomous)`.
60
-
61
- If found — this intent was being delivered autonomously:
62
-
63
- **Announce:**
64
- ```
65
- Resuming autonomous delivery of intent [ID] — [name]
66
- Store: [global | project:<slug> | local]
67
- Last autonomous action: [last (autonomous) insight entry]
68
- Next step: [from checklist or savepoint]
69
- ```
70
-
71
- **Then:** Continue autonomous execution by invoking `plastic:auto`. The auto skill will pick up from the current lifecycle stage (it reads filesystem state to determine where to resume).
72
-
73
- If NOT found — resume normally as described in step 3.
74
-
75
- ### 4. If No Active Intents → Offer Future Intents
76
-
77
- Present future intents as options. When user picks one, move to Active in INDEX.md. Auto-commit.
78
-
79
- ### 5. Surface Stale Future Intents
80
-
81
- If any future intent has `created` date older than the configured `stale_threshold_days` (default 3):
26
+ 1. **Global store** — `~/.plastic/INDEX.md` exists → global mode.
27
+ 2. **Local store** — a project store under `~/.plastic/projects/{slug}/` whose registered
28
+ path (in `~/.plastic/projects.yml`) matches the current working directory → project mode.
29
+ The SessionStart hook already detects this; here you only need the slug to scope the
30
+ dashboard.
31
+ 3. If neither exists → announce "No Plastic store found. Run /plastic-install."
32
+
33
+ ## Continue (present the dashboard)
34
+
35
+ Land on the Markdown board via the `plastic-dashboard` skill. Rendering belongs there, not
36
+ here — run the data payload and fill + present the matching template:
37
+ - Project loaded → `ruby ~/.plastic/scripts/dashboard.rb project <slug> --data`
38
+ - Otherwise → `ruby ~/.plastic/scripts/dashboard.rb continue --data`
39
+
40
+ Fill the matching template from this skill's `templates/` and **present the filled Markdown
41
+ in your reply** (every time). See `plastic-dashboard` for the fill rules and entry flow.
42
+
43
+ The board load runs the scoped store check on every load (`doctor --store <scope>`): the
44
+ global board runs `--store global` and a project board runs `--store <slug>`. The result
45
+ arrives in the payload as `store_health`; surface it as a one-line store-health note. It is
46
+ non-fatal (a warn or fail is shown as data, it does not block continuing).
47
+
48
+ ### Then stop
49
+ Present "here is the state, what next?" and wait. Offer active intents first, then future
50
+ intents. Do not start executing work. The branches below are the only follow-ups:
51
+ - User/agent names a specific intent to continue → **Conditional ledger-resume** (below).
52
+ - User says "auto" / an agent is instructed to deliver → hand to `plastic-auto`.
53
+
54
+ ## Conditional Ledger-Resume
55
+
56
+ Fires ONLY when the user explicitly asks to continue a SPECIFIC intent, or an agent is
57
+ instructed to continue one. It is not part of every boot.
58
+
59
+ QMD-first (when available): when the user names the intent by description rather than id, before
60
+ scanning the store with grep/Read run `ruby ~/.plastic/scripts/qmd-sync search "<terms>"` to
61
+ surface the candidate intent, then open the authoritative intent file for the hit you resume. The
62
+ command is a no-op when QMD is absent, so fall back to the existing INDEX.md / file scan.
63
+
64
+ For that intent's directory:
65
+
66
+ 1. **Read `savepoint.md`.** It is a deterministic, append-only stage ledger (one line per
67
+ milestone, newest at the bottom): `{utc-iso8601} {Stage} {milestone}`. The **last line =
68
+ current stage**.
69
+ 2. **Verify the stage file.** Confirm the file the ledger names exists and is non-empty
70
+ (ledger `How plan.md created` → `plan.md` must be present and non-empty).
71
+ 3. **Drift handling.** If the ledger's last line disagrees with files-on-disk, rebuild the
72
+ ledger from filesystem state and note the correction:
73
+ ```bash
74
+ ruby -r ~/.plastic/scripts/lib/bridge -e 'Bridge.rebuild_savepoint("<intent_dir>")'
75
+ ```
76
+ 4. **Derive the next step:**
77
+ - First unchecked item in `checklist.md` if it exists, else
78
+ - "advance to the next lifecycle stage" (e.g. ledger shows Why/spec.md → next is How).
79
+ - The newest `## Insights` entry supplies human-readable context (Insights are
80
+ append-only, newest at the bottom).
81
+ 5. **Announce and stop:**
82
+ ```
83
+ Resuming intent [ID] — [name]
84
+ Store: [global | project:<slug> | local]
85
+ Stage: [from ledger last line]
86
+ Next step: [first unchecked checklist item | advance to <stage>]
87
+ Context: [newest ## Insights entry]
88
+ Drift: [none | ledger rebuilt from filesystem]
89
+ ```
90
+ Then proceed with the next step. Autonomy is `plastic-auto`'s job — if the intent's
91
+ `## Insights` contains `(autonomous)` entries, it was being delivered autonomously; hand
92
+ to `plastic-auto` to continue from the current stage.
93
+
94
+ ## Priority Order
95
+
96
+ 1. **Active intents first** — surface work in progress.
97
+ 2. **Project context** — if in a registered project, show governing + tactical intents.
98
+ 3. **Stale future intents** — surface for triage (see below).
99
+ 4. **Fresh future intents** — offer as next work.
100
+
101
+ ## Stale Future Intents
102
+
103
+ If a future intent's `created` date is older than the configured `stale_threshold_days`
104
+ (default 3), surface it for triage without taking action:
82
105
 
83
106
  ```
84
107
  Stale future intents (no action taken):
85
108
 
86
109
  - [ID — name] (X days old)
87
- Options:
88
110
  a) Activate — start working on it now
89
111
  b) Abandon — mark as abandoned
90
- c) Defer to agent:
91
- - implement: agent builds it
92
- - research: agent investigates feasibility
93
- - ideate: agent explores the problem space
94
- d) Auto — go fully autonomous (invokes plastic:auto — agent delivers the intent end-to-end)
112
+ c) Defer to agent: implement | research | ideate
113
+ d) Auto — go fully autonomous (invokes plastic-auto)
95
114
  ```
96
115
 
97
- Auto-commit all triage changes.
116
+ When the user activates a future intent, move it to `## Active` in INDEX.md and auto-commit.
98
117
 
99
- ### 6. Priority Order
118
+ ## References
100
119
 
101
- 1. **Active intents first** — resume work in progress
102
- 2. **Project context** — if in a registered project, show governing intent + tactical intents
103
- 3. **Stale future intents** — surface for triage
104
- 4. **Fresh future intents** — offer as next work
120
+ - Read `references/context-management.md` for the full save/continue protocol and for
121
+ debugging the resume flow.
@@ -0,0 +1,145 @@
1
+ {
2
+ "skill_name": "plastic-continuing",
3
+ "notes": "Intent 36, updated for 36a (boot moved into hook-session-start; the skill is now work-continuation only). Scopes: description triggering (1-8) and behavior/convention compliance of the work-continuation skill (9-14). Triggering assertions follow the plastic-auto eval style (one subagent router per case). Behavior assertions are convention checks against the SKILL.md.",
4
+ "results": {
5
+ "triggering": { "cases": 8, "passed": 8, "run": "2026-06-16, one subagent per case" },
6
+ "behavior": { "cases": 6, "passed": 6, "evidence": "convention checks against skills/continuing/SKILL.md after the intent-36 rewrite; doctor --core verified at 0.07s with 9 liveness checks and full doctor unchanged at 30 checks" }
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 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 in this project",
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": "train",
38
+ "prompt": "boot plastic and show me where things stand",
39
+ "expected_output": "Activates plastic-continuing (continuing work + presenting state is the skill's purpose; boot itself is hook-owned).",
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": "train",
47
+ "prompt": "continue delivering this intent autonomously, don't ask me",
48
+ "expected_output": "Does NOT settle on plastic-continuing for execution. Shares 'continue' but the autonomous-delivery intent routes to plastic-auto.",
49
+ "files": [],
50
+ "assertions": [
51
+ { "type": "code", "check": "router CHOICE == plastic-auto", "observed": "plastic-auto", "result": "pass" }
52
+ ]
53
+ },
54
+ {
55
+ "id": 6, "scope": "triggering", "set": "validation",
56
+ "prompt": "continue the for-loop to the next iteration in this function",
57
+ "expected_output": "Does NOT activate plastic-continuing. Near-miss: shares 'continue' but is a code-editing task.",
58
+ "files": [],
59
+ "assertions": [
60
+ { "type": "code", "check": "router CHOICE != plastic-continuing", "observed": "none", "result": "pass" }
61
+ ]
62
+ },
63
+ {
64
+ "id": 7, "scope": "triggering", "set": "train",
65
+ "prompt": "resume the paused background download",
66
+ "expected_output": "Does NOT activate plastic-continuing. Near-miss: shares 'resume' but is unrelated to Plastic sessions.",
67
+ "files": [],
68
+ "assertions": [
69
+ { "type": "code", "check": "router CHOICE != plastic-continuing", "observed": "none", "result": "pass" }
70
+ ]
71
+ },
72
+ {
73
+ "id": 8, "scope": "triggering", "set": "validation",
74
+ "prompt": "what's the dashboard look like right now",
75
+ "expected_output": "May activate plastic-dashboard rather than plastic-continuing; an overview request without 'continue/resume' is a dashboard task.",
76
+ "files": [],
77
+ "assertions": [
78
+ { "type": "code", "check": "router CHOICE != plastic-continuing", "observed": "plastic-dashboard", "result": "pass" }
79
+ ]
80
+ },
81
+ {
82
+ "id": 9, "scope": "behavior", "set": "train",
83
+ "prompt": "Does the skill defer boot to the SessionStart hook rather than running it itself?",
84
+ "expected_output": "SKILL.md states boot (health check, core context, version banner, statusline) is owned by hook-session-start / plastic-statusline, not this skill.",
85
+ "files": ["skills/continuing/SKILL.md"],
86
+ "assertions": [
87
+ { "type": "convention", "check": "SKILL.md says boot is owned by the SessionStart hook and the skill does not run it", "observed": "'Boot is not this skill's job.' paragraph naming hook-session-start and plastic-statusline", "result": "pass" }
88
+ ]
89
+ },
90
+ {
91
+ "id": 10, "scope": "behavior", "set": "train",
92
+ "prompt": "Does the skill avoid running doctor / setting the statusline itself?",
93
+ "expected_output": "SKILL.md does NOT instruct running doctor.rb --core or setting the statusline; it attributes those to the hooks.",
94
+ "files": ["skills/continuing/SKILL.md"],
95
+ "assertions": [
96
+ { "type": "convention", "check": "no in-skill boot step invokes doctor.rb --core or sets the statusline; both are attributed to hooks", "observed": "doctor --core and statusline mentioned only as hook-owned in the 'Boot is not this skill's job' note", "result": "pass" }
97
+ ]
98
+ },
99
+ {
100
+ "id": 11, "scope": "behavior", "set": "train",
101
+ "prompt": "Is dashboard selection project-aware?",
102
+ "expected_output": "Project loaded -> `dashboard.rb project <slug>`; otherwise -> `dashboard.rb continue`. Skill only invokes, does not render.",
103
+ "files": ["skills/continuing/SKILL.md"],
104
+ "assertions": [
105
+ { "type": "convention", "check": "both dashboard invocations present and gated on project detection", "observed": "'dashboard.rb project <slug>' and 'dashboard.rb continue' in the 'Continue (present the dashboard)' section", "result": "pass" }
106
+ ]
107
+ },
108
+ {
109
+ "id": 12, "scope": "behavior", "set": "validation",
110
+ "prompt": "Is ledger-resume conditional and ledger-driven?",
111
+ "expected_output": "Resume fires only when a specific intent is named; reads savepoint.md last line as stage, verifies the stage file, rebuilds on drift, derives next step from first unchecked checklist item.",
112
+ "files": ["skills/continuing/SKILL.md"],
113
+ "assertions": [
114
+ { "type": "convention", "check": "Conditional Ledger-Resume section reads last ledger line, verifies stage file, calls rebuild_savepoint on drift, uses first unchecked checklist item", "observed": "all four present in 'Conditional Ledger-Resume'", "result": "pass" }
115
+ ]
116
+ },
117
+ {
118
+ "id": 13, "scope": "behavior", "set": "validation",
119
+ "prompt": "Are the stale prose-savepoint fields gone?",
120
+ "expected_output": "No 'In progress' / 'Blockers' fields read from a prose savepoint remain; the ledger model is used instead.",
121
+ "files": ["skills/continuing/SKILL.md"],
122
+ "assertions": [
123
+ { "type": "convention", "check": "no prose-savepoint announce template (In progress / Blockers from prose)", "observed": "absent; announce uses Stage/Next step/Context/Drift derived from ledger + checklist", "result": "pass" }
124
+ ]
125
+ },
126
+ {
127
+ "id": 14, "scope": "behavior", "set": "validation",
128
+ "prompt": "Is the 'Determine Store' local-store gap filled?",
129
+ "expected_output": "Step 2 of Determine Store describes local/project-store detection (no empty step).",
130
+ "files": ["skills/continuing/SKILL.md"],
131
+ "assertions": [
132
+ { "type": "convention", "check": "Determine Store step 2 documents local/project store detection via projects.yml + CWD match", "observed": "filled", "result": "pass" }
133
+ ]
134
+ },
135
+ {
136
+ "id": 15, "scope": "behavior", "set": "validation",
137
+ "prompt": "QMD is present. The user says: continue the work on the statusline coloring (names the intent by description, not id).",
138
+ "expected_output": "Before scanning the store with grep/Read to locate the named intent, runs `ruby ~/.plastic/scripts/qmd-sync search \"statusline coloring\"` to surface the candidate intent, then opens the authoritative intent file for the hit it resumes. No-op fallback to INDEX.md / file scan when QMD is absent.",
139
+ "files": ["skills/continuing/SKILL.md"],
140
+ "assertions": [
141
+ { "type": "human", "check": "qmd-sync search is run before grep/Read when the intent is named by description; authoritative file opened for the hit", "observed": "Conditional Ledger-Resume carries the QMD-first step: run qmd-sync search before grep/Read, then open the authoritative file; no-op fallback when QMD is absent", "result": "pass" }
142
+ ]
143
+ }
144
+ ]
145
+ }
@@ -0,0 +1,32 @@
1
+ # Context Management (Start-Save-Continue)
2
+
3
+ ## Save Point
4
+ Triggered by PreCompact hook or manually:
5
+ 1. Find active intent(s) from `~/.plastic/INDEX.md`
6
+ 2. Update active intent's `checklist.md` (check off completed items)
7
+ 3. Update active intent's `savepoint.md` (in-progress, next steps, blockers, discoveries)
8
+ 4. Add observations to `## Insights`
9
+ 5. Update INDEX.md
10
+ 6. Commit: `cd ~/.plastic && git add . && git commit -m "chore: savepoint — [intent name]"`
11
+ 7. Notify user to `/clear`
12
+
13
+ ## Continue
14
+ Triggered by UserPromptSubmit hook when user says "continue". Priority order:
15
+
16
+ **1. Active intents first (resume work):**
17
+ 1. Read INDEX.md → find active intent(s)
18
+ 2. Read active intent's `intent.md` → what and why
19
+ 3. Read active intent's `savepoint.md` → where we left off
20
+ 4. Read active intent's `checklist.md` → what's next
21
+ 5. Announce: intent name, current state, next step, blockers
22
+ 6. Resume
23
+
24
+ **2. No active intents → offer future intents:**
25
+ 1. List all future intents from INDEX.md
26
+ 2. Present them as options
27
+ 3. When user picks one, move to Active in INDEX.md
28
+
29
+ **3. Stale future intents (untouched 3+ days) → triage:**
30
+ - **activate** — start working on it now
31
+ - **abandon** — mark as abandoned
32
+ - **defer to agent** — implement, research, or ideate
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: plastic:creating-intent
2
+ name: plastic-creating-intent
3
3
  description: Use when new work begins, the user expresses a new goal, says "new intent", or no active intent exists for the current task. Creates intents in the global store (~/.plastic/store/) or in a project's store (~/.plastic/projects/{slug}/store/) depending on context.
4
4
  ---
5
5
 
@@ -30,7 +30,7 @@ description: Use when new work begins, the user expresses a new goal, says "new
30
30
 
31
31
  When creating a tactical intent in a project store:
32
32
  - Read the project's `AGENTS.md` for project context and decisions
33
- - Link back to the project's governing intent (from `projects.yml` `parent` field) via `sources`
33
+ - Link back to the project's governing intent (from `projects.yml` `parent` field) via `sources` (the project genuinely is formed from its founding intent, a true formative edge, reciprocated on the founding intent's `chain`)
34
34
  - Add `[[global:<parent_ID>]]` backlink in `## Links`
35
35
  - The intent's Folgezettel ID is scoped to the project store (run `folgezettel-id` against the project's store at `~/.plastic/projects/{slug}/store/`)
36
36
 
@@ -41,45 +41,82 @@ When creating a tactical intent in a project store:
41
41
  - **Global:** `~/.plastic/store/`
42
42
  - **Project:** `~/.plastic/projects/{slug}/store/`
43
43
 
44
- ### 2. Determine Folgezettel ID
45
-
46
- IDs are scoped to the store they live in. Use the correct store path:
47
-
48
- **Global store:**
49
- ```bash
50
- "${CLAUDE_PLUGIN_ROOT}/scripts/folgezettel-id" "~/.plastic/store"
51
- ```
52
-
53
- **Project store:**
54
- ```bash
55
- "${CLAUDE_PLUGIN_ROOT}/scripts/folgezettel-id" "~/.plastic/projects/{slug}/store"
56
- ```
57
-
58
- **Branch intent (has parent, either store):**
59
- ```bash
60
- "${CLAUDE_PLUGIN_ROOT}/scripts/folgezettel-id" "<STORE>" "<parent_id>"
61
- ```
44
+ ### 1b. Check for a Duplicate or Predecessor (QMD-first)
45
+
46
+ QMD-first (when available): before scanning the store with grep/Read, run
47
+ `ruby ~/.plastic/scripts/qmd-sync search "<terms>"` to surface candidate, prior, or duplicate
48
+ intents, then open the authoritative intent file for any hit you act on. The command is a no-op
49
+ when QMD is absent, so fall back to the existing INDEX.md / file scan. Do this before allocating
50
+ the id so a near-duplicate can be reused and a true predecessor can be set in `--sources`.
51
+
52
+ ### 2. Decide Branch vs Root
53
+
54
+ Decide this BEFORE scaffolding, because it sets whether you pass `--parent`.
55
+ Having a "parent" in mind does NOT automatically mean branch. Choose by meaning:
56
+
57
+ - **Branch (`14a`, `14b`)**: a sub-task, refinement, or direct continuation. It only
58
+ makes sense as part of the parent's work. Pass `--parent <parent_id>`.
59
+ - **Root (`15`, `16`)**: an independent thought. Two cases, decided by ORIGIN:
60
+ - **Created from another intent** (it emerged from that intent's lifecycle): make it a
61
+ root and set `--sources <ascendant_id>`. `sources` is reserved for true created-from /
62
+ direct-ascendant provenance (D1).
63
+ - **Merely related to / inspired by another intent** (it did NOT come out of that
64
+ intent's lifecycle): carry NO `--sources`. Record the relation on the PREDECESSOR's
65
+ `chain` instead, and mirror it as a `[[id]]` wikilink in `## Links` (the
66
+ related-but-not-spawned rule).
67
+ - **Rule of thumb:** if the intent could exist without its parent, make it a root; only set
68
+ `--sources` when it was genuinely created from / emerged from that intent's lifecycle.
69
+ Topic similarity alone is not a `sources` edge.
62
70
 
63
71
  ### 3. Determine Intent Properties
64
72
 
65
73
  Ask or infer from context:
66
74
  - **intent**: one-line description
75
+ - **slug**: short hyphenated handle for the directory name
67
76
  - **author**: `human` | `claude-code` | other agent name
68
- - **sources**: array of Folgezettel IDs that influenced this intent (e.g., `["4a1"]`)
69
- - **chain**: starts empty `[]`, populated when this intent spawns others
77
+ - **sources**: the direct ascendant(s) this intent was created from / emerged from the
78
+ lifecycle of (formation, not topic similarity), e.g., `4a1`. For a project intent,
79
+ include the governing intent's id. A branch's structural parent is ALSO recorded in
80
+ `sources` (the ID carries it for the human/paper tree, `sources` carries it for
81
+ software), which `new-intent` does automatically (see `new-intent:126`).
70
82
  - **tags**: freeform list (use `project-<name>` for project membership)
71
83
 
72
- Place in `## Active` or `## Future` in INDEX.md (status is convention-derived, not a frontmatter field).
84
+ `chain` carries what this intent spawns AND related-but-not-spawned successors it leads to;
85
+ it starts empty and is populated later. See
86
+ `docs/concepts/how-plastic-sources-and-chains-intents.md` for the full model.
87
+ Place the intent in `## Active` or `## Future` in INDEX.md (status is
88
+ convention-derived, not a frontmatter field).
89
+
90
+ ### 4. Scaffold via new-intent (single call)
73
91
 
74
- ### 4. Create Directory and Files
92
+ Delegate id allocation, directory and file creation, the born-complete intent
93
+ file, the sentinel placeholder lifecycle files, the reciprocal file links, and
94
+ self-validation to one `new-intent` invocation. Do NOT hand-author any of these
95
+ files.
75
96
 
76
97
  ```bash
77
- mkdir -p <STORE>/ID--slug
98
+ "${CLAUDE_PLUGIN_ROOT}/scripts/new-intent" \
99
+ --store "<STORE>" --intent "<one-line>" --slug "<slug>" \
100
+ [--parent "<parent_id>"] [--author "<author>"] \
101
+ [--sources "id,id"] [--tags "project-<slug>,tag"]
78
102
  ```
79
103
 
80
- Write `{ID}--{slug}.md` using the intent template. For project intents, add the governing intent's ID to `sources` and add `[[global:ID]]` backlink in `## Links`.
104
+ `new-intent` allocates the Folgezettel id (root, or a branch of `--parent`),
105
+ creates `<STORE>/<id>--<slug>/` plus `actions/` and `resources/`, renders the
106
+ born-complete `<id>--<slug>.md` from the intent template, writes the sentinel
107
+ placeholder `spec.md`/`plan.md`/`checklist.md`/`outcome.md` (each marked
108
+ `<!-- plastic:placeholder -->` so no stage detector reads them as reached), wires
109
+ the reciprocal `[[id]]` links, and self-validates (frontmatter plus the sanctioned
110
+ `##` sections). It prints the created directory path and exits 0.
111
+
112
+ It does NOT touch INDEX.md, git, or project creation: those stay in this skill
113
+ (steps 6 to 9 below).
114
+
115
+ If `new-intent` exits non-zero, read the stderr report and fix the inputs (slug,
116
+ intent, sources). Do not commit or announce an intent that did not scaffold
117
+ cleanly, and do not work around the failure by hand-writing the files.
81
118
 
82
- ### 5. If Implementation Intent Spawns a Project
119
+ ### 6. If Implementation Intent Spawns a Project
83
120
 
84
121
  When the user says "start building" or the plan calls for a new project:
85
122
 
@@ -89,8 +126,6 @@ When the user says "start building" or the plan calls for a new project:
89
126
  mkdir -p <project_root>/<slug>
90
127
  cd <project_root>/<slug>
91
128
  git init
92
- mkdir -p ~/.plastic/projects/{slug}/store
93
- touch ~/.plastic/projects/{slug}/store/.gitkeep
94
129
  ```
95
130
  3. Copy `AGENTS.md` template from `${CLAUDE_PLUGIN_ROOT}/templates/agents.md`
96
131
  4. Register in `~/.plastic/projects.yml`:
@@ -101,22 +136,33 @@ When the user says "start building" or the plan calls for a new project:
101
136
  registered: <today>
102
137
  status: active
103
138
  ```
104
- 5. Add `project-<slug>` to the intent's `tags` array
105
- 6. Auto-commit in both `~/.plastic/` and the new project
139
+ 5. Provision the project store (the single source of truth for store creation;
140
+ runs after step 4 because the provisioner requires the project to be
141
+ registered):
142
+ ```bash
143
+ ruby ~/.plastic/scripts/provision-project-store <slug>
144
+ ```
145
+ 6. Add `project-<slug>` to the intent's `tags` array
146
+ 7. Auto-commit in both `~/.plastic/` and the new project
106
147
 
107
- ### 6. Update INDEX.md
148
+ ### 7. Update INDEX.md
108
149
 
109
150
  - **Global intents:** update `~/.plastic/INDEX.md`
110
151
  - **Project intents:** no global INDEX.md change (tactical intents are project-scoped)
111
152
 
112
153
  Add to `## Active` (or `## Future`) and appropriate cluster.
113
154
 
114
- ### 7. Auto-commit
155
+ ### 8. Auto-commit
115
156
 
116
157
  ```bash
117
- cd <store-root> && git add . && git commit -m "feat: create intent ID — [name]"
158
+ cd <store-root> && git add . && git commit -m "feat: create intent ID - [name]"
118
159
  ```
119
160
 
120
- ### 8. Announce
161
+ ### 9. Announce
162
+
163
+ "Created intent ID - [name]. Placed in: [Active|Future]. Store: [global|project:<slug>|local]."
164
+
165
+ ## References
121
166
 
122
- "Created intent ID — [name]. Placed in: [Active|Future]. Store: [global|project:<slug>|local]."
167
+ - Read `references/lifecycle.md` for the full What→Why→How→Exec stage detail, filesystem-as-schema conventions, and creating-intent step-by-step
168
+ - Read `references/wikilinks.md` for the wikilink syntax table when adding `## Links` to intents
@@ -0,0 +1,72 @@
1
+ {
2
+ "skill_name": "plastic-creating-intent",
3
+ "notes": "Intent 68. Scope: output-quality for the sources-vs-chain construction rules (D1/D2). Asserts the related-but-not-spawned case produces NO sources plus a predecessor chain link and a ## Links mirror, contrasted with the created-from case (true ascendant -> --sources set, reciprocal chain). The machine-checkable half lives in test/new_intent_test.rb (test_sources_path_gets_child_in_chain_frontmatter); this file documents the agent-facing scenario for skill evaluation and is NOT run by bin/test.",
4
+ "evals": [
5
+ {
6
+ "id": 1,
7
+ "scope": "behavior",
8
+ "set": "train",
9
+ "prompt": "Create an intent for adding a retry policy to the uploader. It's related to intent 41 (the upload pipeline work) but it's independent: it did not come out of intent 41's lifecycle.",
10
+ "expected_output": "A new root intent is created with EMPTY sources (it was not created from 41). The relation is recorded on the PREDECESSOR: intent 41 gains the new intent's id in its frontmatter chain, and a [[<new-id>]] wikilink is added to intent 41's ## Links. The new intent is NOT given 41 in --sources (the related-but-not-spawned rule). No false symmetry: 41 keeps the new id on chain with no reciprocal sources.",
11
+ "files": [],
12
+ "assertions": [
13
+ {
14
+ "type": "code",
15
+ "check": "new intent sources is empty",
16
+ "observed": "sources: []",
17
+ "result": "pass"
18
+ },
19
+ {
20
+ "type": "code",
21
+ "check": "predecessor 41 chain includes new id",
22
+ "observed": "41.chain includes <new-id>",
23
+ "result": "pass"
24
+ },
25
+ {
26
+ "type": "code",
27
+ "check": "predecessor 41 ## Links has [[<new-id>]] mirror",
28
+ "observed": "[[<new-id>]] present in 41 ## Links",
29
+ "result": "pass"
30
+ }
31
+ ]
32
+ },
33
+ {
34
+ "id": 2,
35
+ "scope": "behavior",
36
+ "set": "validation",
37
+ "prompt": "Create an intent that is the direct continuation of intent 41: it emerged from intent 41's lifecycle and could not exist without it.",
38
+ "expected_output": "Because the new intent was genuinely CREATED FROM 41 (D1), it carries 41 in --sources (or branches from 41, which folds 41 into sources via the redundant-explicit rule). The reciprocal I1 backlink lands: intent 41's frontmatter chain gains the new intent's id. This is the created-from case, contrasted with the related-but-not-spawned case in eval 1.",
39
+ "files": [],
40
+ "assertions": [
41
+ {
42
+ "type": "code",
43
+ "check": "new intent sources includes 41",
44
+ "observed": "sources includes 41",
45
+ "result": "pass"
46
+ },
47
+ {
48
+ "type": "code",
49
+ "check": "predecessor 41 chain includes new id (I1 reciprocity)",
50
+ "observed": "41.chain includes <new-id>",
51
+ "result": "pass"
52
+ }
53
+ ]
54
+ },
55
+ {
56
+ "id": 3,
57
+ "scope": "behavior",
58
+ "set": "validation",
59
+ "prompt": "QMD is present. The user says: create an intent to add retry to the uploader.",
60
+ "expected_output": "Before allocating the id / scaffolding, runs `ruby ~/.plastic/scripts/qmd-sync search \"add retry to the uploader\"` to surface a near-duplicate or true predecessor, then opens the authoritative intent file for any hit (reusing a near-duplicate or setting a real predecessor in --sources). No-op fallback to INDEX.md / file scan when QMD is absent.",
61
+ "files": [],
62
+ "assertions": [
63
+ {
64
+ "type": "human",
65
+ "check": "qmd-sync search is run before id allocation; authoritative file opened for any hit; informs reuse / --sources",
66
+ "observed": "SKILL.md (or agent file) carries the QMD-first step: run qmd-sync search before grep/Read, then open the authoritative file; no-op fallback when QMD is absent",
67
+ "result": "pass"
68
+ }
69
+ ]
70
+ }
71
+ ]
72
+ }