Files
slopus--happy/docs/competition/opencode/message-protocol.md
T
wehub-resource-sync 98e40dac97
CLI Smoke Test / smoke-test-linux (20) (push) Has been cancelled
CLI Smoke Test / smoke-test-linux (24) (push) Has been cancelled
CLI Smoke Test / smoke-test-windows (20) (push) Has been cancelled
CLI Smoke Test / smoke-test-windows (24) (push) Has been cancelled
Expo App TypeScript typecheck / typecheck (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:40:49 +08:00

6.2 KiB

OpenCode Message Protocol

Bottom line

OpenCode has the cleanest transcript shape of the three systems reviewed so far. If Happy wants a strong protocol reference for app + server + session UI, this is the one to steal from first.

Core transcript model

The key design is: message envelope first, typed parts second.

  • messages are stable top-level records with IDs, session linkage, model/provider metadata, path, token usage, cost, and error state
  • content is not a single blob; it is an ordered list of typed parts
  • important part kinds include text, reasoning, tool, file, snapshot, patch, agent, subtask, step-start, step-finish, and compaction
  • this makes streaming, partial updates, replay, and debug rendering much cleaner than mutating one giant assistant string

Primary source files:

  • ../happy-adjacent/research/opencode/packages/opencode/src/session/message-v2.ts
  • ../happy-adjacent/research/opencode/packages/sdk/js/src/v2/gen/types.gen.ts

Live event model

OpenCode separates full transcript state from incremental transport events.

  • canonical live events include message.updated, message.part.updated, message.part.delta, message.part.removed, message.removed, session.status, todo.updated, and permission.asked
  • message.part.delta is the streaming primitive for appending text into a named field
  • later message.part.updated events can replace or supersede earlier deltas
  • the UI reducer explicitly merges stream events into cached transcript state

This is a very good pattern for Happy: use events for freshness, not as the only source of truth.

Primary source files:

  • ../happy-adjacent/research/opencode/packages/opencode/src/session/index.ts
  • ../happy-adjacent/research/opencode/packages/app/src/context/global-sync/event-reducer.ts

Subagents and task delegation

OpenCode models delegation as child sessions, not inline mystery behavior.

  • the task tool chooses a non-primary agent and creates or resumes a child session
  • task_id is really the child session ID, so delegation is resumable
  • subagent intent is visible in the parent transcript as a tool call and related subtask part
  • tool permissions for subagents are intentionally constrained

This is much closer to what Happy should want than flattening delegated work into one chat thread without identity.

Primary source files:

  • ../happy-adjacent/research/opencode/packages/opencode/src/tool/task.ts
  • ../happy-adjacent/research/opencode/packages/opencode/src/agent/agent.ts

Task tracking / todos

Todos are a first-class session store.

  • todo state is separate from transcript parts
  • write behavior is whole-list replacement with ordered rows
  • schema is intentionally tiny: content, status, priority
  • UI gets a proper todo dock instead of scraping plans from text

This is a strong design signal for Happy: todos should be their own state channel.

Primary source files:

  • ../happy-adjacent/research/opencode/packages/opencode/src/tool/todo.ts
  • ../happy-adjacent/research/opencode/packages/opencode/src/session/todo.ts

Modes, models, and permissions

OpenCode treats these as explicit state, not just prompt flavor.

  • newer logic keys on agent, providerID, modelID, and variant
  • plan/build/general/explore are modeled as agent choices more than a free-form mode string
  • permissions are first-class requests with id, sessionID, permission, patterns, metadata, and decision mode
  • decisions can be once, always, or reject
  • permission rules are pattern-based and support auto-unblocking pending matching requests

This is a good reference for Happy's app model even if Happy keeps its own policy engine.

Primary source files:

  • ../happy-adjacent/research/opencode/packages/opencode/src/permission/index.ts
  • ../happy-adjacent/research/opencode/packages/opencode/src/permission/evaluate.ts
  • ../happy-adjacent/research/opencode/packages/app/src/context/permission.tsx

Sandbox and isolation

OpenCode is weaker on true sandboxing than Codex.

  • the main isolation story is workspace and git worktree separation
  • extra workspaces are treated like sandboxes in product language
  • the server routes operations by workspace directory
  • there is not much evidence here of strong OS-level sandbox policy comparable to Codex

Takeaway for Happy: copy the workspace isolation ideas, not the lack of a deeper sandbox layer.

Primary source files:

  • ../happy-adjacent/research/opencode/packages/opencode/src/worktree/index.ts
  • ../happy-adjacent/research/opencode/packages/opencode/src/control-plane/workspace.ts

Sync and server architecture

This is probably the most valuable follow-up topic.

  • the app listens to a global SSE stream
  • events are then fanned into per-directory caches and reducers
  • full session history is fetched separately when needed
  • the client batches and coalesces updates instead of repainting on every raw event
  • the control plane already looks ready for non-local workspace adaptors later

This is a much better direction for Happy than a single opaque message pipeline.

Primary source files:

  • ../happy-adjacent/research/opencode/packages/opencode/src/control-plane/workspace-server/routes.ts
  • ../happy-adjacent/research/opencode/packages/opencode/src/control-plane/sse.ts
  • ../happy-adjacent/research/opencode/packages/app/src/context/global-sync.tsx
  • ../happy-adjacent/research/opencode/packages/app/src/context/sync.tsx

Context debug surface

The user feedback here is correct and important.

  • clicking the context usage field opens a context tab
  • that tab shows a useful breakdown of model/provider/context usage
  • it also exposes raw message-plus-parts state, effectively a built-in protocol debugger

Happy should copy this idea.

Primary source files:

  • ../happy-adjacent/research/opencode/packages/app/src/components/session-context-usage.tsx
  • ../happy-adjacent/research/opencode/packages/app/src/components/session/session-context-tab.tsx

What Happy should steal

  • envelope + typed-parts transcript structure
  • child-session subagent model with resumable IDs
  • first-class todo and permission stores
  • event stream for freshness plus fetch API for hydration
  • built-in raw context/messages inspector in the UI