@zalom/plastic 1.4.0 → 1.4.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.
@@ -33,14 +33,19 @@ ruby ~/.plastic/scripts/dashboard.rb [continue|project <slug>] --data
33
33
  - `continue` (default) → the **global** board payload (`mode: "global"`).
34
34
  - `project <slug>` → that **project** board payload (`mode: "project"`).
35
35
 
36
- The payload is read-only JSON. Global-board fields: `date`, `store_health`, `recently_worked`,
37
- `next_work`, `counts`, `projects`, `project_totals`. Project-board fields: `slug`, `store_health`,
38
- `description`, `recently_worked`, `next_work`, `counts`, `active`, `future`. Each list carries
39
- cell-ready fields for its table: `next_work` rows are
36
+ The payload is read-only JSON. Global-board fields: `date`, `store_health`, `summary`,
37
+ `next_work`, `next_total`, `next_shown`, `counts`, `projects`, `project_totals`, `footer`.
38
+ Project-board fields: `slug`, `store_health`, `description`, `summary`, `counts`, `active`,
39
+ `active_total`, `active_shown`, `next_work`, `next_total`, `next_shown`, `footer`. `summary`
40
+ and `footer` are finished prose strings (2-3 sentences and one line respectively), built in
41
+ `dashboard.rb` and substituted verbatim, exactly like `{{date}}`/`{{description}}` already
42
+ are - never re-worded or re-derived by the skill. Each list carries cell-ready fields for
43
+ its table: `next_work` rows are
40
44
  `{id, intent, scope, lifecycle, value, disposition, flags, what, flags_label, line}`;
41
- `recently_worked` rows carry `{id, status, glyph, last_accessed_at, what, state, scope, line}`;
42
- `active`/`future` rows carry `{id, intent, created, bullet, scope, what, stage, line}`. The `what`,
43
- `scope`, and `flags_label` cell fields arrive pipe-escaped and whitespace-normalized.
45
+ `active` rows carry
46
+ `{id, intent, created, bullet, scope, what, stage, worker, activity, line}`. The `what`,
47
+ `scope`, `worker`, `activity`, and `flags_label` cell fields arrive pipe-escaped and
48
+ whitespace-normalized.
44
49
 
45
50
  Each board load runs the scoped store check (`doctor --store <scope>`): the global board runs
46
51
  `--store global` and a project board runs `--store <slug>`. The result rides in the payload as
@@ -57,24 +62,42 @@ Templates live in this skill's `templates/` directory:
57
62
 
58
63
  Fill mechanically, no rewriting, no re-sorting:
59
64
  - `{{a.b.count}}` → the integer (e.g. `counts.active` = that count).
60
- - `{{<list>.rows}}` → the four intent lists (`recently_worked`, `next_work`, `active`, `future`)
61
- render as **Markdown table rows**. The template hard-codes each table's header and separator;
62
- this placeholder becomes one data row per list entry, joined with real newlines, in that table's
63
- fixed column order (below). Drop each cell from the named payload field **verbatim**: cells
64
- arrive pre-escaped and whitespace-normalized from the script (pipes escaped as `\|`), so never
65
- re-escape, re-truncate, or reword them. Never emit `<br>`.
66
- - `recently_worked` (global) → `| {id} | {what} | {state} | {scope} |`
67
- - `recently_worked` (project) → `| {id} | {what} | {state} |`
65
+ - `{{<list>.rows}}` → the two intent lists (`active`, `next_work`) render as **Markdown table
66
+ rows**. The template hard-codes each table's header and separator; this placeholder becomes
67
+ one data row per list entry, joined with real newlines, in that table's fixed column order
68
+ (below). Drop each cell from the named payload field **verbatim**: cells arrive pre-escaped
69
+ and whitespace-normalized from the script (pipes escaped as `\|`), so never re-escape,
70
+ re-truncate, or reword them. Never emit `<br>`.
68
71
  - `next_work` → `| {id} | {what} | {value} | {disposition} | {flags_label} |`
