Files
2026-09-18 20:13:54 +02:00

203 lines
10 KiB
Markdown

# Multi-work
`multi-work` is a **primary-only** agent for coordinating independent work in
the current Herdr root checkout or new Herdr-managed Git worktrees. Like
`coordinate`, it uses the configured `deep-lo` model and effort, falling back
to `good-lo` when `deep-lo` is unavailable. No extra custom model assignment is
required.
```text
multi-work (root checkout)
├── fast-lo (local retrieval)
├── coordinate (current root checkout)
└── coordinate (new Herdr worktree)
└── existing leaf workers (that worktree)
```
## Availability
The agent appears when the plugin can verify a live, unambiguous Herdr root
workspace for the current **checkout root directory**, and coordinate/fast-lo are
available. Herdr and Git must be executable by the OpenCode server. The CLI uses
that server process's Herdr socket/session configuration; it never targets the
UI-focused workspace.
Eligibility is location-based: all OpenCode clients viewing the eligible location
can see the agent. This does not identify the client's pane. Linked worktrees,
subdirectories, closed workspaces, duplicate workspace ownership, unavailable CLI,
and failed discovery do not qualify. Missing workspace metadata is resolved using
Herdr's worktree inventory rather than assuming a Git root is a Herdr root.
The registry refreshes every 30 seconds. Every multi-work model turn and delegation
rechecks the executing session's location; creation revalidates the root again
immediately before its Git/Herdr operations. Stale picker visibility cannot authorize
creation. Creating/opening the root workspace remains a user action.
## Configuration
Use OpenCode **2.0.4**, the version this integration targets. At both the root and
destination locations, configure:
```jsonc
{
"experimental": { "subagent_depth": 2 },
}
```
The plugin does not modify your global configuration. Native OpenCode still
enforces nesting depth; its default of 1 is insufficient for coordinate's workers.
The public plugin context does not expose a configuration reader to preflight
the effective depth.
Each destination must load the multi-work-enabled plugin and the required worker
models. A global plugin installation/configuration is useful when source branches
have different project configuration. The tool checks the destination's live agent
registry for the coordinate protocol marker and required worker agents before
prompting. This checks feature availability, not the trustworthiness of other
plugins or project configuration.
## Delegation
Multi-work retains the native tool name, `subagent`. For work in the current root
checkout, omit `worktree`:
```js
subagent({
agent: "coordinate",
description: "Implement local change",
prompt: "Goal, owned files, constraints, and acceptance checks...",
background: true,
});
```
The child is bound to the verified root workspace before its prompt is admitted.
No Herdr workspace is created and neither the child nor parent is moved. Root-local
children share a checkout, so parallel assignments must have disjoint file ownership.
Their placement metadata uses `branch: "root"` to identify the shared root checkout;
it is not a claim about the root's current Git branch.
Use a worktree when edits may overlap or require branch isolation:
```js
subagent({
agent: "coordinate",
description: "Implement API change",
prompt: "Goal, scope, constraints, and acceptance checks...",
worktree: {
base: "main",
branch: "fix/login-timeout",
label: "Fix login timeout",
},
background: true,
});
```
`base` identifies a locally available branch or remote-tracking branch. Optional
`branch` chooses the exact new Git branch and optional `label` sets the Herdr workspace
display label through `herdr worktree create --label`. Both must be nonempty after
trimming. Prefer concise, descriptive human-readable names. Existing branch validation
and collision checks apply, and the tool never overwrites a branch. When omitted, the
tool retains the previous behavior: a unique `multi-work/<uuid>` branch and Herdr's
default workspace label. Naming fields are creation-only; resumes accept only `sessionID`.
The tool
resolves the base commit and creates the branch with Herdr.
It does not fetch refs or copy uncommitted root changes. Herdr determines the
checkout path; the tool parses and verifies the returned checkout/workspace.
Creation explicitly preserves focus with `--no-focus`.
For focused retrieval, use native `subagent` with `agent: "fast-lo"` and no
`worktree`. A new coordinate call without `worktree` means root-local work. Resume
an owned coordinate child with its `sessionID` and **omit**
`worktree`. Resumes verify parent, agent, assigned checkout, and live Herdr ownership;
worktree resumes also verify the branch.
Bound coordinate children cannot be repurposed through native delegation.
Neither multi-work nor coordinate has general shell/edit permissions. Multi-work
also rejects non-reading/non-delegation tools at execution, including Code Mode,
even if a session permission override would expose them. Creating or resuming
worktree-backed delegation requires effective `herdr_worktree: allow`, evaluated
against the canonical root directory using ordered agent and session rules. `ask`
fails explicitly because the public plugin API cannot request custom-tool approval.
Native subagent permissions are still asserted by OpenCode before preparation
starts. Root-local delegation performs no Herdr creation and therefore does not
require `herdr_worktree`; worker edit/shell permissions remain inherited and
enforced normally.
Worktree permissions inherit the base plugin's **effective build-permission
snapshot**, including configuration applied after plugin transforms. Its existing
`agent.updated` listener refreshes that snapshot and replays the registry when it
changes. Later `multi-work` agent rules and session rules retain their precedence;
inheritance does not turn a build deny into an unconditional execution-time veto
against an explicitly configured later allow.
## Native lifecycle and placement
The plugin composes the original **Effect executor** in place, preserving the
`subagent` tool identity, native child ancestry, progress/result metadata,
foreground results, background job handling, and completion notifications. It does
not create substitute top-level sessions or a separate job scheduler.
OpenCode 2.0.4 awaits a child-ID progress callback after child creation and before
prompting. The wrapper uses that boundary to create the worktree, move the explicit
child ID, and confirm its actual session location before allowing the task prompt.
A move-request acknowledgement alone is insufficient. Confirmation is bounded to
30 seconds and remains interruptible. The parent session does not move.
Coordinate is child-capable only through an owned, ready multi-work binding. Prompt
admission and model-context guards reject unbound or relocated coordinate children.
Multi-work cannot be a child, and the existing workers remain leaves.
Normal delegation cards and child navigation recognize the retained `subagent`
name. Children remain in the session family after moving; they do not become
top-level entries in root-session pickers. Moving a session does not attach an
OpenCode TUI to the new Herdr pane.
## Failures and verification limits
The plugin records the attempted child/branch and the returned worktree binding,
and reports progress IDs during preparation. Failed or interrupted initialization
does not admit the task prompt. It retains resources rather than deleting checkouts
or closing workspace groups. Inspect reported IDs and Herdr inventory before
retrying an ambiguous creation failure; CLI interruption cannot roll back a request
already accepted by Herdr. Unready children are not resumable as completed setups.
The ordinary suite uses isolated Git repositories and simulated Herdr responses.
It covers gating, source refs, ordering, failures, and interruption. Composite tests
run the exported plugin through the real Promise adapter, apply configuration after
both plugin transforms, replay twice, and test separate location registries sharing
disk-backed bindings across plugin scope restarts. Their executor is simulated.
An opt-in integration check runs the **real OpenCode 2.0.4 server and native
subagent executor**:
```sh
OPENCODE_204=/absolute/path/to/2.0.4/opencode bun scripts/test-multi-work-host.ts
```
It requires the exact-version binary (for Linux x64, published as
`@opencode/cli-linux-x64@2.0.4`), uses fresh HOME/XDG/config/database paths under
`/tmp/opencode`, and starts only loopback services. Herdr is a fake CLI performing
real Git worktree operations in the fixture repository; the model is a deterministic
HTTP endpoint. Fixture resources and logs are retained at the printed path.
Verified with this host check:
- Late configured build deny and a subsequent session allow.
- Native child creation/ancestry, confirmed move before first prompt, and foreground result.
- Separate root/destination plugin instances reading the host's persistent binding store.
- Resuming that child after a complete host restart, then native background completion
and its synthetic notification to the parent.
- Interrupting a foreground RPC while the child awaits its model response causes
the native executor to interrupt the child; the parent remains at the root.
The fixture RPC invokes the actual wrapped executor; it does not exercise the
parent model's tool-call dispatch or rendered tool cards. Recovery of an **in-flight**
job across a crash, coordinate-to-leaf nesting, background cancellation, live Herdr
focus/pane behavior, and TUI/web/mini navigation remain unverified end-to-end. A
completed child resumed after restart is not evidence of in-flight job recovery.
The progress boundary is version-sensitive, not a documented initialization hook.
Before upgrading OpenCode, verify native initialization order, foreground/background
interruption, notifications/recovery, and TUI/web/mini navigation after refresh.
Other authenticated clients/plugins are trusted: these guards are not an API-wide
sandbox, and cwd placement is not filesystem isolation for shell-capable workers.