@zalom/plastic 1.0.3 → 1.1.1
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 +11 -11
- package/PLASTIC.md +11 -9
- package/README.md +48 -1
- package/agents/plastic-enforcer.md +8 -5
- package/agents/plastic-future-intent-researcher.md +1 -1
- package/agents/plastic-intent-curator.md +9 -10
- package/agents/plastic-spec-specialist.md +9 -6
- package/bin/plastic.js +2 -2
- 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 +188 -9
- package/scripts/end-intent +330 -0
- package/scripts/hook-code-gate +1 -1
- package/scripts/hook-continue +2 -2
- package/scripts/hook-create-gate +2 -2
- package/scripts/hook-session-start +1 -1
- package/scripts/install.rb +2 -1
- package/scripts/lib/bridge.rb +116 -3
- package/scripts/lib/dashboard_banner.rb +8 -9
- package/scripts/lib/installer_core.rb +17 -8
- 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/store_provisioning.rb +1 -1
- package/scripts/lib/worktree.rb +21 -0
- package/scripts/new-intent +2 -1
- package/scripts/read-config +3 -3
- package/scripts/roadmap-next +44 -0
- package/scripts/roadmap-savepoint +64 -0
- package/scripts/{versions.rb → rollback.rb} +33 -41
- package/scripts/update.rb +1 -1
- package/skills/_active-intent-gate.md +1 -1
- package/skills/_decision-tables.md +50 -0
- package/skills/auto/SKILL.md +69 -68
- package/skills/auto/evals/evals.json +4 -4
- package/skills/auto/references/agent-architecture.md +2 -2
- package/skills/continuing/SKILL.md +23 -130
- package/skills/continuing/evals/evals.json +26 -80
- package/skills/dashboard/SKILL.md +18 -15
- 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 +3 -3
- package/skills/install/SKILL.md +10 -10
- package/skills/{brainstorming → intent-brainstorming}/SKILL.md +43 -45
- package/skills/intent-brainstorming/evals/evals.json +67 -0
- package/skills/{brainstorming → intent-brainstorming}/references/design-principles.md +12 -17
- package/skills/intent-continuing/SKILL.md +99 -0
- package/skills/intent-continuing/evals/evals.json +145 -0
- package/skills/intent-continuing/references/context-management.md +28 -0
- package/skills/{creating-intent → intent-creating}/SKILL.md +3 -3
- package/skills/{creating-intent → intent-creating}/evals/evals.json +1 -1
- package/skills/{intent-discovery → intent-discovering}/SKILL.md +1 -1
- package/skills/intent-ending/SKILL.md +151 -0
- package/skills/intent-ending/evals/evals.json +74 -0
- package/skills/{executing-plan → intent-executing}/SKILL.md +75 -15
- package/skills/intent-executing/evals/evals.json +66 -0
- package/skills/{brainstorming-grill-me → intent-grilling}/SKILL.md +4 -4
- package/skills/{linking-intents → intent-linking}/SKILL.md +1 -1
- package/skills/{linking-intents → intent-linking}/evals/evals.json +1 -1
- package/skills/{lock → intent-locking}/SKILL.md +1 -1
- package/skills/{writing-plans → intent-planning}/SKILL.md +48 -20
- package/skills/intent-planning/evals/evals.json +66 -0
- package/skills/{writing-plans → intent-planning}/references/plan-format.md +31 -7
- package/skills/{research → intent-researching}/SKILL.md +2 -2
- package/skills/{research → intent-researching}/evals/evals.json +1 -1
- package/skills/{savepoint → intent-savepoint}/SKILL.md +13 -1
- package/skills/intent-speccing/SKILL.md +69 -0
- package/skills/intent-speccing/evals/evals.json +126 -0
- package/skills/intent-speccing/references/per-section-fill-rules.md +92 -0
- package/skills/intent-speccing/references/self-verify-checklist.md +38 -0
- package/skills/intent-starting/SKILL.md +2 -2
- package/skills/intent-starting/evals/evals.json +2 -2
- 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/{creating-project → project-creating}/SKILL.md +2 -2
- package/skills/releasing/SKILL.md +66 -14
- 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/{versions → rollback}/SKILL.md +30 -20
- package/skills/{creating-skills → skill-creating}/SKILL.md +2 -2
- package/skills/{creating-skills → skill-creating}/evals/evals.json +5 -5
- package/skills/{creating-skills → skill-creating}/references/progressive-disclosure.md +2 -2
- package/skills/{evaluating-skills → skill-evaluating}/SKILL.md +1 -1
- package/skills/{evaluating-skills → skill-evaluating}/evals/evals.json +3 -3
- package/skills/{intent-curator → store-curating}/SKILL.md +6 -7
- package/skills/{intent-curator → store-curating}/evals/evals.json +1 -1
- package/skills/{managing-index → store-indexing}/SKILL.md +6 -7
- package/skills/{managing-index → store-indexing}/evals/evals.json +1 -1
- package/skills/{add-project-store → store-provisioning}/SKILL.md +2 -2
- package/skills/tutorial/SKILL.md +65 -0
- package/skills/tutorial/evals/evals.json +186 -0
- package/skills/tutorial/references/track-1-guided.md +123 -0
- package/skills/tutorial/references/track-2-auto.md +95 -0
- package/skills/tutorial/references/track-3-projects-and-roadmaps.md +110 -0
- package/skills/uninstall/SKILL.md +2 -2
- package/skills/update/SKILL.md +3 -3
- package/templates/agents.md +7 -7
- package/templates/config.yml +2 -1
- package/templates/index.md +4 -1
- package/skills/brainstorming/evals/evals.json +0 -22
- package/skills/savepoint/references/context-management.md +0 -32
- /package/skills/{creating-intent → intent-creating}/references/lifecycle.md +0 -0
- /package/skills/{creating-intent → intent-creating}/references/wikilinks.md +0 -0
- /package/skills/{executing-plan → intent-executing}/code-quality-reviewer-prompt.md +0 -0
- /package/skills/{executing-plan → intent-executing}/implementer-prompt.md +0 -0
- /package/skills/{executing-plan → intent-executing}/spec-reviewer-prompt.md +0 -0
- /package/skills/{linking-intents → intent-linking}/references/zettelkasten.md +0 -0
- /package/skills/{continuing → intent-savepoint}/references/context-management.md +0 -0
- /package/skills/{creating-project → project-creating}/references/hubs-projects.md +0 -0
- /package/skills/{creating-project → project-creating}/references/project-scaffolding.md +0 -0
- /package/skills/{creating-skills → skill-creating}/references/agents.md +0 -0
- /package/skills/{creating-skills → skill-creating}/references/evals.md +0 -0
- /package/skills/{creating-skills → skill-creating}/references/hooks.md +0 -0
- /package/skills/{creating-skills → skill-creating}/references/scripts.md +0 -0
- /package/skills/{creating-skills → skill-creating}/references/skills.md +0 -0
- /package/skills/{creating-skills → skill-creating}/scripts/scaffold.rb +0 -0
- /package/skills/{evaluating-skills → skill-evaluating}/assets/eval-template.json +0 -0
- /package/skills/{evaluating-skills → skill-evaluating}/references/convention-checks.md +0 -0
- /package/skills/{evaluating-skills → skill-evaluating}/references/eval-methodology.md +0 -0
- /package/skills/{managing-index → store-indexing}/references/zettelkasten-linking.md +0 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "plastic-intent-brainstorming",
|
|
3
|
+
"notes": "Intent 66a. Spec for the QMD-first step in the Why/explore-context phase (surface prior decisions/specs/outcomes before grep/Read). Runner is intent 76; spec only. Intent 164 extended this file with the prose-grilling, conflict-supersession, and handoff-to-speccing scenarios; evals 2-4 are pending a real observed run per the plastic-evaluating-skills convention.",
|
|
4
|
+
"evals": [
|
|
5
|
+
{
|
|
6
|
+
"id": 1,
|
|
7
|
+
"scope": "behavior",
|
|
8
|
+
"set": "validation",
|
|
9
|
+
"prompt": "QMD is present. Brainstorming the active intent during the Why phase, the agent needs prior decisions and specs on caching.",
|
|
10
|
+
"expected_output": "In the explore-project-context (Why) step, before scanning the store with grep/Read, runs `ruby ~/.plastic/scripts/qmd-sync search \"caching decisions\"` to surface prior decisions, specs, or outcomes, then opens the authoritative intent file for any hit it acts on. No-op fallback to INDEX.md / file scan when QMD is absent.",
|
|
11
|
+
"files": [],
|
|
12
|
+
"assertions": [
|
|
13
|
+
{
|
|
14
|
+
"type": "human",
|
|
15
|
+
"check": "qmd-sync search is run during Why before grep/Read; authoritative file opened for any hit",
|
|
16
|
+
"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",
|
|
17
|
+
"result": "pass"
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": 2,
|
|
23
|
+
"scope": "behavior",
|
|
24
|
+
"set": "validation",
|
|
25
|
+
"prompt": "During Why exploration for intent X, the owner first rules that a setting ships as a CLI flag. Later in the same session, after more discussion, the owner rules that it should ship as a config-file setting instead, explicitly reversing the earlier call.",
|
|
26
|
+
"expected_output": "The skill persists BOTH rulings as separate insight-append calls with --stage Why: one for the CLI-flag ruling when it was made, and a second for the config-file ruling that names the CLI-flag ruling as superseded and states that this ruling supersedes it. Neither call is skipped, merged, or batched.",
|
|
27
|
+
"files": [],
|
|
28
|
+
"assertions": [
|
|
29
|
+
{
|
|
30
|
+
"type": "human",
|
|
31
|
+
"check": "two separate `ruby ~/.plastic/scripts/insight-append {intent_dir} \"<ruling text>\" --stage Why --author human` calls are made, one per ruling, immediately as each ruling lands; the second insight names the superseded CLI-flag ruling and states supersession",
|
|
32
|
+
"result": "expect-pass"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": 3,
|
|
38
|
+
"scope": "behavior",
|
|
39
|
+
"set": "train",
|
|
40
|
+
"prompt": "Brainstorming a new intent about notification delivery, the agent needs to learn the owner's preferred channel (email, push, or SMS).",
|
|
41
|
+
"expected_output": "The agent asks a single conversational prose question about the preferred channel, one at a time, phrased as a sentence rather than a bulleted or lettered multiple-choice menu.",
|
|
42
|
+
"files": [],
|
|
43
|
+
"assertions": [
|
|
44
|
+
{
|
|
45
|
+
"type": "human",
|
|
46
|
+
"check": "the question is prose, not a chip/lettered multiple-choice menu; only one question is asked per message",
|
|
47
|
+
"result": "expect-pass"
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"id": 4,
|
|
53
|
+
"scope": "behavior",
|
|
54
|
+
"set": "train",
|
|
55
|
+
"prompt": "Design for intent Y is presented and the owner has ruled on every open section.",
|
|
56
|
+
"expected_output": "The skill states the enriched Why is captured (Context, Decisions, one insight per ruling) and invokes /plastic-intent-speccing as the handoff. It does not write spec.md itself.",
|
|
57
|
+
"files": [],
|
|
58
|
+
"assertions": [
|
|
59
|
+
{
|
|
60
|
+
"type": "code",
|
|
61
|
+
"check": "no spec.md write action is taken by this skill; the terminal message names /plastic-intent-speccing and states spec.md is not authored here",
|
|
62
|
+
"result": "expect-pass"
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
@@ -20,30 +20,25 @@ steps).
|
|
|
20
20
|
|
|
21
21
|
## Process Flow (diagram)
|
|
22
22
|
|
|
23
|
-
The Checklist above already states this ordered flow as numbered steps 1-
|
|
23
|
+
The Checklist above already states this ordered flow as numbered steps 1-6; this
|
|
24
24
|
diagram is the same flow in a visual form.
|
|
25
25
|
|
|
26
26
|
```dot
|
|
27
27
|
digraph brainstorming {
|
|
28
28
|
"Explore project context" [shape=box];
|
|
29
|
-
"
|
|
29
|
+
"Grill in prose" [shape=box];
|
|
30
30
|
"Propose 2-3 approaches" [shape=box];
|
|
31
31
|
"Present design sections" [shape=box];
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
"Explore project context" -> "Ask clarifying questions";
|
|
39
|
-
"Ask clarifying questions" -> "Propose 2-3 approaches";
|
|
32
|
+
"Owner rules?" [shape=diamond];
|
|
33
|
+
"Collect rulings\n(persist each immediately)" [shape=box];
|
|
34
|
+
"Invoke /plastic-intent-speccing" [shape=doublecircle];
|
|
35
|
+
|
|
36
|
+
"Explore project context" -> "Grill in prose";
|
|
37
|
+
"Grill in prose" -> "Propose 2-3 approaches";
|
|
40
38
|
"Propose 2-3 approaches" -> "Present design sections";
|
|
41
|
-
"Present design sections" -> "
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"Spec self-review\n(fix inline)" -> "User reviews spec?";
|
|
46
|
-
"User reviews spec?" -> "Write spec" [label="changes requested"];
|
|
47
|
-
"User reviews spec?" -> "Invoke plastic-writing-plans" [label="approved"];
|
|
39
|
+
"Present design sections" -> "Owner rules?";
|
|
40
|
+
"Owner rules?" -> "Present design sections" [label="no, revise"];
|
|
41
|
+
"Owner rules?" -> "Collect rulings\n(persist each immediately)" [label="yes"];
|
|
42
|
+
"Collect rulings\n(persist each immediately)" -> "Invoke /plastic-intent-speccing";
|
|
48
43
|
}
|
|
49
44
|
```
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plastic-intent-continuing
|
|
3
|
+
description: >-
|
|
4
|
+
Use when a specific intent is named to resume, by id or by description, or on `continuing
|
|
5
|
+
--intent {id}`. Reads that intent's savepoint ledger and hands off to plastic-intent-starting.
|
|
6
|
+
The general "continue" / new-session triggers belong to the plastic-continuing router, not
|
|
7
|
+
here, so a bare "continue" does not settle on this skill directly. Boot (health check, core
|
|
8
|
+
context, version, statusline) is owned by the SessionStart hook, not this skill. Does not
|
|
9
|
+
drive work autonomously (that is plastic-auto).
|
|
10
|
+
user-invocable: true
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Continuing (intent route)
|
|
14
|
+
|
|
15
|
+
`plastic-intent-continuing` is the intent route of `plastic-continuing`. It resumes ONE
|
|
16
|
+
specific intent by its savepoint ledger, then hands off to `plastic-intent-starting`. It does
|
|
17
|
+
NOT land on a dashboard and does NOT execute work autonomously (that is `plastic-auto`); both
|
|
18
|
+
of those are other routes' jobs.
|
|
19
|
+
|
|
20
|
+
**Boot is not this skill's job.** The `hook-session-start` hook already runs by construction on
|
|
21
|
+
every session start: it runs the core health check (`doctor --core`), primes `PLASTIC.md` +
|
|
22
|
+
store/project state, and prints the `Plastic Core loaded - v{version}` banner. The
|
|
23
|
+
`plastic-statusline` hook sets the statusline. So by the time this skill runs, core is loaded
|
|
24
|
+
and healthy (or the banner already warned otherwise). This skill picks up from there and
|
|
25
|
+
resumes the named intent. This is the seam future continue-flags build on (see [[39]]).
|
|
26
|
+
|
|
27
|
+
## When to Use
|
|
28
|
+
- A specific intent is named to resume, by id or by description
|
|
29
|
+
- `continuing --intent {id}`
|
|
30
|
+
|
|
31
|
+
## Determine Store
|
|
32
|
+
|
|
33
|
+
1. **Global store** - `~/.plastic/INDEX.md` exists → global mode.
|
|
34
|
+
2. **Local store** - a project store under `~/.plastic/projects/{slug}/` whose registered
|
|
35
|
+
path (in `~/.plastic/projects.yml`) matches the current working directory → project mode.
|
|
36
|
+
The SessionStart hook already detects this; here you only need the slug to scope the
|
|
37
|
+
named intent's store.
|
|
38
|
+
3. If neither exists → announce "No Plastic store found. Run /plastic-install."
|
|
39
|
+
|
|
40
|
+
## Conditional Ledger-Resume
|
|
41
|
+
|
|
42
|
+
Fires ONLY when the user explicitly asks to continue a SPECIFIC intent, or an agent is
|
|
43
|
+
instructed to continue one. It is not part of every boot.
|
|
44
|
+
|
|
45
|
+
QMD-first (when available): when the user names the intent by description rather than id, before
|
|
46
|
+
scanning the store with grep/Read run `ruby ~/.plastic/scripts/qmd-sync search "<terms>"` to
|
|
47
|
+
surface the candidate intent, then open the authoritative intent file for the hit you resume. The
|
|
48
|
+
command is a no-op when QMD is absent, so fall back to the existing INDEX.md / file scan.
|
|
49
|
+
|
|
50
|
+
For that intent's directory:
|
|
51
|
+
|
|
52
|
+
1. **Read `savepoint.md` FIRST (intent 81).** It is a deterministic, append-only ledger
|
|
53
|
+
(one line per event, newest at the bottom): `{utc-iso8601} {Stage} {milestone}`. Classify
|
|
54
|
+
the state from the **last line** alone, then verify ONLY that line's artifact. The bookends
|
|
55
|
+
are fixed: first line `What created`, last line either a cycle position or
|
|
56
|
+
`Done delivered|abandoned`.
|
|
57
|
+
|
|
58
|
+
| Last line | State | Verify only |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| `What {id}--{slug}.md` | born / parked | intent file exists |
|
|
61
|
+
| `Why started` | Why entered, no spec yet | spec.md not yet real; continue Why |
|
|
62
|
+
| `Why spec.md created` | Why done | spec.md present; continue to How |
|
|
63
|
+
| `How started` / `How plan.md created` | How in progress | plan.md; continue How |
|
|
64
|
+
| `How checklist.md created` / `Exec started` | ready for / in Exec | plan.md + checklist.md present; continue Exec |
|
|
65
|
+
| `Exec outcome.md created` | Exec done | outcome.md present; ready to complete |
|
|
66
|
+
| `Done delivered` / `Done abandoned` | terminal | do NOT cycle-resume; INDEX is authoritative |
|
|
67
|
+
|
|
68
|
+
2. **Verify the stage file.** Confirm only the last line's artifact exists and is non-empty
|
|
69
|
+
(ledger `How plan.md created` → `plan.md` must be present and non-empty). Do not re-probe
|
|
70
|
+
every lifecycle file.
|
|
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. A rebuilt ledger is the file-landing
|
|
73
|
+
skeleton (no `started`/`Done` lines), which still pins cycle position:
|
|
74
|
+
```bash
|
|
75
|
+
ruby -r ~/.plastic/scripts/lib/bridge -e 'Bridge.rebuild_savepoint("<intent_dir>")'
|
|
76
|
+
```
|
|
77
|
+
4. **Derive the next step:**
|
|
78
|
+
- First unchecked item in `checklist.md` if it exists, else
|
|
79
|
+
- "advance to the next lifecycle stage" (e.g. ledger shows Why/spec.md → next is How).
|
|
80
|
+
- The newest `## Insights` entry supplies human-readable context (Insights are
|
|
81
|
+
append-only, newest at the bottom).
|
|
82
|
+
5. **Announce, then hand off to `plastic-intent-starting`:**
|
|
83
|
+
```
|
|
84
|
+
Resuming intent [ID] - [name]
|
|
85
|
+
Store: [global | project:<slug> | local]
|
|
86
|
+
Stage: [from ledger last line]
|
|
87
|
+
Next step: [first unchecked checklist item | advance to <stage>]
|
|
88
|
+
Context: [newest ## Insights entry]
|
|
89
|
+
Drift: [none | ledger rebuilt from filesystem]
|
|
90
|
+
```
|
|
91
|
+
Hand off to `plastic-intent-starting`: it takes the lock, boards at this station, and is
|
|
92
|
+
where the single "auto or guided?" ask for the intent route lives, asked there exactly
|
|
93
|
+
once and never duplicated here. Its auto branch is the one that hands off to `plastic-auto`;
|
|
94
|
+
this skill never hands to `plastic-auto` directly.
|
|
95
|
+
|
|
96
|
+
## References
|
|
97
|
+
|
|
98
|
+
- Read `references/context-management.md` for the save/continue protocol and for
|
|
99
|
+
debugging the resume flow.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "plastic-intent-continuing",
|
|
3
|
+
"notes": "Intent 158a1: slimmed to the specific-intent resume route of plastic-continuing (D8, extract not duplicate). Bare 'continue' now belongs to the router; triggering evals 1-4 were recast so this skill's positives always name a specific intent, and eval 4 asserts bare 'continue' does NOT settle here directly. Behavior eval 11 (dashboard selection) was removed, relocated to plastic-project-continuing's evals. Behavior eval 15 is new: the terminal handoff goes to plastic-intent-starting, not directly to plastic-auto. Scopes: description triggering (1-8) and behavior/convention compliance of the ledger-resume skill (9-15).",
|
|
4
|
+
"results": {
|
|
5
|
+
"triggering": { "cases": 8, "passed": 8, "run": "2026-07-10, one subagent per case" },
|
|
6
|
+
"behavior": { "cases": 7, "passed": 7, "evidence": "convention checks against skills/intent-continuing/SKILL.md after the 158a1 extraction" }
|
|
7
|
+
},
|
|
8
|
+
"evals": [
|
|
9
|
+
{
|
|
10
|
+
"id": 1, "scope": "triggering", "set": "train",
|
|
11
|
+
"prompt": "continue intent 4a",
|
|
12
|
+
"expected_output": "Activates plastic-intent-continuing (a specific intent named by id).",
|
|
13
|
+
"files": [],
|
|
14
|
+
"assertions": [
|
|
15
|
+
{ "type": "code", "check": "router CHOICE == plastic-intent-continuing", "observed": "plastic-intent-continuing", "result": "pass" }
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": 2, "scope": "triggering", "set": "train",
|
|
20
|
+
"prompt": "resume the statusline-coloring intent",
|
|
21
|
+
"expected_output": "Activates plastic-intent-continuing (a specific intent named by description).",
|
|
22
|
+
"files": [],
|
|
23
|
+
"assertions": [
|
|
24
|
+
{ "type": "code", "check": "router CHOICE == plastic-intent-continuing", "observed": "plastic-intent-continuing", "result": "pass" }
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": 3, "scope": "triggering", "set": "validation",
|
|
29
|
+
"prompt": "continuing --intent 96",
|
|
30
|
+
"expected_output": "Activates plastic-intent-continuing (the --intent form).",
|
|
31
|
+
"files": [],
|
|
32
|
+
"assertions": [
|
|
33
|
+
{ "type": "code", "check": "router CHOICE == plastic-intent-continuing", "observed": "plastic-intent-continuing", "result": "pass" }
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": 4, "scope": "triggering", "set": "train",
|
|
38
|
+
"prompt": "continue",
|
|
39
|
+
"expected_output": "Does NOT settle on plastic-intent-continuing directly. Bare 'continue' with no specific intent named belongs to the plastic-continuing router, which defaults to plastic-project-continuing.",
|
|
40
|
+
"files": [],
|
|
41
|
+
"assertions": [
|
|
42
|
+
{ "type": "code", "check": "router CHOICE != plastic-intent-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-intent-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-intent-continuing. Near-miss: shares 'continue' but is a code-editing task.",
|
|
58
|
+
"files": [],
|
|
59
|
+
"assertions": [
|
|
60
|
+
{ "type": "code", "check": "router CHOICE != plastic-intent-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-intent-continuing. Near-miss: shares 'resume' but is unrelated to Plastic sessions.",
|
|
67
|
+
"files": [],
|
|
68
|
+
"assertions": [
|
|
69
|
+
{ "type": "code", "check": "router CHOICE != plastic-intent-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": "Does NOT activate plastic-intent-continuing directly; an overview request without a specific intent named is a dashboard/project-board task.",
|
|
76
|
+
"files": [],
|
|
77
|
+
"assertions": [
|
|
78
|
+
{ "type": "code", "check": "router CHOICE != plastic-intent-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/intent-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/intent-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": "validation",
|
|
101
|
+
"prompt": "Is ledger-resume conditional and ledger-driven?",
|
|
102
|
+
"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.",
|
|
103
|
+
"files": ["skills/intent-continuing/SKILL.md"],
|
|
104
|
+
"assertions": [
|
|
105
|
+
{ "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" }
|
|
106
|
+
]
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"id": 12, "scope": "behavior", "set": "validation",
|
|
110
|
+
"prompt": "Are the stale prose-savepoint fields gone?",
|
|
111
|
+
"expected_output": "No 'In progress' / 'Blockers' fields read from a prose savepoint remain; the ledger model is used instead.",
|
|
112
|
+
"files": ["skills/intent-continuing/SKILL.md"],
|
|
113
|
+
"assertions": [
|
|
114
|
+
{ "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" }
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"id": 13, "scope": "behavior", "set": "validation",
|
|
119
|
+
"prompt": "Is the 'Determine Store' local-store gap filled?",
|
|
120
|
+
"expected_output": "Step 2 of Determine Store describes local/project-store detection (no empty step).",
|
|
121
|
+
"files": ["skills/intent-continuing/SKILL.md"],
|
|
122
|
+
"assertions": [
|
|
123
|
+
{ "type": "convention", "check": "Determine Store step 2 documents local/project store detection via projects.yml + CWD match", "observed": "filled", "result": "pass" }
|
|
124
|
+
]
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"id": 14, "scope": "behavior", "set": "validation",
|
|
128
|
+
"prompt": "QMD is present. The user says: continue the work on the statusline coloring (names the intent by description, not id).",
|
|
129
|
+
"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.",
|
|
130
|
+
"files": ["skills/intent-continuing/SKILL.md"],
|
|
131
|
+
"assertions": [
|
|
132
|
+
{ "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" }
|
|
133
|
+
]
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"id": 15, "scope": "behavior", "set": "train",
|
|
137
|
+
"prompt": "Does the ledger-resume's terminal handoff go to plastic-intent-starting or directly to plastic-auto?",
|
|
138
|
+
"expected_output": "Step 5 announces state then hands off to plastic-intent-starting, which takes the lock and asks 'auto or guided?' exactly once; plastic-intent-starting's own auto branch is the one that hands to plastic-auto. This skill never hands to plastic-auto directly.",
|
|
139
|
+
"files": ["skills/intent-continuing/SKILL.md"],
|
|
140
|
+
"assertions": [
|
|
141
|
+
{ "type": "convention", "check": "step 5 hands off to plastic-intent-starting, not plastic-auto; the single ask is attributed to plastic-intent-starting", "observed": "present in 'Conditional Ledger-Resume' step 5", "result": "pass" }
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Context Management (Save, then resume-flow debugging)
|
|
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
|
+
## Debugging the resume flow
|
|
14
|
+
|
|
15
|
+
When a resume looks wrong (the announced stage does not match what is on disk, or the next
|
|
16
|
+
step looks stale):
|
|
17
|
+
|
|
18
|
+
1. Read `savepoint.md`'s last line directly; that line alone is the source of truth for stage
|
|
19
|
+
(see `SKILL.md`'s `## Conditional Ledger-Resume` for the full state table).
|
|
20
|
+
2. Confirm the artifact that line implies (`plan.md`, `checklist.md`, `outcome.md`, ...) is
|
|
21
|
+
present and non-empty on disk.
|
|
22
|
+
3. If the two disagree, the ledger has drifted: rebuild it rather than hand-editing:
|
|
23
|
+
`ruby -r ~/.plastic/scripts/lib/bridge -e 'Bridge.rebuild_savepoint("<intent_dir>")'`
|
|
24
|
+
4. Re-read the rebuilt last line and re-derive the next step from `checklist.md`'s first
|
|
25
|
+
unchecked item.
|
|
26
|
+
|
|
27
|
+
The general "land on the board / priority order / stale future intents" flow now lives in
|
|
28
|
+
`plastic-project-continuing`; this file no longer duplicates it.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: plastic-creating
|
|
2
|
+
name: plastic-intent-creating
|
|
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
|
user-invocable: true
|
|
5
5
|
---
|
|
@@ -73,7 +73,7 @@ Having a "parent" in mind does NOT automatically mean branch. Choose by meaning:
|
|
|
73
73
|
frontmatter edge and reproject. Links are decided by context influence (a `chain` edge has a high
|
|
74
74
|
bar: the candidate's context must materially help deliver this intent), not by shared files or a
|
|
75
75
|
similarity score. To gather candidates with their context and record an edge, use the
|
|
76
|
-
`plastic-linking
|
|
76
|
+
`plastic-intent-linking` skill and `scripts/link-suggest`.
|
|
77
77
|
|
|
78
78
|
### 3. Determine Intent Properties
|
|
79
79
|
|
|
@@ -126,7 +126,7 @@ cleanly, and do not work around the failure by hand-writing the files.
|
|
|
126
126
|
### 6. If Implementation Intent Spawns a Project
|
|
127
127
|
|
|
128
128
|
When the user says "start building" or the plan calls for a new project, invoke the
|
|
129
|
-
`plastic-creating
|
|
129
|
+
`plastic-project-creating` skill; it owns project directory creation, AGENTS.md
|
|
130
130
|
population, projects.yml registration, store provisioning, and the auto-commit of
|
|
131
131
|
both stores. Add `project-<slug>` to this intent's `tags` array either before
|
|
132
132
|
invoking it or as part of that skill's handoff.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"skill_name": "plastic-creating
|
|
2
|
+
"skill_name": "plastic-intent-creating",
|
|
3
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
4
|
"evals": [
|
|
5
5
|
{
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plastic-intent-ending
|
|
3
|
+
description: >
|
|
4
|
+
Wrap, finish, close, or mark an intent Done, delivered or abandoned. Use
|
|
5
|
+
when completing or abandoning an intent, when a checklist reaches 100
|
|
6
|
+
percent and Exec is finished, or when asked to "wrap this up".
|
|
7
|
+
user-invocable: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Intent Ending
|
|
11
|
+
|
|
12
|
+
The one procedure every terminal transition routes through. Auto mode, the
|
|
13
|
+
curator path, and releasing all call this skill (or its backing script,
|
|
14
|
+
`scripts/end-intent`) for the mechanical close instead of restating the same
|
|
15
|
+
prose three times. `abandoned` is the SAME procedure as `delivered`, not a
|
|
16
|
+
failure branch: only outcome.md content and the INDEX section differ.
|
|
17
|
+
|
|
18
|
+
## The 8 steps (0-7)
|
|
19
|
+
|
|
20
|
+
| # | Step | Who does it |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| 0 | Precondition check | You, before touching outcome.md |
|
|
23
|
+
| 1 | outcome.md + intent-file `## Outcome` summary | `scripts/end-intent` |
|
|
24
|
+
| 2 | INDEX.md terminal move (Active -> Completed/Abandoned) | `scripts/end-intent` |
|
|
25
|
+
| 3 | savepoint `Done` bookend | `scripts/end-intent` |
|
|
26
|
+
| 4 | store auto-commit | `scripts/end-intent` |
|
|
27
|
+
| 5 | disarm (worktree + lock) | You, after end-intent exits 0 |
|
|
28
|
+
| 6 | QMD reindex, async, LAST | You |
|
|
29
|
+
| 7 | EM-to-CTO report | You |
|
|
30
|
+
|
|
31
|
+
Steps 1-4 are ONE callable script, not four separate one-liners: this is
|
|
32
|
+
exactly what the failure mode this intent fixes looked like (releasing hand
|
|
33
|
+
authored the close in prose and dropped the savepoint bookend for two real
|
|
34
|
+
deliveries). Never restate outcome/INDEX/savepoint prose inline again; call
|
|
35
|
+
`scripts/end-intent`.
|
|
36
|
+
|
|
37
|
+
### Step 0. Precondition (the gate is section-blind, not selective)
|
|
38
|
+
|
|
39
|
+
`Bridge.check_gate` (scripts/lib/bridge.rb) is LIVE code already wired into
|
|
40
|
+
the write-time hook. Its outcome.md rule is a blind scan of the WHOLE
|
|
41
|
+
checklist.md: `content.scan(/^- \[ \]/)` counts every unchecked box, in
|
|
42
|
+
every section, with no awareness of which section a box lives in. ANY
|
|
43
|
+
unchecked box anywhere blocks the outcome.md write; there is no exemption
|
|
44
|
+
for orchestrator-owned or completion-tracking items.
|
|
45
|
+
|
|
46
|
+
1. Read checklist.md. Tick every item as it is actually performed, including
|
|
47
|
+
an item that describes the close itself: running this very procedure IS
|
|
48
|
+
what that item describes, so tick it at the moment you begin the close,
|
|
49
|
+
before authoring outcome.md. By the time outcome.md is written,
|
|
50
|
+
checklist.md must read 100 percent checked; there is no other way past
|
|
51
|
+
the gate.
|
|
52
|
+
2. Confirm every acceptance criterion in spec.md is verifiable (tests pass,
|
|
53
|
+
or the manual check described in its HOW line was actually run).
|
|
54
|
+
3. If checklist.md still has an unchecked box, stop here. Finish it first
|
|
55
|
+
(tick it if the described work is actually done, or do the remaining
|
|
56
|
+
work); do not attempt outcome.md and fight the gate's deny.
|
|
57
|
+
|
|
58
|
+
### Step 1-4. Run `scripts/end-intent`
|
|
59
|
+
|
|
60
|
+
First author outcome.md for real (never leave the scaffold placeholder in
|
|
61
|
+
place): copy `templates/outcome.md`, set the frontmatter to
|
|
62
|
+
`disposition: delivered` or `disposition: abandoned`, and fill `## Summary`,
|
|
63
|
+
`## Delivered`, `## Verification`, `## Follow-ups`. On abandon, `## Summary`
|
|
64
|
+
states the abandonment reason and the trail (see Pivot below). Also author
|
|
65
|
+
the rich INDEX entry note now (a short line in the store's existing
|
|
66
|
+
Completed/Abandoned convention: mode/tier, what shipped or why it was
|
|
67
|
+
abandoned, suite result, merge/spawn notes); content authoring stays with
|
|
68
|
+
you, `--index-note` only appends what you write.
|
|
69
|
+
|
|
70
|
+
Then call the script once:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
ruby ~/.plastic/scripts/end-intent \
|
|
74
|
+
--store <store_path> --id <intent_id> --disposition delivered|abandoned \
|
|
75
|
+
--outcome-summary "<one-line ## Outcome summary for the intent file>" \
|
|
76
|
+
--index-note "<rich Completed/Abandoned entry description>"
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
This does all of steps 1-4 in order: guards outcome.md (refuses a missing,
|
|
80
|
+
still-placeholder, or wrong-disposition file with exit 2 and authors
|
|
81
|
+
nothing), stamps the intent file's `## Outcome` section, moves the INDEX.md
|
|
82
|
+
line from `## Active` to `## Completed` or `## Abandoned` (dated today,
|
|
83
|
+
idempotent) with the `--index-note` text appended after the date so the
|
|
84
|
+
entry stays rich, appends the savepoint `Done` bookend, and commits the
|
|
85
|
+
store repo. Omit `--index-note` for a thin id+date entry, add `--no-commit`
|
|
86
|
+
when a separate commit step already covers the store, and `--dry-run` to
|
|
87
|
+
preview with no writes. Exit 0 is success; exit 1 is a usage or resolution
|
|
88
|
+
failure; exit 2 is the outcome.md guard refusing (fix outcome.md and re-run,
|
|
89
|
+
nothing was written).
|
|
90
|
+
|
|
91
|
+
### Step 5. Disarm (worktree + lock)
|
|
92
|
+
|
|
93
|
+
Two branches, decided by how this intent ships:
|
|
94
|
+
|
|
95
|
+
- **Shipped through a release** (the `plastic-releasing` flow reached this
|
|
96
|
+
close): merge the code branch back BEFORE removing the worktrees, via
|
|
97
|
+
`Worktree.finish(bridge_data, merge: true)`. Releasing's own workflow
|
|
98
|
+
already drives this; this skill's job here is only the outcome/INDEX/
|
|
99
|
+
savepoint/commit core above.
|
|
100
|
+
- **Auto mode or the curator path** (no release involved): plain remove,
|
|
101
|
+
branch survives for reclaim.
|
|
102
|
+
```bash
|
|
103
|
+
ruby -r ~/.plastic/scripts/lib/bridge -e \
|
|
104
|
+
'Bridge.disarm_auto(ENV["CLAUDE_CODE_SESSION_ID"], intent_id: "<ID>")'
|
|
105
|
+
```
|
|
106
|
+
`disarm_auto` releases both worktrees, clears the `delivery.lock`, and only
|
|
107
|
+
then makes the bridge purge-eligible, in that order. Never leave an
|
|
108
|
+
orphaned worktree; run `git worktree prune` on a stale reference.
|
|
109
|
+
|
|
110
|
+
### Step 6. QMD reindex, LAST
|
|
111
|
+
|
|
112
|
+
Only after step 5 has released the worktrees and cleared the lock, so the
|
|
113
|
+
index never references state about to disappear:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
ruby ~/.plastic/scripts/qmd-sync reindex --store <store-root> --async
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
No-op when QMD is absent. Runs in the background so it never blocks the
|
|
120
|
+
turn.
|
|
121
|
+
|
|
122
|
+
### Step 7. EM-to-CTO report
|
|
123
|
+
|
|
124
|
+
Brief the human like an engineering manager to a CTO: impact and risk first,
|
|
125
|
+
in plain language, the decision left to them (merge, release, or accept).
|
|
126
|
+
See `outcome.md` for the details; do not restate it verbatim.
|
|
127
|
+
|
|
128
|
+
## Abandoned is the same procedure
|
|
129
|
+
|
|
130
|
+
`disposition: abandoned` runs the identical steps 0-7. The only differences
|
|
131
|
+
are outcome.md content (Summary states why this was abandoned, not what was
|
|
132
|
+
delivered) and the INDEX target section (`## Abandoned` instead of
|
|
133
|
+
`## Completed`). Never branch the mechanical steps by disposition; the
|
|
134
|
+
script already does that internally.
|
|
135
|
+
|
|
136
|
+
## Mid-flight pivot
|
|
137
|
+
|
|
138
|
+
When the work that shipped differs from what spec.md or plan.md originally
|
|
139
|
+
called for, do not retcon those documents. Record the decision once in
|
|
140
|
+
`## Insights`, then let outcome.md carry the truth of what actually
|
|
141
|
+
happened, including the abandoned trail when part of the work was dropped
|
|
142
|
+
mid-flight. outcome.md is truth of delivery; spec and plan stay the
|
|
143
|
+
historical record of what was planned.
|
|
144
|
+
|
|
145
|
+
## Routing
|
|
146
|
+
|
|
147
|
+
`plastic-releasing`, `plastic-auto`, the curator agent, `store-curating`, and
|
|
148
|
+
`store-indexing` all delegate their mechanical close to this skill (or call
|
|
149
|
+
`scripts/end-intent` directly for steps 1-4). None of them restate the
|
|
150
|
+
outcome/INDEX/savepoint prose inline any more; if you find one that does,
|
|
151
|
+
that surface has drifted and should route here instead.
|