69
- - `active` → `| {id} | {what} | {stage} |`
70
- - `future` `| {id} | {what} |`
71
- Overflow entry (empty `id`, `what` = `+N more`) one row with `+N more` in the Id column and
72
- every other cell blank. Empty list one full-width row with `_(none)_` in the Id column and
73
- every other cell blank, matching that table's column count (e.g. `| _(none)_ | | | | |` for
74
- the 5-column next_work table, `| _(none)_ | |` for the 2-column future table).
75
- - `{{projects.lines}}` the project rollup stays **prose**, one line per project (not a table):
72
+ - `active` → `| {id} | {what} | {stage} | {worker} | {activity} |`
73
+ Empty list → one full-width row with `_(none)_` in the Id column and every other cell blank,
74
+ matching that table's column count (e.g. `| _(none)_ | | | | |` for the 5-column next_work
75
+ table, `| _(none)_ | | | |` for the 5-column active table). Neither list carries an overflow
76
+ "+N more" row anymore (D5, intent 202): the true pool size rides on the payload as
77
+ `active_total`/`next_total` (shown counts as `active_shown`/`next_shown`), and `{{footer}}`
78
+ states it in prose instead.
79
+ - `{{projects.lines}}` (global board only) → the project rollup stays **prose**, one line per
80
+ project (not a table):
76
81
  `- **{slug}**: {description}, active {active}, done {done}, future {future}, last accessed {last_accessed_at[0,10]}`.
77
- - Scalars (`{{date}}`, `{{slug}}`, `{{description}}`) → substitute verbatim.
82
+ - Scalars (`{{date}}`, `{{slug}}`, `{{summary}}`, `{{footer}}`) → substitute verbatim. `summary`
83
+ and `footer` are finished prose built in `dashboard.rb`; do not rewrite, shorten, or
84
+ re-derive them from the counts - that is exactly the non-determinism D5 rules out.
85
+
86
+ ### Paging (conversational, D4)
87
+
88
+ The board shows a short page by default (Active capped at 3, Next-work at 5). When the
89
+ user asks for "more" or "all", re-invoke Step 1 with an explicit flag and re-fill the
90
+ template with the new payload - nothing is persisted to disk, the offset lives only in the
91
+ chat turn:
92
+ - "all" → add `--all` (lifts both caps to unbounded; the footer then shows equal shown/total).
93
+ - "more" → add `--limit-active N`/`--limit-next N` with a larger `N` for whichever list the
94
+ user is paging.
95
+
96
+ For a real, own-terminal pager instead, point the owner at `--plain`:
97
+ `ruby ~/.plastic/scripts/dashboard.rb project <slug> --plain | less` (or `continue --plain`
98
+ for the global board). `--plain` prints the full, uncapped board as plain text with no
99
+ Markdown table syntax; it is a separate CLI mode from `--data`, not something this skill
100
+ fills a template from.
78
101
 
79
102
  ### Step 3 — Present it (mandatory, every invocation)
80
103
 
@@ -139,8 +162,8 @@ intentional change means the skill is broken.
139
162
 
140
163
  ## Notes
141
164
 
142
- - The four intent lists (recently worked, active, future, next work) render as Markdown tables;
143
- the narrative wrappers, counts, and the project rollup stay prose. No Value x Effort grid
165
+ - The two intent lists (active, next work) render as Markdown tables; the prose summary,
166
+ footer, counts, and the project rollup stay prose (intent 202). No Value x Effort grid
144
167
  returns. Never emit `<br>`.
145
168
  - Clusters (Zettelkasten grouping in INDEX.md) are intentionally not rendered.
146
169
  - Additive: changes no core lifecycle, gate, or cycle logic.
@@ -22,14 +22,14 @@
22
22
  "id": 2,
23
23
  "scope": "behavior",
24
24
  "set": "validation",
