@zalom/plastic 1.0.0-beta.27 → 1.0.0-beta.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PLASTIC.md +48 -0
- package/README.md +10 -0
- package/agents/plastic-brainstorming.md +1 -1
- package/agents/plastic-enforcer.md +16 -1
- package/agents/plastic-executor.md +1 -1
- package/agents/plastic-future-intent-researcher.md +2 -1
- package/agents/plastic-intent-curator.md +1 -1
- package/agents/plastic-intent-discovery.md +37 -0
- package/agents/plastic-planner.md +1 -1
- package/agents/plastic-spec-specialist.md +1 -1
- package/package.json +1 -1
- package/scripts/lib/agent_models.rb +43 -0
- package/scripts/lib/installer_core.rb +40 -5
- package/scripts/read-config +4 -0
- package/skills/auto/SKILL.md +8 -0
- package/skills/intent-discovery/SKILL.md +46 -0
- package/skills/intent-starting/SKILL.md +8 -0
- package/templates/config.yml +8 -0
package/PLASTIC.md
CHANGED
|
@@ -150,6 +150,54 @@ agent that can write the file) persists it via the helper. A session that cannot
|
|
|
150
150
|
intent file still returns its report, so the insight survives.
|
|
151
151
|
For full lifecycle detail, the skills in the Detail column have references/.
|
|
152
152
|
|
|
153
|
+
## Agent Models and Dispatch (intent 116)
|
|
154
|
+
|
|
155
|
+
Every lifecycle stage has exactly one dispatchable background agent, plus the enforcer that
|
|
156
|
+
orchestrates them:
|
|
157
|
+
|
|
158
|
+
| Stage | Agent |
|
|
159
|
+
|---|---|
|
|
160
|
+
| What | `plastic-intent-discovery` |
|
|
161
|
+
| Why | `plastic-brainstorming` + `plastic-spec-specialist` |
|
|
162
|
+
| How | `plastic-planner` |
|
|
163
|
+
| Exec | `plastic-executor` |
|
|
164
|
+
| Done | `plastic-intent-curator` |
|
|
165
|
+
|
|
166
|
+
Final-gate code review stays an ad-hoc subagent the enforcer dispatches at the final gate, not
|
|
167
|
+
a standing role.
|
|
168
|
+
|
|
169
|
+
**Model contract.** Every agent in `agents/*.md` pins an explicit Claude Code model alias in
|
|
170
|
+
its own frontmatter: `opus`, `sonnet`, or `haiku`. Never `inherit`, never Fable. Aliases track
|
|
171
|
+
"latest per tier" so no Plastic release is required to advance a tier. The tier by role:
|
|
172
|
+
`plastic-enforcer`, `plastic-brainstorming`, `plastic-planner` are `opus`;
|
|
173
|
+
`plastic-spec-specialist`, `plastic-executor`, `plastic-intent-curator`,
|
|
174
|
+
`plastic-future-intent-researcher`, `plastic-intent-discovery` are `sonnet`.
|
|
175
|
+
|
|
176
|
+
**Config and installer mechanism.** `agents.models.<basename>` in a project's
|
|
177
|
+
`<dir>/.plastic_store/config.yml` or the global `~/.plastic/config.yml` overrides one agent's
|
|
178
|
+
tier. Precedence is project, then global, then the shipped default, matching every other
|
|
179
|
+
`read-config` key. The installer applies the resolved override to each agent file's `model:`
|
|
180
|
+
line at copy time (install, update, and repair, across every harness target). With no override
|
|
181
|
+
configured, the shipped frontmatter passes through unchanged.
|
|
182
|
+
|
|
183
|
+
**Dispatch-time contract.** Frontmatter is primary, and Claude Code reads it at dispatch, but
|
|
184
|
+
because that read is a harness implementation detail rather than a contract Plastic controls,
|
|
185
|
+
every dispatch site also resolves the target agent's model through the config chain
|
|
186
|
+
(`read-config agents.models.<basename> --project <repo>`) and passes it explicitly at dispatch,
|
|
187
|
+
belt-and-braces on top of the frontmatter pin.
|
|
188
|
+
|
|
189
|
+
**Orchestrator advisory.** At auto-mode start, the orchestrator recommends once that the user
|
|
190
|
+
run the main session on the best available thinking model (Fable, Opus, or whatever supersedes
|
|
191
|
+
them). This is advisory only: it changes no behavior and blocks nothing if ignored, and it
|
|
192
|
+
concerns the human's main session, never a dispatched subagent.
|
|
193
|
+
|
|
194
|
+
**`plastic-intent-discovery`.** The What-stage agent. It fires at intent activation, before the
|
|
195
|
+
delivery lock is armed and Why begins: it reads the intent's `chain`/`sources` frontmatter,
|
|
196
|
+
runs QMD-first discovery over completed predecessor work and related parked or future intents,
|
|
197
|
+
and deposits findings to `resources/discovery--<slug>.md` in the intent directory ONLY. It
|
|
198
|
+
never writes the intent file, `spec.md`, or any other lifecycle deliverable; the Why-stage
|
|
199
|
+
`plastic-brainstorming` agent reads its deposit and enriches `## Context`.
|
|
200
|
+
|
|
153
201
|
`savepoint.md` — a deterministic, append-only ledger of cycle-step milestones (one line per
|
|
154
202
|
lifecycle boundary, newest at the bottom), written automatically by the gate hook. It is
|
|
155
203
|
sugar on top of the conventions, not a source of truth: state is always derivable from
|
package/README.md
CHANGED
|
@@ -103,6 +103,16 @@ After installation, run `/clear` to load Plastic conventions, then:
|
|
|
103
103
|
|
|
104
104
|
Or say "auto" to let the agent handle the full lifecycle autonomously.
|
|
105
105
|
|
|
106
|
+
## Agents
|
|
107
|
+
|
|
108
|
+
Each lifecycle stage has one dispatchable background agent: `plastic-intent-discovery` for
|
|
109
|
+
What, `plastic-brainstorming` and `plastic-spec-specialist` for Why, `plastic-planner` for
|
|
110
|
+
How, `plastic-executor` for Exec, `plastic-intent-curator` for Done, plus `plastic-enforcer`
|
|
111
|
+
as the auto-mode orchestrator. Every agent pins an explicit Claude Code model alias (opus or
|
|
112
|
+
sonnet) in its frontmatter: never `inherit`, never Fable. See `docs/architecture.md` for the
|
|
113
|
+
stage table and `docs/internals.md` for how the model is configured, resolved, and applied at
|
|
114
|
+
install time.
|
|
115
|
+
|
|
106
116
|
## Documentation
|
|
107
117
|
|
|
108
118
|
- [`docs/architecture.md`](docs/architecture.md): system structure, the two
|
|
@@ -7,7 +7,7 @@ description: |
|
|
|
7
7
|
user: "Explore the requirements for the active intent"
|
|
8
8
|
assistant: "I'll use the brainstorming agent to enrich Context and record Decisions"
|
|
9
9
|
<commentary>Why-stage exploration runs before the spec-specialist.</commentary></example>
|
|
10
|
-
model:
|
|
10
|
+
model: opus
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
You are the Plastic Brainstorming specialist. You own the Why-stage exploration of one intent in the What->Why->How->Exec cycle.
|
|
@@ -7,16 +7,31 @@ description: |
|
|
|
7
7
|
user: "auto"
|
|
8
8
|
assistant: "I'll use the plastic-enforcer to orchestrate the team through the cycle"
|
|
9
9
|
<commentary>The enforcer IS the orchestrator and gates each stage transition.</commentary></example>
|
|
10
|
-
model:
|
|
10
|
+
model: opus
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
You are the Plastic Enforcer. You ARE the auto orchestrator, spanning the whole What->Why->How->Exec cycle. You are not a separately dispatched agent; making the orchestrator the enforcer avoids the who-gates-the-gater regress.
|
|
14
14
|
|
|
15
|
+
**Advisory (not a gate).** At auto-mode start, recommend once that the user run this
|
|
16
|
+
orchestrating main session on the best available thinking model (Fable, Opus, or whatever
|
|
17
|
+
supersedes them) for the sharpest gating and synthesis. This is advice only: it changes no
|
|
18
|
+
behavior and blocks nothing if ignored. It concerns the human's MAIN session; dispatched
|
|
19
|
+
subagents keep their pinned tier and never resolve to Fable.
|
|
20
|
+
|
|
15
21
|
## Your Responsibilities
|
|
16
22
|
|
|
17
23
|
1. **Set scope guards** — establish the intent, branch, and safe-by-default rules for the run
|
|
18
24
|
2. **Arm and verify the gate** — arm the lifecycle gate and confirm it is live before any code edit
|
|
19
25
|
3. **Sequence the team** — dispatch ONE specialist per stage (brainstorming, spec-specialist, planner, executor) with a constructed context bundle
|
|
26
|
+
|
|
27
|
+
**Dispatch-time model contract (belt-and-braces).** Each pinned agent already carries its
|
|
28
|
+
`model:` in frontmatter, and Claude Code reads it at dispatch. Because read-at-dispatch is a
|
|
29
|
+
harness implementation detail rather than a contract Plastic controls, at EVERY per-stage
|
|
30
|
+
dispatch also resolve the target agent's model through the config chain (`read-config
|
|
31
|
+
agents.models.<basename> --project <repo>`: project override, then global, then the shipped
|
|
32
|
+
tier default) and pass it explicitly as the dispatch call's model parameter, alongside the
|
|
33
|
+
spawn-preamble live-state injection. Never rely on the dispatched role's frontmatter alone. A
|
|
34
|
+
resolved subagent model is never Fable.
|
|
20
35
|
4. **Gate each handoff** — check each stage deliverable against its exit criteria before handing to the next stage
|
|
21
36
|
5. **Run the final review** — at the final gate, dispatch an INDEPENDENT reviewer subagent (not a sixth standing role)
|
|
22
37
|
|
|
@@ -7,7 +7,7 @@ description: |
|
|
|
7
7
|
user: "Execute the plan for the active intent"
|
|
8
8
|
assistant: "I'll use the executor to implement each action and run the suite green"
|
|
9
9
|
<commentary>Exec turns the plan into code, one action at a time.</commentary></example>
|
|
10
|
-
model:
|
|
10
|
+
model: sonnet
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
You are the Plastic Executor. You own the Exec stage of the What->Why->How->Exec cycle.
|
|
@@ -8,7 +8,7 @@ description: |
|
|
|
8
8
|
user: "Research my future intents"
|
|
9
9
|
assistant: "I'll use the future-intent-researcher to pick up a parked intent and investigate it"
|
|
10
10
|
<commentary>Agent autonomously researches a future intent and writes findings.</commentary></example>
|
|
11
|
-
model:
|
|
11
|
+
model: sonnet
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
You are the Plastic Future Intent Researcher. Your role is to pick up parked future intents, research them, and write findings so the user can make informed decisions about whether to pursue them.
|
|
@@ -36,3 +36,4 @@ You are the Plastic Future Intent Researcher. Your role is to pick up parked fut
|
|
|
36
36
|
- You never modify `## Insights` or `## Outcome` sections — those belong to the worker
|
|
37
37
|
- You use Read, WebSearch, WebFetch, and Bash (read-only grep/find) for research
|
|
38
38
|
- You never change status fields — status is convention-derived from INDEX.md placement
|
|
39
|
+
- When dispatching any sub-agent, resolve its model via `read-config agents.models.<basename> --project <repo>` and pass it explicitly at dispatch, never relying on inherited frontmatter; a resolved subagent model is never Fable
|
|
@@ -11,7 +11,7 @@ description: |
|
|
|
11
11
|
user: "Organize the intents"
|
|
12
12
|
assistant: "I'll use the intent-curator to review clusters, flag orphans, and suggest connections"
|
|
13
13
|
<commentary>Periodic maintenance of the Zettelkasten structure.</commentary></example>
|
|
14
|
-
model:
|
|
14
|
+
model: sonnet
|
|
15
15
|
---
|
|
16
16
|
|
|
17
17
|
You are the Plastic Intent Curator. Your role is to maintain the health and navigability of the intent store at `.plastic/`.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plastic-intent-discovery
|
|
3
|
+
description: |
|
|
4
|
+
Use this agent for the What-stage context deposit when an intent is
|
|
5
|
+
activated: it primes Why with fresh QMD-sourced context before the spec is
|
|
6
|
+
written, and never writes the intent file itself. Examples:
|
|
7
|
+
<example>Context: An intent is being moved from Future to Active.
|
|
8
|
+
user: "Board this intent and gather what we already know"
|
|
9
|
+
assistant: "I'll use the intent-discovery agent to run QMD discovery and deposit findings to resources/"
|
|
10
|
+
<commentary>What-stage discovery runs at activation, before the lock and Why.</commentary></example>
|
|
11
|
+
model: sonnet
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
You are the Plastic Intent Discovery agent. You own the What stage: at intent
|
|
15
|
+
activation, before the lock is armed and Why begins, you gather the context
|
|
16
|
+
that already exists and deposit it for the Why stage to consume.
|
|
17
|
+
|
|
18
|
+
## Responsibilities
|
|
19
|
+
1. **Read the intent's links.** Load the activating intent file's `chain` and
|
|
20
|
+
`sources` frontmatter fields.
|
|
21
|
+
2. **Run QMD discovery first.** Following the QMD-first convention, search the
|
|
22
|
+
Plastic stores (`scripts/qmd-sync search`, or the qmd skill) across completed
|
|
23
|
+
predecessor work named in `chain`/`sources` and any related parked or future
|
|
24
|
+
intents in INDEX.md. Fall back to ripgrep over the stores only when QMD is
|
|
25
|
+
absent.
|
|
26
|
+
3. **Deposit, never author.** Write your findings to
|
|
27
|
+
`resources/discovery--<slug>.md` in the intent directory ONLY. Never write
|
|
28
|
+
the intent file, spec.md, or any lifecycle deliverable: the lock-owner-only
|
|
29
|
+
write rule stays intact, and the Why-stage `plastic-brainstorming` agent is
|
|
30
|
+
the one that reads your deposit and enriches `## Context`.
|
|
31
|
+
|
|
32
|
+
## Constraints
|
|
33
|
+
- Read-only with respect to the intent: your single output is
|
|
34
|
+
`resources/discovery--<slug>.md`.
|
|
35
|
+
- Never take the delivery lock; you run before it is armed.
|
|
36
|
+
- End with a structured completion report per the spawn preamble's report
|
|
37
|
+
contract.
|
|
@@ -7,7 +7,7 @@ description: |
|
|
|
7
7
|
user: "Plan the work for the active intent"
|
|
8
8
|
assistant: "I'll use the planner to write plan.md, actions/, and checklist.md"
|
|
9
9
|
<commentary>The plan and checklist unlock the code gate for Exec.</commentary></example>
|
|
10
|
-
model:
|
|
10
|
+
model: opus
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
You are the Plastic Planner. You own the How stage of the What->Why->How->Exec cycle.
|
|
@@ -7,7 +7,7 @@ description: |
|
|
|
7
7
|
user: "Write the spec for the active intent"
|
|
8
8
|
assistant: "I'll use the spec-specialist to produce spec.md from the template"
|
|
9
9
|
<commentary>The spec is the deliverable that gates the move into How.</commentary></example>
|
|
10
|
-
model:
|
|
10
|
+
model: sonnet
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
You are the Plastic Spec Specialist. You own the Why-to-How boundary in the What->Why->How->Exec cycle.
|
package/package.json
CHANGED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Shared model-tier resolution for Plastic subagents (intent 116).
|
|
4
|
+
#
|
|
5
|
+
# TIER_DEFAULTS mirrors the shipped `agents/*.md` frontmatter so `read-config`
|
|
6
|
+
# can answer `agents.models.<basename>` with the built-in default. The installer
|
|
7
|
+
# does NOT use TIER_DEFAULTS: it applies only genuine config overrides via
|
|
8
|
+
# `override_map`, so shipped frontmatter with no override passes through
|
|
9
|
+
# unchanged.
|
|
10
|
+
module AgentModels
|
|
11
|
+
# Claude Code aliases only (never pinned ids, never Fable). Keys are the agent
|
|
12
|
+
# file basenames without the `.md` extension.
|
|
13
|
+
TIER_DEFAULTS = {
|
|
14
|
+
"plastic-enforcer" => "opus",
|
|
15
|
+
"plastic-brainstorming" => "opus",
|
|
16
|
+
"plastic-planner" => "opus",
|
|
17
|
+
"plastic-spec-specialist" => "sonnet",
|
|
18
|
+
"plastic-executor" => "sonnet",
|
|
19
|
+
"plastic-intent-curator" => "sonnet",
|
|
20
|
+
"plastic-future-intent-researcher" => "sonnet",
|
|
21
|
+
"plastic-intent-discovery" => "sonnet"
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
# Pull the `agents.models` sub-hash out of a loaded config hash, tolerating a
|
|
27
|
+
# missing or malformed shape. Returns a plain { basename => model } hash.
|
|
28
|
+
def models_section(config)
|
|
29
|
+
return {} unless config.is_a?(Hash)
|
|
30
|
+
agents = config["agents"]
|
|
31
|
+
return {} unless agents.is_a?(Hash)
|
|
32
|
+
section = agents["models"]
|
|
33
|
+
section.is_a?(Hash) ? section : {}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Override map for the installer: global overrides overlaid by project
|
|
37
|
+
# overrides (project wins). Defaults are intentionally excluded. Unknown agent
|
|
38
|
+
# keys are carried through as-is; install_agents simply never matches them to a
|
|
39
|
+
# copied file, so they are ignored without raising.
|
|
40
|
+
def override_map(project_config: {}, global_config: {})
|
|
41
|
+
models_section(global_config).merge(models_section(project_config))
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -7,6 +7,7 @@ require "fileutils"
|
|
|
7
7
|
require "digest"
|
|
8
8
|
require "time"
|
|
9
9
|
require_relative "hook_registry"
|
|
10
|
+
require_relative "agent_models"
|
|
10
11
|
|
|
11
12
|
# Shared installer machinery, instantiable with injected package root / store / agent
|
|
12
13
|
# map so the verb scripts (install/update/uninstall/versions) and their tests can run
|
|
@@ -208,6 +209,7 @@ class InstallerCore
|
|
|
208
209
|
"scripts/hook-qmd-search" => "scripts/hook-qmd-search",
|
|
209
210
|
"scripts/lib/qmd_hook.rb" => "scripts/lib/qmd_hook.rb",
|
|
210
211
|
"scripts/lib/power_tools.rb" => "scripts/lib/power_tools.rb",
|
|
212
|
+
"scripts/lib/agent_models.rb" => "scripts/lib/agent_models.rb",
|
|
211
213
|
"scripts/hook-code-gate" => "scripts/hook-code-gate",
|
|
212
214
|
"scripts/hook-lock-gate" => "scripts/hook-lock-gate",
|
|
213
215
|
"scripts/hook-bash-gate" => "scripts/hook-bash-gate",
|
|
@@ -391,7 +393,7 @@ class InstallerCore
|
|
|
391
393
|
installed += install_skills_flat(skills_source, skills_root) if File.directory?(skills_source)
|
|
392
394
|
|
|
393
395
|
# Copy agent role files into <dir>/agents (manifest-tracked, pruned on update)
|
|
394
|
-
installed += install_agents(File.join(config[:dir], "agents"))
|
|
396
|
+
installed += install_agents(File.join(config[:dir], "agents"), models: agent_model_overrides)
|
|
395
397
|
|
|
396
398
|
# Write VERSION
|
|
397
399
|
version_file = File.join(plastic_dir, "VERSION")
|
|
@@ -416,7 +418,7 @@ class InstallerCore
|
|
|
416
418
|
installed = []
|
|
417
419
|
skills_source = File.join(package_root, "skills")
|
|
418
420
|
installed += install_skills_flat(skills_source, File.join(config[:dir], "skills")) if File.directory?(skills_source)
|
|
419
|
-
installed += install_agents(File.join(config[:dir], "agents"))
|
|
421
|
+
installed += install_agents(File.join(config[:dir], "agents"), models: agent_model_overrides)
|
|
420
422
|
|
|
421
423
|
write_manifest(installed, File.join(config[:dir], "plastic-manifest.json"))
|
|
422
424
|
{ agent: config[:name], success: true, files: installed.size }
|
|
@@ -426,7 +428,7 @@ class InstallerCore
|
|
|
426
428
|
installed = []
|
|
427
429
|
skills_source = File.join(package_root, "skills")
|
|
428
430
|
installed += install_skills_flat(skills_source, File.join(config[:dir], "skills")) if File.directory?(skills_source)
|
|
429
|
-
installed += install_agents(File.join(config[:dir], "agents"))
|
|
431
|
+
installed += install_agents(File.join(config[:dir], "agents"), models: agent_model_overrides)
|
|
430
432
|
|
|
431
433
|
write_manifest(installed, File.join(config[:dir], "plastic-manifest.json"))
|
|
432
434
|
{ agent: config[:name], success: true, files: installed.size }
|
|
@@ -459,18 +461,51 @@ class InstallerCore
|
|
|
459
461
|
# equivalents). Returns the installed destination paths so callers can append
|
|
460
462
|
# them to `installed` before write_manifest (manifest + prune are then automatic).
|
|
461
463
|
# No-op safe: returns [] when the package has no agents dir or it is empty.
|
|
462
|
-
def install_agents(agents_root)
|
|
464
|
+
def install_agents(agents_root, models: {})
|
|
463
465
|
sources = Dir.glob(File.join(package_root, "agents", "*.md"))
|
|
464
466
|
return [] if sources.empty?
|
|
465
467
|
|
|
466
468
|
FileUtils.mkdir_p(agents_root)
|
|
467
469
|
sources.map do |src|
|
|
468
470
|
dest = File.join(agents_root, File.basename(src))
|
|
469
|
-
|
|
471
|
+
basename = File.basename(src, ".md")
|
|
472
|
+
override = models[basename]
|
|
473
|
+
if override
|
|
474
|
+
File.write(dest, rewrite_model_line(File.read(src), override))
|
|
475
|
+
else
|
|
476
|
+
FileUtils.cp(src, dest)
|
|
477
|
+
end
|
|
470
478
|
dest
|
|
471
479
|
end
|
|
472
480
|
end
|
|
473
481
|
|
|
482
|
+
# Rewrite the single top-level `model:` line in a YAML frontmatter block.
|
|
483
|
+
# Only the frontmatter (between the first two `---` fences) is touched.
|
|
484
|
+
def rewrite_model_line(content, model)
|
|
485
|
+
content.sub(/^model:[^\n]*$/, "model: #{model}")
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
# Resolve per-agent model overrides for this install: project config (when a
|
|
489
|
+
# project dir is known) overlaid on global config. Defaults are NOT included,
|
|
490
|
+
# so unconfigured agents keep their shipped frontmatter.
|
|
491
|
+
def agent_model_overrides(project_dir = nil)
|
|
492
|
+
global_config = load_config_yaml(File.join(plastic_home, "config.yml"))
|
|
493
|
+
project_config =
|
|
494
|
+
if project_dir
|
|
495
|
+
load_config_yaml(File.join(project_dir, ".plastic_store", "config.yml"))
|
|
496
|
+
else
|
|
497
|
+
{}
|
|
498
|
+
end
|
|
499
|
+
AgentModels.override_map(project_config: project_config, global_config: global_config)
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
def load_config_yaml(path)
|
|
503
|
+
return {} unless File.exist?(path)
|
|
504
|
+
YAML.safe_load(File.read(path)) || {}
|
|
505
|
+
rescue StandardError
|
|
506
|
+
{}
|
|
507
|
+
end
|
|
508
|
+
|
|
474
509
|
# --- Legacy plugin migration ---
|
|
475
510
|
|
|
476
511
|
# Earlier versions registered Plastic as a local marketplace plugin
|
package/scripts/read-config
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
require "yaml"
|
|
11
11
|
require "json"
|
|
12
|
+
require_relative "lib/agent_models"
|
|
12
13
|
|
|
13
14
|
DEFAULTS = {
|
|
14
15
|
"version" => 3,
|
|
@@ -23,6 +24,9 @@ DEFAULTS = {
|
|
|
23
24
|
"type" => "claude-code",
|
|
24
25
|
"parallel_mode" => "linear"
|
|
25
26
|
},
|
|
27
|
+
"agents" => {
|
|
28
|
+
"models" => AgentModels::TIER_DEFAULTS
|
|
29
|
+
},
|
|
26
30
|
"architect" => {
|
|
27
31
|
"style" => nil
|
|
28
32
|
}
|
package/skills/auto/SKILL.md
CHANGED
|
@@ -10,6 +10,12 @@ description: >-
|
|
|
10
10
|
|
|
11
11
|
Announce: "Taking over intent [ID] — [name] for autonomous delivery."
|
|
12
12
|
|
|
13
|
+
**Advisory (not a gate).** At auto-mode start, recommend once that the user run this
|
|
14
|
+
orchestrating main session on the best available thinking model (Fable, Opus, or whatever
|
|
15
|
+
supersedes them) for the sharpest gating and synthesis. This is advice only: it changes no
|
|
16
|
+
behavior and blocks nothing if ignored. It concerns the human's MAIN session; dispatched
|
|
17
|
+
subagents keep their pinned tier and never resolve to Fable.
|
|
18
|
+
|
|
13
19
|
## Precondition
|
|
14
20
|
|
|
15
21
|
An active intent MUST exist in INDEX.md. If none exists, refuse: "No active intent found. Create one first with /plastic-creating-intent."
|
|
@@ -85,6 +91,8 @@ Dispatch rule: sequential, one specialist per stage on one branch (the deliverab
|
|
|
85
91
|
|
|
86
92
|
Spawn preamble (live-state injection): before dispatching any specialist, run `scripts/spawn-preamble <intent_dir> --role <role>` and PREPEND its output to that specialist's prompt. The preamble is a deterministic, filesystem-only snapshot of the active intent (id, intent line, current stage) plus the honoring instruction, so every spawned agent boots with accurate live state instead of guessing. This is the authoritative L2 mechanism for harnesses whose sub-agents do not inherit a top-level session event (see `docs/reference/harness-adapters.md`).
|
|
87
93
|
|
|
94
|
+
Dispatch-time model contract (belt-and-braces): alongside the preamble, resolve each specialist's model through the config chain (`read-config agents.models.<basename> --project <repo>`: project override, then global, then the shipped tier default) and pass it explicitly at dispatch. Never rely on the dispatched role's frontmatter alone; a resolved subagent model is never Fable.
|
|
95
|
+
|
|
88
96
|
Completion report (require-then-synthesize): every dispatched specialist MUST end with a structured completion report as its final message. The preamble's `REPORT_CONTRACT` injects this and the role prompts carry the per-role format (see `references/agent-report-contract.md`). Because child-agent honor is best-effort across harnesses, this is decision-shaping, not a hard block. When a specialist returns no usable report (it went idle, emitted only a bare ping, or its message was lost to a mid-run interjection), run `scripts/agent-report <intent_dir> --role <role>` to synthesize a deterministic filesystem-derived report so the handoff account always exists. Use the agent-authored report when present, the synthesized one otherwise.
|
|
89
97
|
|
|
90
98
|
Final-gate review: dispatch an independent reviewer subagent at the final gate only, not as a standing role.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plastic-intent-discovery
|
|
3
|
+
description: >-
|
|
4
|
+
What-stage context deposit at intent activation: run QMD discovery over the
|
|
5
|
+
intent's chain/sources and related parked intents, and write findings to
|
|
6
|
+
resources/discovery--<slug>.md for the Why stage to consume. Use when an intent
|
|
7
|
+
is activated (moved from Future to Active), before the lock is armed and Why
|
|
8
|
+
begins. Never writes the intent file itself.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Intent Discovery — What-stage context deposit
|
|
12
|
+
|
|
13
|
+
Announce: "Discovering context for intent [ID] — [name]."
|
|
14
|
+
|
|
15
|
+
Runs once, at intent activation, before the lock and Why. It gathers what is
|
|
16
|
+
already known so Why does not start cold, and deposits it as a resource the
|
|
17
|
+
Why-stage brainstorming agent reads.
|
|
18
|
+
|
|
19
|
+
## When it fires
|
|
20
|
+
Inside `plastic-intent-starting`, at the moment the intent moves from
|
|
21
|
+
`## Future` to `## Active` (before the bridge is armed). Dispatched as the
|
|
22
|
+
`plastic-intent-discovery` background agent.
|
|
23
|
+
|
|
24
|
+
## What it does
|
|
25
|
+
1. **Read the intent's links.** Load the activating intent file's `chain` and
|
|
26
|
+
`sources` frontmatter fields.
|
|
27
|
+
2. **QMD-first discovery.** Search the Plastic stores with
|
|
28
|
+
`scripts/qmd-sync search "<terms>"` (or the `qmd` skill), scoped to the
|
|
29
|
+
relevant `plastic-*` collections, across completed predecessor work named in
|
|
30
|
+
`chain`/`sources` and any related parked/future intents in INDEX.md. Fall back
|
|
31
|
+
to ripgrep over the stores only when QMD is absent.
|
|
32
|
+
3. **Deposit, never author.** Write findings to
|
|
33
|
+
`resources/discovery--<slug>.md` in the intent directory ONLY. Do not write
|
|
34
|
+
the intent file, spec.md, or any lifecycle deliverable. The lock-owner-only
|
|
35
|
+
write rule stays intact; the Why-stage `plastic-brainstorming` agent reads the
|
|
36
|
+
deposit and enriches `## Context`.
|
|
37
|
+
|
|
38
|
+
## Stage coverage
|
|
39
|
+
This is the What-stage agent in the one-agent-per-stage table (What:
|
|
40
|
+
intent-discovery, Why: brainstorming + spec-specialist, How: planner, Exec:
|
|
41
|
+
executor, Done: intent-curator).
|
|
42
|
+
|
|
43
|
+
## Boundaries
|
|
44
|
+
- Single output: `resources/discovery--<slug>.md`.
|
|
45
|
+
- Never takes the delivery lock (it runs before the lock is armed).
|
|
46
|
+
- Advisory input to Why, not a gate.
|
|
@@ -34,6 +34,14 @@ enforces it: without a held lock, mutating writes to this active intent's dir ar
|
|
|
34
34
|
1. **Ensure the intent is in INDEX `## Active`.** If it sits in `## Future`, activate it
|
|
35
35
|
(move it to `## Active`, auto-commit) before arming. Creation precedes activation, so a
|
|
36
36
|
brand-new What intent is activated here, then locked.
|
|
37
|
+
1a. **Dispatch What-stage discovery (before the lock).** Right after activation and before
|
|
38
|
+
arming the bridge, dispatch the `plastic-intent-discovery` agent (see the
|
|
39
|
+
`plastic-intent-discovery` skill). Resolve its model explicitly and pass it at dispatch
|
|
40
|
+
time (belt-and-braces): `read-config agents.models.plastic-intent-discovery --project
|
|
41
|
+
<repo>`. The agent runs QMD discovery over the intent's `chain`/`sources` and deposits
|
|
42
|
+
findings to `resources/discovery--<slug>.md` only; it never writes the intent file, so the
|
|
43
|
+
lock-owner-only rule is untouched. This is advisory context for Why, not a gate: if
|
|
44
|
+
discovery yields nothing, proceed to the lock normally.
|
|
37
45
|
2. **Self-heal the lock state first.** Run:
|
|
38
46
|
`ruby ~/.plastic/scripts/plastic-lock fix --intent-dir <STORE>/<dir>`
|
|
39
47
|
This is the one repair function (same one /plastic-lock exposes): it removes
|
package/templates/config.yml
CHANGED
|
@@ -11,3 +11,11 @@ agent:
|
|
|
11
11
|
parallel_mode: linear
|
|
12
12
|
architect:
|
|
13
13
|
style:
|
|
14
|
+
|
|
15
|
+
# Per-agent model override (intent 116). Uncomment and set to a Claude Code
|
|
16
|
+
# alias (opus, sonnet, haiku) to override the shipped tier for one agent. With
|
|
17
|
+
# no entry, the shipped default applies. Never resolves to Fable.
|
|
18
|
+
# agents:
|
|
19
|
+
# models:
|
|
20
|
+
# plastic-executor: sonnet
|
|
21
|
+
# plastic-enforcer: opus
|