orchestrator-workflow 0.21.0 → 0.22.0
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/CHANGELOG.md +42 -0
- package/INSTALL-AGENT.md +24 -7
- package/README.md +29 -2
- package/assets/agents-md-section.md +5 -0
- package/assets/skill/SKILL.md +7 -4
- package/dist/init.js +43 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,48 @@ All notable changes to `orchestrator-workflow` are documented here.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.22.0] - 2026-08-20
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **Default subagent spawns no longer inherit the orchestrator session's
|
|
13
|
+
effort.** Every unsuffixed default agent file (`explorer.md`,
|
|
14
|
+
`task-slicer.md`, `implementer.md`, `reviewer.md`, `advisor.md`) now
|
|
15
|
+
carries its own pinned default effort, unconditionally, regardless of
|
|
16
|
+
whether `--tiers` is on: `effort: medium` for explorer, task-slicer, and
|
|
17
|
+
implementer, `effort: high` for reviewer and advisor
|
|
18
|
+
(`TIER_DEFS[DEFAULT_TIER[role]].effort`, the same tier data `--tiers`
|
|
19
|
+
already used, applied by `composeClaudeAgent` for every install, tiers
|
|
20
|
+
flag or not). opencode gets the matching pinned line via
|
|
21
|
+
`opencodeEffortLine` (renamed from `opencodeVariantEffortLine`, now shared
|
|
22
|
+
by the default file and the tier variants): a resolved Claude-family model
|
|
23
|
+
gets `variant: high` for reviewer/advisor and no effort field at all for
|
|
24
|
+
the three medium-default roles (opencode's `variant:` option does not
|
|
25
|
+
distinguish an effort below `high`, the same collapse tier variants
|
|
26
|
+
already documented), a non-Claude-family provider-qualified model gets
|
|
27
|
+
`reasoningEffort: medium`/`reasoningEffort: high`, and Ollama, a
|
|
28
|
+
provider-less id, or an unresolved model gets no effort field either way.
|
|
29
|
+
Practically: on a high-effort orchestrator session, a default subagent
|
|
30
|
+
spawn used to silently run at that same high effort; it now runs at its
|
|
31
|
+
own role's pinned effort instead, which is weaker (and cheaper) for the
|
|
32
|
+
three medium-default roles. Escalate deliberately via the `-high`/`-xhigh`
|
|
33
|
+
tier variants (`--tiers`) when a task actually needs more.
|
|
34
|
+
**`CLAUDE_CODE_EFFORT_LEVEL` still beats this pin**: when the harness
|
|
35
|
+
environment sets that variable, it overrides every installed agent's
|
|
36
|
+
frontmatter `effort:`, default files and tier variants alike, the same
|
|
37
|
+
warning `--tiers` already carried. **opencode cannot express `medium` for
|
|
38
|
+
a Claude-family model at all**: the `variant:` field only distinguishes
|
|
39
|
+
`high`/`max`, so a Claude-family default file for explorer, task-slicer,
|
|
40
|
+
or implementer renders with no effort field, falling back to whatever the
|
|
41
|
+
resolved model's own default happens to be.
|
|
42
|
+
The default file's content stays byte-identical whether or not `--tiers`
|
|
43
|
+
is also on, since the pin does not read the `tiers` flag; this invariant
|
|
44
|
+
is now belt-and-suspenders tested directly (a two-target diff, not just
|
|
45
|
+
inferred from reading the source).
|
|
46
|
+
A `--tiers`-off install (the default) renders no variant files at all, so
|
|
47
|
+
it has no in-install escalation path off a default's pinned effort; pull
|
|
48
|
+
`init --tiers` afterward if a task needs one.
|
|
49
|
+
|
|
8
50
|
## [0.21.0] - 2026-08-20
|
|
9
51
|
|
|
10
52
|
### Added
|
package/INSTALL-AGENT.md
CHANGED
|
@@ -146,10 +146,15 @@ steps in the repository you were asked to install into.
|
|
|
146
146
|
for `full`; only `implementer` and `reviewer` for `minimal`),
|
|
147
147
|
`.claude/agents/<role>.md` from
|
|
148
148
|
`assets/agents/<role>.md` with `model: <operator's choice>` added as a
|
|
149
|
-
new line directly after the `description:` line
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
new line directly after the `description:` line, then
|
|
150
|
+
`effort: <medium|high>` on the next line (`medium` for explorer,
|
|
151
|
+
task-slicer, and implementer; `high` for reviewer and advisor; this
|
|
152
|
+
pinned default effort is unconditional, not tied to whether the
|
|
153
|
+
operator asked for `--tiers`; see the package README's "Effort tiers"
|
|
154
|
+
section), that placement matching the installer's output byte for
|
|
155
|
+
byte. For the explorer, reviewer, and advisor roles additionally,
|
|
156
|
+
`disallowedTools: Edit, Write, NotebookEdit` goes on a new line
|
|
157
|
+
directly after the `effort:` line. Ensure `CLAUDE.md` exists and
|
|
153
158
|
contains a line `@AGENTS.md`.
|
|
154
159
|
- Codex: `.agents/skills/orchestrator-workflow/SKILL.md`, same skill file.
|
|
155
160
|
- opencode: `.opencode/skills/orchestrator-workflow/SKILL.md` from
|
|
@@ -166,9 +171,21 @@ steps in the repository you were asked to install into.
|
|
|
166
171
|
which is the safe portable fallback. The installed CLI resolves aliases
|
|
167
172
|
to fully-qualified ids by running `opencode models` at install time; in a
|
|
168
173
|
manual install you may not have a live catalog, so omitting `model:` is
|
|
169
|
-
correct.
|
|
170
|
-
line
|
|
171
|
-
|
|
174
|
+
correct. When you do have a fully-qualified `model:` value, add the same
|
|
175
|
+
pinned-default-effort line (see the package README's "Effort tiers"
|
|
176
|
+
section for the exact dispatch rule), keyed by
|
|
177
|
+
the role's own default tier instead of a suffix tier (`medium` for
|
|
178
|
+
explorer/task-slicer/implementer, `high` for reviewer/advisor): a
|
|
179
|
+
resolved Claude-family model gets `variant: high` for reviewer/advisor
|
|
180
|
+
and no effort line at all for the three medium-default roles, a
|
|
181
|
+
non-Claude-family provider-qualified model gets `reasoningEffort:
|
|
182
|
+
medium` or `reasoningEffort: high`, and Ollama or a provider-less id
|
|
183
|
+
gets no effort line either way; when `model:` is omitted (the common
|
|
184
|
+
manual-fallback case above), omit the effort line too, the same
|
|
185
|
+
no-live-catalog fallback. For the explorer, reviewer, and advisor roles
|
|
186
|
+
additionally, `permission:` goes on a new line directly after
|
|
187
|
+
`mode: subagent` (or after `model:`/the effort line when present),
|
|
188
|
+
followed by ` edit: deny` (two-space indent) on the next line.
|
|
172
189
|
Example read-only role frontmatter (explorer, reviewer, or advisor) when
|
|
173
190
|
no model is resolved:
|
|
174
191
|
```yaml
|
package/README.md
CHANGED
|
@@ -215,8 +215,27 @@ non-default effort tier, alongside the one default (unsuffixed) agent file
|
|
|
215
215
|
`--profile` already installs. Each tier variant is a standalone subagent
|
|
216
216
|
definition, not a modification of the default file: the default file
|
|
217
217
|
(`<role>.md`) stays byte-identical to what a tiers-off install already
|
|
218
|
-
produces
|
|
219
|
-
|
|
218
|
+
produces, and each variant lives next to it as `<role>-<tier>.md`.
|
|
219
|
+
|
|
220
|
+
**Every default file carries its own pinned effort, independent of
|
|
221
|
+
`--tiers`.** Since 0.22.0, `composeClaudeAgent`/`composeOpencodeAgent` add
|
|
222
|
+
the role's own `TIER_DEFS[DEFAULT_TIER[role]].effort` to the default
|
|
223
|
+
(unsuffixed) file unconditionally: `effort: medium` for explorer,
|
|
224
|
+
task-slicer, and implementer; `effort: high` for reviewer and advisor
|
|
225
|
+
(opencode: a `variant: high` line when the resolved model is Claude-family,
|
|
226
|
+
following the same dispatch rule tier variants use, `reasoningEffort:
|
|
227
|
+
medium`/`reasoningEffort: high` for a non-Claude-family provider-qualified
|
|
228
|
+
model, nothing for Ollama, a provider-less id, or an unresolved model). This
|
|
229
|
+
pin does not depend on `tiers`, so a plain install (no `--tiers`) already
|
|
230
|
+
carries it; the flag only controls whether the additional `<role>-<tier>.md`
|
|
231
|
+
variant files are also rendered. The motivation: a default spawn used to
|
|
232
|
+
silently inherit the orchestrator session's own effort, so a `high`-effort
|
|
233
|
+
orchestrator session made every default subagent spawn at `high` too,
|
|
234
|
+
regardless of the role's own intended weight; the pin makes each role's
|
|
235
|
+
effort deterministic and independent of the caller's session. A `--tiers`-off
|
|
236
|
+
install (the default) has no variant files and therefore no in-install
|
|
237
|
+
escalation path off a default's pinned effort; run `init --tiers` afterward
|
|
238
|
+
if a task ever needs one.
|
|
220
239
|
|
|
221
240
|
Default off, like every optional pack in this kit: a fresh install renders
|
|
222
241
|
no variant files unless asked. `--tiers` turns the feature on for that run,
|
|
@@ -307,6 +326,14 @@ agent, tier variants and default files alike, not just the one this feature
|
|
|
307
326
|
adds. Check for it before relying on a specific tier variant's requested
|
|
308
327
|
effort actually taking effect.
|
|
309
328
|
|
|
329
|
+
The pin is also emitted unconditionally regardless of which model the role
|
|
330
|
+
resolves to via `--models`, including a model with no effort support at all
|
|
331
|
+
(e.g. `--models reviewer=haiku` still renders `model: haiku` followed by
|
|
332
|
+
`effort: high`). A wire probe on 2026-08-19 (not re-measured for this doc)
|
|
333
|
+
showed the Claude Code CLI silently drops the `effort:` parameter for Haiku
|
|
334
|
+
4.5 rather than rejecting it: the value is ignored, not an install-time or
|
|
335
|
+
run-time error.
|
|
336
|
+
|
|
310
337
|
## Ownership and re-runs
|
|
311
338
|
|
|
312
339
|
`init` is idempotent: a second run changes nothing. The rules:
|
|
@@ -60,6 +60,11 @@ default, not a ritual.
|
|
|
60
60
|
downshift at all: its default `high` is already its only non-`-xhigh`
|
|
61
61
|
tier. Spawn only variants that are actually installed. Tier choice is a
|
|
62
62
|
conscious decision, not a ritual; when unsure, use the default.
|
|
63
|
+
- Every unsuffixed default subagent carries its own pinned default effort
|
|
64
|
+
baked into its own file, not inherited from the orchestrator session:
|
|
65
|
+
medium for the explorer, the task-slicer, and the implementer; high for
|
|
66
|
+
the reviewer and the advisor. This holds whether or not tier variants are
|
|
67
|
+
installed; it is not gated on `--tiers`.
|
|
63
68
|
- Under the `full` profile, an advisor subagent is available for escalation
|
|
64
69
|
only: architectural uncertainty, requirements that contradict each other,
|
|
65
70
|
multiple valid solution paths where committing to one is expensive to
|
package/assets/skill/SKILL.md
CHANGED
|
@@ -134,10 +134,13 @@ directory and the subagents.
|
|
|
134
134
|
enough, testable, ordered correctly, and aligned with the goal. Fix the
|
|
135
135
|
slicing before any implementation starts.
|
|
136
136
|
6. **Delegate implementation.** Send each implementer subagent one narrow task
|
|
137
|
-
contract (format below).
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
137
|
+
contract (format below). The unsuffixed implementer carries a pinned
|
|
138
|
+
effort: `medium` in its own file, whether or not tier variants are
|
|
139
|
+
installed, so a default spawn no longer inherits the session's effort.
|
|
140
|
+
When tier variants are installed, pick the implementer tier (the
|
|
141
|
+
installed `implementer-<tier>` subagents, if any) by the task's
|
|
142
|
+
complexity and risk, at your own judgment, defaulting to the unsuffixed
|
|
143
|
+
subagent when unsure; record a non-default tier choice with a
|
|
141
144
|
one-line reason in `03-decisions.md` when the task is non-trivial. When a
|
|
142
145
|
task's acceptance rests on a test that must fail without the change, name
|
|
143
146
|
the mutation probes to run in the task assignment; the implementer reports
|
package/dist/init.js
CHANGED
|
@@ -95,6 +95,22 @@ export function readInstalledManifest(targetDir) {
|
|
|
95
95
|
function yamlQuote(value) {
|
|
96
96
|
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
97
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Composes the unsuffixed default agent file. It carries a pinned
|
|
100
|
+
* `effort: <TIER_DEFS[DEFAULT_TIER[role]].effort>` line unconditionally
|
|
101
|
+
* (medium for explorer/task-slicer/implementer, high for reviewer/advisor),
|
|
102
|
+
* regardless of whether `--tiers` is on: this is the deterministic tier
|
|
103
|
+
* ladder's floor, not a tier-variant feature, so a default spawn no longer
|
|
104
|
+
* silently inherits the orchestrator session's effort. Since the pin does
|
|
105
|
+
* not depend on the `tiers` flag, the default file's content still stays
|
|
106
|
+
* byte-identical whether or not tier variants are also rendered, the same
|
|
107
|
+
* invariant `composeClaudeAgentVariant`'s own doc comment below describes.
|
|
108
|
+
* Computed inline here rather than passed in like `composeOpencodeAgent`'s
|
|
109
|
+
* `effortLine`: `TIER_DEFS[DEFAULT_TIER[role]].effort` is a pure function of
|
|
110
|
+
* `role` alone, with no model-dependent dispatch on Claude Code the way
|
|
111
|
+
* opencode's family-based `opencodeEffortLine` has, so there is no second,
|
|
112
|
+
* potentially-diverging computation here to guard against.
|
|
113
|
+
*/
|
|
98
114
|
function composeClaudeAgent(role, model) {
|
|
99
115
|
const asset = readAgentAsset(role);
|
|
100
116
|
const frontmatter = [
|
|
@@ -102,6 +118,7 @@ function composeClaudeAgent(role, model) {
|
|
|
102
118
|
`name: ${asset.name}`,
|
|
103
119
|
`description: ${yamlQuote(asset.description)}`,
|
|
104
120
|
`model: ${claudeModelValue(model)}`,
|
|
121
|
+
`effort: ${TIER_DEFS[DEFAULT_TIER[role]].effort}`,
|
|
105
122
|
];
|
|
106
123
|
// Read-only roles keep every read/search tool but cannot mutate files.
|
|
107
124
|
if (READ_ONLY_ROLES.has(role)) {
|
|
@@ -110,7 +127,15 @@ function composeClaudeAgent(role, model) {
|
|
|
110
127
|
frontmatter.push("---");
|
|
111
128
|
return [...frontmatter, "", asset.body.trimEnd(), ""].join("\n");
|
|
112
129
|
}
|
|
113
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Composes the unsuffixed default opencode agent file. `effortLine` is the
|
|
132
|
+
* same pinned-default-effort line a tier variant would carry, decided once
|
|
133
|
+
* by the caller via `opencodeEffortLine(DEFAULT_TIER[role], modelValue)`
|
|
134
|
+
* (single source of truth, the same pattern `composeOpencodeAgentVariant`
|
|
135
|
+
* already uses for its own effort line) and passed in rather than
|
|
136
|
+
* recomputed here.
|
|
137
|
+
*/
|
|
138
|
+
function composeOpencodeAgent(role, modelValue, effortLine) {
|
|
114
139
|
const asset = readAgentAsset(role);
|
|
115
140
|
const frontmatter = [
|
|
116
141
|
"---",
|
|
@@ -122,6 +147,9 @@ function composeOpencodeAgent(role, modelValue) {
|
|
|
122
147
|
if (modelValue) {
|
|
123
148
|
frontmatter.push(`model: ${modelValue}`);
|
|
124
149
|
}
|
|
150
|
+
if (effortLine) {
|
|
151
|
+
frontmatter.push(effortLine);
|
|
152
|
+
}
|
|
125
153
|
if (READ_ONLY_ROLES.has(role)) {
|
|
126
154
|
frontmatter.push("permission:", " edit: deny");
|
|
127
155
|
}
|
|
@@ -134,8 +162,8 @@ function tierDescriptionSuffix(asset, tier) {
|
|
|
134
162
|
/**
|
|
135
163
|
* Composes a tier-variant sibling of `composeClaudeAgent` (`<role>-<tier>.md`).
|
|
136
164
|
* The default-tier file is never rendered here (callers skip it via
|
|
137
|
-
* `DEFAULT_TIER`), so `composeClaudeAgent`'s own output
|
|
138
|
-
* whether or not tiers are on.
|
|
165
|
+
* `DEFAULT_TIER`), so `composeClaudeAgent`'s own output (pinned default
|
|
166
|
+
* effort included) stays byte-identical whether or not tiers are on.
|
|
139
167
|
*/
|
|
140
168
|
function composeClaudeAgentVariant(role, tier) {
|
|
141
169
|
const asset = readAgentAsset(role);
|
|
@@ -177,8 +205,12 @@ function isClaudeFamilyModel(modelValue) {
|
|
|
177
205
|
* effort passthrough, and every other model accepts a plain
|
|
178
206
|
* `reasoningEffort:` value. An unresolved (`undefined`) model gets no
|
|
179
207
|
* effort field either, since there is then no model to key the decision on.
|
|
208
|
+
* Shared by both the default (unsuffixed) agent file, keyed by the role's
|
|
209
|
+
* own `DEFAULT_TIER`, and the tier-variant files, keyed by the variant's own
|
|
210
|
+
* suffix tier: the dispatch rule is identical either way, only which tier
|
|
211
|
+
* gets passed in differs.
|
|
180
212
|
*/
|
|
181
|
-
function
|
|
213
|
+
function opencodeEffortLine(tier, modelValue) {
|
|
182
214
|
if (!modelValue)
|
|
183
215
|
return undefined;
|
|
184
216
|
if (isClaudeFamilyModel(modelValue)) {
|
|
@@ -197,7 +229,7 @@ function opencodeVariantEffortLine(tier, modelValue) {
|
|
|
197
229
|
/**
|
|
198
230
|
* Composes a tier-variant sibling of `composeOpencodeAgent`. `effortLine` is
|
|
199
231
|
* decided once, at the single call site in the opencode tier loop of
|
|
200
|
-
* `runInit` (via `
|
|
232
|
+
* `runInit` (via `opencodeEffortLine`), and passed in rather than
|
|
201
233
|
* recomputed here, so there is exactly one place that decides it instead
|
|
202
234
|
* of a second, independent source of truth for the same value.
|
|
203
235
|
*/
|
|
@@ -356,7 +388,8 @@ export function runInit(options) {
|
|
|
356
388
|
const modelValue = options.opencodeModels !== undefined
|
|
357
389
|
? options.opencodeModels[role]
|
|
358
390
|
: opencodeModelValue(options.models[role]);
|
|
359
|
-
|
|
391
|
+
const defaultEffortLine = opencodeEffortLine(DEFAULT_TIER[role], modelValue);
|
|
392
|
+
installKitFile(join(".opencode", "agents", `${role}.md`), composeOpencodeAgent(role, modelValue, defaultEffortLine));
|
|
360
393
|
if (tiers) {
|
|
361
394
|
for (const tier of ROLE_TIERS[role]) {
|
|
362
395
|
if (tier === DEFAULT_TIER[role])
|
|
@@ -364,8 +397,8 @@ export function runInit(options) {
|
|
|
364
397
|
const modelClass = TIER_DEFS[tier].modelClass;
|
|
365
398
|
const variantModelValue = options.opencodeClassModels?.[modelClass];
|
|
366
399
|
if (variantModelValue === undefined) {
|
|
367
|
-
// No model resolved for this class:
|
|
368
|
-
//
|
|
400
|
+
// No model resolved for this class: opencodeEffortLine always
|
|
401
|
+
// returns undefined too when its modelValue argument is
|
|
369
402
|
// undefined (it short-circuits on that first), so this variant
|
|
370
403
|
// would carry neither a model: nor an effort line, a silent
|
|
371
404
|
// no-op duplicate of the base file's own (possibly also
|
|
@@ -375,10 +408,10 @@ export function runInit(options) {
|
|
|
375
408
|
// (e.g. a low/medium tier on a Claude-family model, or any
|
|
376
409
|
// Ollama model) is NOT skipped by this check: it still renders
|
|
377
410
|
// with just its model: line, see the effort-field dispatch
|
|
378
|
-
// rules in
|
|
411
|
+
// rules in opencodeEffortLine above.
|
|
379
412
|
continue;
|
|
380
413
|
}
|
|
381
|
-
const effortLine =
|
|
414
|
+
const effortLine = opencodeEffortLine(tier, variantModelValue);
|
|
382
415
|
installKitFile(join(".opencode", "agents", `${role}-${tier}.md`), composeOpencodeAgentVariant(role, tier, variantModelValue, effortLine));
|
|
383
416
|
}
|
|
384
417
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "orchestrator-workflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Installer for an orchestrator-led agent workflow: .ai/ run state, an AGENTS.md policy section, and per-harness subagent definitions for Claude Code, OpenAI Codex, and opencode",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|