25
- "prompt": "How do the four intent lists render on the Markdown boards?",
26
- "expected_output": "recently_worked, next_work, active, and future render as Markdown tables (fixed columns: next_work Id|What|Value|Disposition|Flags; active Id|What|Stage; future Id|What; recently_worked Id|What|State, plus a Scope column on the global board). The narrative wrappers, counts, and the projects rollup stay prose; no Value x Effort grid. Cells arrive pre-escaped from the payload and are dropped verbatim.",
25
+ "prompt": "How does the project board render after intent 202 (short by default, paged on request)?",
26
+ "expected_output": "The project board shows, in order, and nothing else: a 2-3 sentence prose summary of what was delivered most recently (built in dashboard.rb from completed/completed_on data, not the 24h-windowed recently_worked), an Active table capped at 3 rows (Id|What|Stage, ordered lifecycle-stage descending with a savepoint tie-break), a Next-work table capped at 5 rows (Id|What|Value|Disposition|Flags), and a one-line footer stating true totals (e.g. '3 of 12 active, 5 of 47 next work') plus how to see everything. The raw Future table and its {{future.rows}} placeholder, and the separate Recently-worked table, are both gone from dashboard-project.md. dashboard-global.md carries the equivalent fix (D6): a prose summary in place of its recently-worked table, the same honest footer, and the same --limit-active/--limit-next/--all/--plain mechanics.",
27
27
  "files": ["skills/dashboard/templates/dashboard-global.md", "skills/dashboard/templates/dashboard-project.md", "skills/dashboard/SKILL.md"],
28
28
  "assertions": [
29
29
  {
30
30
  "type": "convention",
31
- "check": "the four intent lists render as Markdown tables with the fixed columns; wrappers and the projects rollup stay prose; no grid",
32
- "observed": "templates hard-code table headers plus {{list.rows}} for recently_worked/next_work/active/future; SKILL.md Step 2 documents the fixed column order and verbatim pre-escaped cell fill; projects stays {{projects.lines}} prose",
31
+ "check": "project board template has summary+active+next_work+footer only (no future, no recently_worked table); global template has summary+footer added; SKILL.md documents the new payload fields and CLI flags",
32
+ "observed": "templates carry {{summary}}, {{active.rows}} (Id|What|Stage), {{next_work.rows}} (Id|What|Value|Disposition|Flags), {{footer}}; {{future.rows}} and the recently-worked table are removed from both; SKILL.md Step 1/2 document summary/footer/active_total/active_shown/next_total/next_shown and --limit-active/--limit-next/--all/--plain",
33
33
  "result": "pass"
34
34
  }
35
35
  ]
@@ -1,10 +1,6 @@
1
1
  # 🧩 Plastic · Global Board, {{date}}
2
2
 
3
- **Recently worked** (last 24h)
4
-
5
- | Id | What | State | Scope |
6
- | --- | --- | --- | --- |
7
- {{recently_worked.rows}}
3
+ {{summary}}
8
4
 
9
5
  ## Where we are
10
6
 
@@ -19,4 +15,6 @@
19
15
  | --- | --- | --- | --- | --- |
20
16
  {{next_work.rows}}
21
17
 
