chore: import upstream snapshot with attribution
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
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
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user