Files
stanp-opencode/docs/multi-work.md
StanPonomarev d132060697
CI / verify (pull_request) Successful in 10s
feat: skills
2026-09-26 21:35:59 +02:00

10 KiB

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.

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.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:

{
    "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:

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:

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.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 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.15 server and native subagent executor:

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.

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.