18
+ {{footer}}
19
+
22
20
  **What would you like to work on next?** (type an **intent id**, a **project name**, or anything **new** you'd like to start)
@@ -1,31 +1,19 @@
1
1
  # 📦 {{slug}} · Project Board, {{date}}
2
2
 
3
- {{description}}
4
-
5
- **Recently worked** (last active work, last 24h)
6
-
7
- | Id | What | State |
8
- | --- | --- | --- |
9
- {{recently_worked.rows}}
10
-
11
- ## Intents, active {{counts.active}}, done {{counts.done}}, future {{counts.future}}
3
+ {{summary}}
12
4
 
13
5
  **Active**
14
6
 
15
- | Id | What | Stage |
16
- | --- | --- | --- |
7
+ | Id | What | Stage | Worker | Activity |
8
+ | --- | --- | --- | --- | --- |
17
9
  {{active.rows}}
18
10
 
19
- **Future**
20
-
21
- | Id | What |
22
- | --- | --- |
23
- {{future.rows}}
24
-
25
- ## Most-valuable next work
11
+ **Most-valuable next work**
26
12
 
27
13
  | Id | What | Value | Disposition | Flags |
28
14
  | --- | --- | --- | --- | --- |
29
15
  {{next_work.rows}}
30
16
 
17
+ {{footer}}
18
+
31
19
  **What would you like to work on next?** (type an **intent id**, or **global** to go back)
@@ -19,23 +19,41 @@ Run from the project (the intent resolves from this session's bridge), or pass
19
19
 
20
20
  | Verb | What it does | When |
21
21
  |---|---|---|
22
+ | `who` | Print a compact owner, heartbeat, claim, and delegate view from durable files only | Safe human inspection; requires `--intent-dir` |
22
23
  | `status` | Report the lock file, bridge cache, freshness, agreement | Always safe; run first |
23
24
  | `fix` | Idempotent repair: rebuild lock + bridge from disk truth for THIS session. Never touches a fresh foreign lock | Interrupted work, corrupted state, /tmp wiped, legacy pid locks |
24
25
  | `release` | Owner clears the lock | Ending or abandoning a boarding |
25
26
  | `reclaim` | Explicit takeover of a STALE lock; appends an audit line to savepoint.md | The owner is gone and the lease expired |
26
- | `delegate` | Owner registers a subagent session under the lock (`--delegate <session-id>`) | Auto-mode orchestration |
27
+ | `delegate` | Owner registers a subagent session and optional provenance, or marks it `finished`/`failed` | Auto-mode orchestration |
27
28
 
28
29
  ```
29
30
  ruby ~/.plastic/scripts/plastic-lock status
31
+ ruby ~/.plastic/scripts/plastic-lock who --intent-dir <store>/<id>--<slug>
30
32
  ruby ~/.plastic/scripts/plastic-lock fix --intent-dir <store>/<id>--<slug>
31
33
  ruby ~/.plastic/scripts/plastic-lock reclaim --intent-dir <store>/<id>--<slug>
32
- ruby ~/.plastic/scripts/plastic-lock delegate --delegate <subagent-session-id>
34
+ ruby ~/.plastic/scripts/plastic-lock delegate --delegate <subagent-session-id> \
35
+ --harness codex --agent plastic-executor --model <model> --thread <thread-id>
36
+ ruby ~/.plastic/scripts/plastic-lock delegate --delegate <subagent-session-id> --status finished
33
37
  ```
34
38
 
39
+ When the current controller knows its provenance, `fix` and `reclaim` accept
40
+ `--harness`, `--agent`, `--model`, `--thread`, and `--mode auto|guided`.
41
+ Provenance is descriptive; the session remains the authorization identity.
42
+
35
43
  ## Rules
36
44
 
37
45
  - `fix` exits non-zero when another session holds a FRESH lock: back off, do
38
46
  not retry in a loop. `status` shows the owner.
47
+ - `who` is strictly read-only. It reads `delivery.lock`, its mtime, and claim
48
+ files; it never reads or repairs a bridge, searches transcripts, heartbeats,
49
+ or writes. Missing legacy provenance displays as `Unknown` rather than being
50
+ inferred.
51
+ - The `delivery.lock` file mtime is the sole heartbeat and freshness truth.
52
+ Provenance timestamps do not replace it.
53
+ - Only the lock owner may register delegates or mark them `finished` or
54
+ `failed`. Terminal status is observational and does not remove the delegate
55
+ session from the authorization list. Finished and failed activity history is
56
+ bounded to the 20 most recent terminal entries.
39
57
  - `reclaim` refuses a fresh lock. There is no silent reclaim anywhere; every
40
58
  takeover is audited in the intent's savepoint.md.
41
59
  - Acquiring a lock for new work is NOT this skill's job: board through
@@ -47,10 +47,10 @@ enforces it: without a held lock, mutating writes to this active intent's dir ar
47
47
  ```bash
48
48
  # guided (lock only):
49
49
  ruby -r ~/.plastic/scripts/lib/bridge -e \
50
- 'Bridge.arm_guided(ENV["CLAUDE_CODE_SESSION_ID"], intent_id: "<ID>", intent_dir: "<STORE>/<dir>", store: "<STORE>", name: "<name>")'
50
+ 'codex=ENV["CODEX_THREAD_ID"].to_s.strip; claude=ENV["CLAUDE_CODE_SESSION_ID"].to_s.strip; harness=!codex.empty? ? "codex" : (!claude.empty? ? "claude" : nil); session=!codex.empty? ? codex : (!claude.empty? ? claude : nil); Bridge.arm_guided(session, intent_id: "<ID>", intent_dir: "<STORE>/<dir>", store: "<STORE>", name: "<name>", harness: harness, agent: "plastic-enforcer", thread: (!codex.empty? ? codex : nil))'
51
51
  # auto (lock + auto), then hand to plastic-auto:
52
52
  ruby -r ~/.plastic/scripts/lib/bridge -e \
53
- 'Bridge.arm_auto(ENV["CLAUDE_CODE_SESSION_ID"], intent_id: "<ID>", intent_dir: "<STORE>/<dir>", store: "<STORE>", name: "<name>")'
53
+ 'codex=ENV["CODEX_THREAD_ID"].to_s.strip; claude=ENV["CLAUDE_CODE_SESSION_ID"].to_s.strip; harness=!codex.empty? ? "codex" : (!claude.empty? ? "claude" : nil); session=!codex.empty? ? codex : (!claude.empty? ? claude : nil); Bridge.arm_auto(session, intent_id: "<ID>", intent_dir: "<STORE>/<dir>", store: "<STORE>", name: "<name>", harness: harness, agent: "plastic-enforcer", thread: (!codex.empty? ? codex : nil))'
54
54
  ```
55
55
  Replace `<ID>`, `<STORE>` (`~/.plastic/projects/<slug>/store` or `~/.plastic/store`),
56
56
  `<dir>` (the `ID--slug` directory), and `<name>`.
@@ -67,8 +67,10 @@ enforces it: without a held lock, mutating writes to this active intent's dir ar
67
67
  discovery yields nothing, proceed to Why normally.
68
68
 
69
69
  **Session id resolution (verbatim from `plastic-auto`).** The first argument is the session
70
- id the bridge is keyed by: pass the hook stdin `session_id` when you have it, otherwise
71
- `ENV["CLAUDE_CODE_SESSION_ID"]`, otherwise `nil`. Both arms call `resolve_session`, which
70
+ id the bridge is keyed by: pass the hook stdin `session_id` when you have it; in the executable
71
+ snippets, a nonblank `CODEX_THREAD_ID` identifies Codex, otherwise a nonblank
72
+ `CLAUDE_CODE_SESSION_ID` identifies Claude, otherwise identity remains unknown. Never infer a
73
+ harness from an absent variable. Both arms call `resolve_session`, which
72
74
  picks the first non-empty of: the explicit id you pass → `CLAUDE_CODE_SESSION_ID` → a
73
75
  deterministic derived key (a hash of the store and intent id). It never returns nil, so the
74
76
  lock is taken even when every session env var is empty; arming prints a one-line stderr
@@ -104,6 +104,16 @@ state and stops, asking nothing (unchanged): it does not itself dispatch, re-ran
104
104
  roadmap. The global store and any project with no roadmap report `none`, so this board stays the
105
105
  default route for them.
106
106
 
107
+ Intent 202 has landed on top of 149/149a: the project board is short by default. The
108
+ Recently-worked table and the raw Future table are both gone, replaced by a 2-3 sentence
109
+ prose summary (built in `dashboard.rb`, not by this skill) plus a one-line footer stating
110
+ true totals. Active is capped at 3 (ordered lifecycle-stage descending, a later savepoint
111
+ breaking a tie - D2), Next-work at 5. Conversational paging ("more"/"all") re-invokes
112
+ `dashboard.rb ... --data` with `--limit-active`/`--limit-next`/`--all`, carrying no state on
113
+ disk; `--plain` prints the full uncapped board as plain text for a real pager. The rule-name
114
+ citations and the `dashboard.rb project <slug> --data` -> `dashboard-project.md` path still
115
+ resolve.
116
+
107
117
  ## References
108
118
 
109
119
  - `references/board-fill.md` - the template-fill mechanics and store-health surfacing detail.
@@ -71,11 +71,11 @@
71
71
  },
72
72
  {
73
73
  "id": 8, "scope": "behavior", "set": "validation",
74
- "prompt": "Does the skill carry the intent-149 coordination note?",
75
- "expected_output": "A 'Coordination' section records that intent 149 has landed (dashboard demoted to prose, no Value x Effort grid) and intent 149a has landed (the four intent lists render as Markdown tables), and confirms the rule-name citations and the dashboard.rb project <slug> --data -> dashboard-project.md path still resolve.",
74
+ "prompt": "Does the skill carry the intent-202 coordination note (project board short by default)?",
75
+ "expected_output": "A 'Coordination' section records that intent 202 has landed: the Recently-worked and raw Future tables are gone, replaced by a prose summary (built in dashboard.rb) and an honest-totals footer; Active is capped at 3 (lifecycle-stage descending, D2) and Next-work at 5; conversational paging re-invokes dashboard.rb --data with --limit-active/--limit-next/--all (no state on disk); --plain prints the full uncapped plain-text board. The rule-name citations and the dashboard.rb project <slug> --data -> dashboard-project.md path still resolve.",
76
76
  "files": ["skills/project-continuing/SKILL.md"],
77
77
  "assertions": [
78
- { "type": "convention", "check": "'149' present with the landed coordination note", "observed": "present: 'Intent 149 has landed' and 'Intent 149a has landed' (lists render as Markdown tables) with confirmed rule-name citations and dashboard.rb path", "result": "pass" }
78
+ { "type": "convention", "check": "'202' present with the landed coordination note describing the new shape, caps, paging flags, and --plain", "observed": "present: 'Intent 202 has landed' paragraph with the described content", "result": "pass" }
79
79
  ]
80
80
  },
81
81
  {
@@ -7,20 +7,22 @@ would otherwise bloat the SKILL.md body.
7
7
  ## Fill rules (owned by plastic-dashboard, summarized here for convenience)
8
8
 
9
9
  - `{{a.b.count}}` -> the integer (e.g. `counts.active` is that count).
10
- - `{{<list>.rows}}` -> the four intent lists (`recently_worked`, `next_work`, `active`, `future`)
11
- render as Markdown table rows. The template hard-codes each table's header and separator; the
12
- placeholder becomes one data row per entry, in that table's fixed column order, cells dropped
13
- verbatim from the payload (cells arrive pipe-escaped and whitespace-normalized; do not re-escape
14
- or re-truncate). Column order per table:
15
- - `recently_worked` -> `| id | what | state | scope |` (global), `| id | what | state |` (project)
10
+ - `{{<list>.rows}}` -> the two intent lists (`active`, `next_work`) render as Markdown table
11
+ rows. The template hard-codes each table's header and separator; the placeholder becomes one
12
+ data row per entry, in that table's fixed column order, cells dropped verbatim from the
13
+ payload (cells arrive pipe-escaped and whitespace-normalized; do not re-escape or
14
+ re-truncate). Column order per table:
16
15
  - `next_work` -> `| id | what | value | disposition | flags_label |`
17
- - `active` -> `| id | what | stage |`; `future` -> `| id | what |`
18
- Overflow entry (empty `id`, `what` = `+N more`) -> `+N more` in the Id column, other cells blank.
16
+ - `active` -> `| id | what | stage |`
19
17
  Empty list -> one full-width row with `_(none)_` in the Id column, other cells blank, matching
20
- that table's column count (e.g. `| _(none)_ | | | | |` for the 5-column next_work table,
21
- `| _(none)_ | |` for the 2-column future table). Never emit `<br>`.
18
+ that table's column count. Neither list carries an overflow "+N more" row (intent 202): the
19
+ true pool size rides on the payload (`active_total`/`next_total`, shown as
20
+ `active_shown`/`next_shown`), stated in prose by `{{footer}}` instead. Never emit `<br>`.
22
21
  - `{{projects.lines}}` (global board) -> the project rollup stays prose, one line per project.
23
- - Scalars (`{{date}}`, `{{slug}}`, `{{description}}`) -> substitute verbatim.
22
+ - Scalars (`{{date}}`, `{{slug}}`, `{{summary}}`, `{{footer}}`) -> substitute verbatim.
23
+ `summary` (the 2-3 sentence "what was delivered most recently") and `footer` (the
24
+ honest-totals + how-to-see-everything line) are finished prose built in `dashboard.rb`,
25
+ replacing the old recently-worked table and the raw future table respectively.
24
26
 
25
27
  No re-sorting, no re-summarizing, no hand-written prose replacing a line the payload already
26
28
  supplies. Same store state produces a byte-identical payload regardless of model.
@@ -59,7 +59,7 @@ remember where they left off.
59
59
 
60
60
  ## Before any track
61
61
 
62
- Every track opens with the same two checks: run `/plastic-update` first, so the walkthrough
63
- matches what is actually installed, and work in a sandbox (a throwaway repo, or a global-store
64
- intent) so nothing real is touched by mistake. Each reference restates this briefly; do not
65
- skip it even if the user seems experienced.
62
+ Every track opens with the same two checks: run `/plastic-update` first (`$plastic-update` on
63
+ Codex), so the walkthrough matches what is actually installed, and work in a sandbox (a
64
+ throwaway repo, or a global-store intent) so nothing real is touched by mistake. Each reference
65
+ restates this briefly; do not skip it even if the user seems experienced.
@@ -9,7 +9,8 @@ end to end: a piece of work moved through What, Why, How, and Exec, with a finis
9
9
 
10
10
  ## Before you start
11
11
 
12
- Run `/plastic-update` first, so the commands below match what is actually installed.
12
+ Run `/plastic-update` first (`$plastic-update` on Codex), so the commands below match what is
13
+ actually installed.
13
14
 
14
15
  Work in a sandbox: this track always creates a global-store intent; the throwaway repo below
15
16
  is never registered as a Plastic project. Pick a throwaway git repository if you have one
@@ -9,7 +9,8 @@ agent end to end, and pausing and resuming that delivery will feel familiar.
9
9
 
10
10
  ## Before you start
11
11
 
12
- Run `/plastic-update` first, so the commands below match what is actually installed.
12
+ Run `/plastic-update` first (`$plastic-update` on Codex), so the commands below match what is
13
+ actually installed.
13
14
 
14
15
  Work in a sandbox: a throwaway git repository, or a global-store intent. Nothing in this
15
16
  track touches a real project.
@@ -9,7 +9,8 @@ will exist with more than one intent inside it and a roadmap file describing the
9
9
 
10
10
  ## Before you start
11
11
 
12
- Run `/plastic-update` first, so the commands below match what is actually installed.
12
+ Run `/plastic-update` first (`$plastic-update` on Codex), so the commands below match what is
13
+ actually installed.
13
14
 
14
15
  Work in a sandbox: this whole track is a walked example. It creates a real project directory
15
16
  and a real roadmap file on disk, but the project is a throwaway one made for learning, not