209 lines
11 KiB
Markdown
209 lines
11 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 or either custom deep assignment is omitted. 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
|
|
|
|
Load **Agents before Multi-work**, at both root and destination locations. Multi-work fails closed without the native Agents RPC registration; there is no shared module-state registry. Its own storage identity is `stanp-opencode.multi-work`.
|
|
|
|
Upgrading from the old `stanp-opencode` monolith is a clean break: existing bindings cannot resume, and quota tracking resets. Start new delegated sessions. Existing worktrees, workspaces, and old host storage remain untouched. New bindings persist normally under the new identity.
|
|
|
|
Use OpenCode **2.0.15**, the version this integration targets. The package
|
|
retains Effect `4.0.0-rc.112` because OpenCode 2.0.15's client requires that
|
|
exact peer version. 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 Agents' **effective build-permission
|
|
snapshot**, including configuration applied after plugin transforms. Its existing
|
|
`agent.updated` listener refreshes that snapshot. Multi-work reads it through the native Agents RPC and replays 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.15 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
|
|
load Agents through the real Promise adapter followed by Multi-work, 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.15 server and native
|
|
subagent executor**:
|
|
|
|
```sh
|
|
OPENCODE_2015=/absolute/path/to/2.0.15/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.15`), 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.
|
|
- Manual configurations with missing or later-loaded Agents fail Multi-work activation.
|
|
- Quota alone activates without Agents or Multi-work, and its stable RPC returns null without credentials.
|
|
|
|
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.
|