2026-08-28 · Updated 2026-08-30 · 12 min read
Use OpenCode with YYLO
Keep OpenCode's configured agents and add what configuration cannot declare — readiness between tasks, quotas around fan-out, and durable evidence per unit of work — with the agent-to-task mapping plus a headless service wrapper wired through the documented extension point today.
By Juno AI INC · opencode · interoperability · yylo
If you build with OpenCode, you already work with agents you configured yourself: a Build agent with every tool enabled, a Plan agent that asks before it writes or executes anything, a review subagent defined in a markdown file next to the code it reviews. That configuration layer is genuinely good at its job — it decides how each agent behaves the moment it starts working. What it cannot decide is everything *around* the working session: which unit of work is safe to begin while another is still open, how much parallel work the repository can absorb before integration degrades, and what durable proof a finished unit carries once the session that produced it closes. What configuration cannot express, YYLO adds as its own layer. OpenCode keeps agent configuration; YYLO contributes declared readiness, quotas, and the task record that admits finished work into shared history.
The combination is one division of labor, not one product merge: the config file shapes how an agent behaves; the task ledger records what the work became. OpenCode's agents are reviewable artifacts — JSON blocks and markdown files you version, diff, and reuse across sessions. YYLO's tasks are durable records — ledger entries with status, responses, dependencies, and commits that outlive every session. The mapping between them falls out along three seams — readiness, quotas, evidence — followed by the dispatch wiring itself, with its support claim held to exactly the verification it has today.
What OpenCode already owns
Verified against OpenCode's published documentation on 2026-08-28, and none of it moves when YYLO joins the stack:
- Primary agents and subagents. "There are two types of agents in OpenCode; primary agents and subagents" — primaries are "the main assistants you interact with directly", while subagents are "specialized assistants that primary agents can invoke for specific tasks" (agents). The built-ins set the pattern: Build, "the default primary agent with all tools enabled", and Plan, "A restricted agent designed for planning and analysis", plus the General, Explore, and Scout subagents.
- Agents as configuration artifacts. Agent definitions live in
opencode.jsonunder theagentkey, or in markdown files under~/.config/opencode/agents/(global) and.opencode/agents/(per project) — and "The markdown file name becomes the agent name" (agents).opencode agent createscaffolds one interactively; passing--path,--description,--mode, and--permissionsmakes it non-interactive, so custom agents can be generated from a script. - Standing instructions. "You can provide custom instructions to opencode by creating an AGENTS.md file";
/init"scans the important files in your repo" and then "creates or updates AGENTS.md with concise project-specific guidance", and aninstructionsarray inopencode.jsonpulls in additional rule files by glob, includingpackages/*/AGENTS.mdshapes for monorepos (rules). - A permission lattice. Every permission key takes
ask,allow, ordeny, patterns are globs, and "Rules are evaluated by pattern match, with the last matching rule winning" (permissions). Per-agent overrides compose with the global config: "Agent permissions are merged with the global config, and agent rules take precedence". - Circuit breakers inside the agent. A
stepsvalue answers a cost question: "Control the maximum number of agentic iterations an agent can perform before being forced to respond with text only" — and "When the limit is reached, the agent receives a special system prompt instructing it to respond with a summarization of its work and recommended remaining tasks" (agents). A separatedoom_looppermission is "triggered when the same tool call repeats 3 times with identical input". - A non-interactive CLI. Beyond the TUI, the docs introduce
opencode runas the way to "Run opencode in non-interactive mode by passing a prompt directly", with--agent("Agent to use"),-m/--model("Model to use in the form of provider/model"), and--format jsonfor "raw JSON events" (CLI).
None of that survives the combination any less OpenCode's. The real question is not *agent quality* — it is *where the consequences of configured-agent work live* — and that boundary is drawn in full in the harness guide for any agent product.
Readiness: from description-driven fan-out to a declared order
OpenCode's subagent selection is dynamic and in-session. Subagents can be invoked "Automatically by primary agents for specialized tasks based on their descriptions", or manually through @ mentions; the General subagent exists for multi-step research and is the one the docs point at when you want "to run multiple units of work in parallel" (agents). When people ask about OpenCode "agent teams" or multi-agent setups, this composition is the real answer: one primary agent, a cast of configured subagents, and permission.task globs deciding who may call whom — "Control which subagents an agent can invoke via the Task tool", where a deny removes the subagent from the tool description entirely. It is a team assembled by configuration and chosen by description, at runtime, inside one session.
What that machinery cannot express is *order between units of work*. Descriptions say what a subagent is good at; they say nothing about which task must land before another may start. YYLO owns that as declared data — the task schema's blocked_by[] field, surfaced by the ledger:
The division of labor is clean: OpenCode's fan-out is chosen inside the session, by description; YYLO's readiness is declared before any session opens, as data every surface reads the same way. Aim parallel OpenCode sessions at tasks the ledger already calls ready, and the quota, isolation, and evidence discipline in safe parallel Kanban execution transfers as-is — no step of it cares which agent executes the work — while use multiple coding agents in one workflow generalizes the pattern across harnesses.
Quotas: bounds inside the agent, bounds around the work
OpenCode already has strong *inner* bounds, and they live in configuration. The steps option caps agentic iterations per agent; doom_loop interrupts identical repeated tool calls; permission ask walls stop dangerous operations mid-session; and --auto, which flips would-be asks into approvals, still leaves explicit deny entries enforced (permissions). Defaults are deliberately permissive on reads and stingy on surprises: .env files are denied by default, and doom_loop plus external_directory ask rather than allow.
Those are bounds on *one agent in one session*. YYLO's bounds sit around the work instead, at the invocation and admission level, where configuration files have no vote:
The -i/--max-iterations flag caps agent iterations per invocation, --on-hourly-limit decides whether provider quota exhaustion waits or exits, and the parallel runner's --parallel N caps concurrent task work with one worktree per task. OpenCode bounds the agent from inside; YYLO bounds the invocation and the fan-out from outside. Together they cover the two failure shapes configuration alone cannot see: an agent that never stops inside a session, and a repository that accepts more concurrent change than it can integrate.
Evidence: what a session keeps, what a task proves
OpenCode's records are built for continuing a session. Subagent work lands in child sessions you can navigate between; hidden system agents produce "short session titles" and "session summaries"; opencode run --format json emits raw JSON events for machine consumers; and session data has its own management commands — the --share flag, opencode session list, and opencode export for JSON data (agents, CLI). All of that is transcript-shaped truth: what was said, in which session, in what order.
YYLO's evidence is admission-shaped: what the work was, what it yielded, and where it settled. The task schema is {id, status, body, commit_hash, agent_response, created_date, last_modified, feature_tags[], related_tasks[], blocked_by[]}, and recording evidence is an explicit operation:
A transcript answers "what happened in this session?"; the ledger answers "what landed in the repository, when, and why?" — the split the task-truth guide introduces in depth, and the raw material behind auditable agent workflows. The practical split: let OpenCode's sessions carry the conversation, and let the task carry the contract — one unit of work, one recorded response, one commit, one admission decision.
Landing is where the last difference shows. A finished OpenCode session hands you a working tree, and the session layer vouches for none of what admission cares about: that the tip was committed clean, that the base was recorded, and that two agents finishing together enter the target one after the other. The YYLO task lifecycle vouches for exactly those: yy task start TASK_ID returns a dedicated worktree whose boundary the README calls "the safety boundary"; the work arrives as a clean committed tip; read-only yy task preflight TASK_ID surfaces closure defects while they are still cheap to fix; and yy task finish TASK_ID hands the tip to a serialized merge, so simultaneous finishes integrate in order rather than colliding on the target branch.
Wire the OpenCode CLI into YYLO's dispatch contract
The dispatch seam, and the answer it now carries with a date. Five services make up YYLO's documented dispatch surface — claude, codex, gemini, pi, and cursor — per the -s/--subagent table and its "Switch between Claude, Codex, Gemini, Pi, or Cursor with one flag" sentence in the README (YYLO documentation). A first-party opencode service is absent from released product truth — verified, not assumed: checklist item SEO-091 closed on 2026-08-29 by inspecting what npm actually distributes. The tarballs behind latest (@yylo/cli 0.2.0) plus the next build (0.2.1-rc.1) were unpacked and read end to end, and opencode never appears in either: not as a word in any file, not among the five service names the dispatcher validates, and not as a script in the shipped templates. The waiting is over in the concrete sense that there is nothing left to wait for: first-party OpenCode dispatch does not exist, and the extension point below is the path — it stays the path for as long as no release ships the service, and any release that does re-opens the question through a fresh verification pass.
The documented extension point is what works today, because YYLO defines a service by contract rather than by a fixed list: "Service scripts live in ~/.yylo/services/. Each is a Python script that accepts standard args (-p/--prompt, -m/--model, -v/--verbose) and outputs JSON events to stdout" (YYLO documentation). The OpenCode CLI supplies the other half — opencode run takes a prompt directly, selects a configured agent with --agent, and unlike some agents documents its own -m/--model flag, so the wrapper can forward every argument the service contract passes it:
Drop it at ~/.yylo/services/opencode.py; dispatch then resolves the service by name, bounds every invocation, and records evidence for it exactly as it does for any built-in service:
Two honest footnotes. The wrapper is yours alone — it sits in the user-services directory, yylo services status reports what YYLO can see of it, and with the first-party surface verified gone, the extension seam is what the product actually supports, not a detour. And it forwards final output only, the minimum the service contract asks for; --format json exists for richer per-step events, and adapting the wrapper to stream them is your call. For repeated dispatches you can also keep opencode serve alive and pass --attach — the docs' stated motivation is "to avoid MCP server cold boot times on every run" (CLI). If a later release adds first-party opencode dispatch, this section will shrink to a single flag — and the word that it shipped comes from a fresh gate run against that release's artifacts, not from an edit here.
Instructions, permissions, and what each layer should own
OpenCode gives you two standing layers — agent configuration and AGENTS.md instructions — and both should stay standing. Your agent files and permission lattice describe how any session behaves in this repository: which subagents exist, who may invoke whom, what edit and bash may touch. Your AGENTS.md carries the conventions a human reviewer would: build and test commands, structure, gotchas. The YYLO task carries the other half of the pair: the intent behind this one task, what it yielded, and where it settled. Standing layers configure agents; the task records work; each layer keeps its own facts and stops there.
The composition is also where caution belongs. A permissive bash permission, a prompt pipeline, and a dispatching control plane stack three shell-executing surfaces on one another, so before any of them may do something irreversible, apply the boundaries in prompt and shell-context safety — every one of them holds with OpenCode underneath. And if the real motive for combining products is lock-in worry rather than workload, start instead from the portability audit: harness switching is a one-flag operation in YYLO (harness switching), and the same separability that keeps switching cheap is what makes the combination safe to try. The Cursor and Kiro sibling guides walk the same composition for those agents.
Prove it with one bounded task
The smallest honest test of the division of labor is one unit of work small enough that nothing rides on it. Install YYLO, register the outcome as one task, then hand the boundary to a configured OpenCode agent:
The first invocation above names a documented service; sending the same task to your opencode wrapper travels the extension point — with the first-party surface verified absent, the wrapper is the route itself, not a placeholder. Hold the first attempt to the bounded-loop guide's standard — one outcome you can verify, checks focused on the surface you touched — and the combination settles: OpenCode configuring and driving agents inside the task, YYLO owning the task's identity, its dependencies, its fan-out allowance, and its landing. Each OpenCode statement above was checked against opencode.ai/docs on 2026-08-28, and each YYLO statement against YYLO's committed README and code, with the dispatch surface additionally checked against the released artifacts (2026-08-29). Both products keep moving; re-verify after either changes, and count the dispatch wiring as extension-only until a fresh gate run rules otherwise.