Deep-Dive DD-03 — OpenCode: Client/Server Architecture

Course: Master Course · Deep-Dive: DD-03 · Duration: 60 min · Prerequisites: Modules 0–12, DD-01, DD-02

156,000+ stars. The largest codebase in the terminal-harness category. Client/server architecture enabling remote sessions. The medium-thick reference.


Learning Objectives

  1. Apply the 6-phase methodology to OpenCode; produce a scored card.
  2. Explain OpenCode's client/server split as the enabler of remote sessions and Docker sandboxing.
  3. Compare OpenCode (medium-thick) against Aider (thin-medium) and Pi (thin).
  4. State why the client/server architecture is the foundation for OpenCode's sandboxing advantage.

The Subject

Metric Value
Language TypeScript
Stars 156,000+
License MIT
Tools ~15
System prompt ~5,000 tokens
Permission model Session-scoped
Architecture Client/server
Memory Server-side persistent sessions
Context mgmt repo-map + session truncation

OpenCode is the largest terminal harness by stars (156K+) and the reference for the client/server architecture in the CLI-harness category. The key architectural decision: the harness loop runs as a server, and the client connects to it — enabling remote sessions, Docker sandboxing of the server, and multi-client access. On Module 0.1's thickness spectrum, OpenCode sits squarely in the medium-thick band — substantially larger than Pi's ~1,200 lines and Aider's monolithic single-process design, and the only CLI harness in the roster where the loop is a separate long-running service.

Architecture — Client/Server, the Defining Split

The client/server split is the load-bearing decision and the source of every downstream capability that distinguishes OpenCode:

This split is why OpenCode can sandbox effectively (the server is containerized; the client is just a UI) while Pi and Aider cannot (their loops run directly in the user's terminal process, so containerizing the loop means containerizing the user's shell). The client/server architecture is the prerequisite for Module 5's outside-sandbox pattern in a CLI context — the sandbox lives where the loop lives, and in OpenCode the loop lives somewhere the user's shell doesn't.

[client TUI]  ←socket/transport→  [server: loop + tools + creds]  →  Docker container
   stateless                          containerized                     network-isolated

Tools (~15)

read, write, edit, bash, search, lsp-integrated operations (go-to-definition, find-references, hover), plus remote-session tools. More than Aider's ~8; justified by the richer use case (LSP integration enables precise code navigation instead of text-grep heuristics). The tool registry follows Module 2's schema-first pattern — each tool is a JSON schema definition, same as Pi, just more of them.

Context management

More sophisticated than Aider — OpenCode uses a combination of repo-map (like Aider) and session-based context management with truncation when a session approaches the model's window. Still not as advanced as Claude Code's active compaction or Tau's non-destructive compaction tree (DD-21), but a real Module 3 implementation. The session-boundary truncation is what keeps long sessions functional where Pi's context rots.

Key Design Decisions

  1. Client/server over monolith. This is the decision every other choice flows from. It costs complexity (the largest codebase in the category, ~25k+ LOC) and gains sandboxability, remoting, and multi-client access. Module 0.1's three-job separation is realized here as a process boundary, not just a code boundary.
  2. Docker as the default sandbox. The server container is the blast-radius container. Credentials live outside the agent's reach. This is the Module 5 outside-sandbox pattern in its CLI-native form.
  3. Session-scoped permissions. Permissions attach to a session, not globally. Reconnecting to a session restores its permission set. This is a middle ground between Pi's trust-the-model and Codex CLI's 3-tier model (DD-04).

Phase 4 — Security Audit

Credential flow: API keys live in the server process (containerized), not the client. The agent's tool-execution context is inside the container; credentials can be mounted read-only and withheld from the tool surface. This is the strongest credential-isolation story in the CLI-harness category — Module 5's "keep credentials outside the agent's reach" realized as an architectural property.

Shell/exec/write paths: bash, write_file, and edit execute inside the container. A compromised agent process can affect the container filesystem and make network calls only if the container's network policy permits. Blast radius is bounded by the container, not the host — the defining difference from Pi/Aider/Codex CLI.

Injection test (reasoned): OpenCode still has no untrusted-content tagging on file reads. A file read via read that contains injected instructions enters context as raw content (Module 2.4 Vector 1, ASI01). The sandbox contains the blast radius of compliance; it does not prevent the injection itself. Same gap as Pi/Aider; the sandbox just makes the consequences less catastrophic.

Score & Synthesize

Module Score Key decision vs Aider
1 Loop 4 ReAct + client/server =
2 Tools 4 ~15, LSP-integrated = (more tools, but justified by LSP)
3 Context 4 repo-map + session truncation =
4 Memory 4 session-based + server-side persistence +1
5 Sandbox 4 Docker (server containerized) +3
6 Permission 3 session-scoped =
7 Errors 3 standard =
8 State 3 server-side =
9 Verification 2 limited -1
10 Subagents n/a =
11 Observability 3 structured (server-side) =
12 Prompt 4 ~5k =
TOTAL 34/60 +2 vs Aider

The +2 over Aider comes almost entirely from the sandboxing advantage (+3 on Module 5, partially offset by -1 on verification). The client/server architecture is the enabler — without it, Docker sandboxing of the loop is impractical in a CLI context.

Architect's Verdict

OpenCode optimizes for remote-capable, sandboxed coding sessions via client/server architecture — the loop runs in a Docker container, the client is a stateless UI. It sacrifices simplicity (the largest codebase in the category) and verification (no built-in test-gate). Build on OpenCode for remote/team coding sessions requiring sandboxing; it is the most architecturally mature CLI harness at scale.

MLSecOps Relevance

The client/server split enables real sandboxing (Module 5) — the server is containerized, credentials can be kept outside the agent's reach. This is OpenCode's defining security property: it is the thinnest CLI harness that can credibly claim multi-tenant-ready isolation.

3 things OpenCode does better

  1. Client/server = sandboxable: the only CLI harness where Docker sandboxing is architecturally native. Module 5's outside-sandbox pattern, realized.
  2. LSP integration: precise code navigation (go-to-definition, find-references) as tools, not just text search. Module 2 done right.
  3. Remote sessions: connect from any client; the server persists. Enables team/shared sessions, headless runs, and reconnecting to long tasks.

3 things to fix

  1. Add computed verification (test gate) — Module 9 is weak; the most production-mature CLI harness should not ship without a verification hook.
  2. Legibility — the large codebase (~25k+ LOC) reduces legibility vs Pi/Aider; documentation of the client/server boundary would help.
  3. Add untrusted-tagging on file reads — same injection gap as Pi/Aider (Module 2.4). The sandbox contains blast radius; it does not prevent injection.

References

  1. OpenCode source — the client/server reference for the CLI-harness category.
  2. DD-01 (Pi) — the thin baseline; same schema-first tool pattern, opposite thickness.
  3. DD-02 (Aider) — the thin-medium comparison; same category, monolithic vs client/server.
  4. DD-04 (Codex CLI) — same total score (34/60), opposite bet (language-level vs architecture-level).
  5. DD-06 (oh-my-opencode) — the meta-harness layered on top of OpenCode.
  6. Module 0.1 — thickness spectrum; OpenCode as the medium-thick reference.
  7. Module 5 — inside vs outside sandbox; OpenCode's client/server enables the outside pattern.
  8. Module 2.4 — untrusted-content tagging (the missing injection defense).
# Deep-Dive DD-03 — OpenCode: Client/Server Architecture

**Course**: Master Course · **Deep-Dive**: DD-03 · **Duration**: 60 min · **Prerequisites**: Modules 0–12, DD-01, DD-02

> *156,000+ stars. The largest codebase in the terminal-harness category. Client/server architecture enabling remote sessions. The medium-thick reference.*

---

## Learning Objectives

1. Apply the 6-phase methodology to OpenCode; produce a scored card.
2. Explain OpenCode's client/server split as the enabler of remote sessions and Docker sandboxing.
3. Compare OpenCode (medium-thick) against Aider (thin-medium) and Pi (thin).
4. State why the client/server architecture is the foundation for OpenCode's sandboxing advantage.

---

## The Subject

| Metric | Value |
| --- | --- |
| Language | TypeScript |
| Stars | 156,000+ |
| License | MIT |
| Tools | ~15 |
| System prompt | ~5,000 tokens |
| Permission model | Session-scoped |
| Architecture | Client/server |
| Memory | Server-side persistent sessions |
| Context mgmt | repo-map + session truncation |

OpenCode is the largest terminal harness by stars (156K+) and the reference for the **client/server architecture** in the CLI-harness category. The key architectural decision: the harness loop runs as a server, and the client connects to it — enabling remote sessions, Docker sandboxing of the server, and multi-client access. On Module 0.1's thickness spectrum, OpenCode sits squarely in the medium-thick band — substantially larger than Pi's ~1,200 lines and Aider's monolithic single-process design, and the only CLI harness in the roster where the loop is a separate long-running service.

## Architecture — Client/Server, the Defining Split

The client/server split is the load-bearing decision and the source of every downstream capability that distinguishes OpenCode:

- **Server**: the loop, tool execution, context management, memory. Runs in a Docker container (sandboxed). Holds the model API credentials. Persists session state across client disconnects.
- **Client**: the terminal UI. Connects to the server via a local socket or remote transport. Stateless — can reconnect, switch machines, or run headless. Multiple clients can attach to one server (team/shared sessions).

This split is why OpenCode can sandbox effectively (the server is containerized; the client is just a UI) while Pi and Aider cannot (their loops run directly in the user's terminal process, so containerizing the loop means containerizing the user's shell). The client/server architecture is the prerequisite for Module 5's outside-sandbox pattern in a CLI context — the sandbox lives where the loop lives, and in OpenCode the loop lives somewhere the user's shell doesn't.

```
[client TUI]  ←socket/transport→  [server: loop + tools + creds]  →  Docker container
   stateless                          containerized                     network-isolated
```

### Tools (~15)

read, write, edit, bash, search, lsp-integrated operations (go-to-definition, find-references, hover), plus remote-session tools. More than Aider's ~8; justified by the richer use case (LSP integration enables precise code navigation instead of text-grep heuristics). The tool registry follows Module 2's schema-first pattern — each tool is a JSON schema definition, same as Pi, just more of them.

### Context management

More sophisticated than Aider — OpenCode uses a combination of repo-map (like Aider) and session-based context management with truncation when a session approaches the model's window. Still not as advanced as Claude Code's active compaction or Tau's non-destructive compaction tree (DD-21), but a real Module 3 implementation. The session-boundary truncation is what keeps long sessions functional where Pi's context rots.

## Key Design Decisions

1. **Client/server over monolith.** This is the decision every other choice flows from. It costs complexity (the largest codebase in the category, ~25k+ LOC) and gains sandboxability, remoting, and multi-client access. Module 0.1's three-job separation is realized here as a process boundary, not just a code boundary.
2. **Docker as the default sandbox.** The server container is the blast-radius container. Credentials live outside the agent's reach. This is the Module 5 outside-sandbox pattern in its CLI-native form.
3. **Session-scoped permissions.** Permissions attach to a session, not globally. Reconnecting to a session restores its permission set. This is a middle ground between Pi's trust-the-model and Codex CLI's 3-tier model (DD-04).

## Phase 4 — Security Audit

**Credential flow**: API keys live in the server process (containerized), not the client. The agent's tool-execution context is inside the container; credentials can be mounted read-only and withheld from the tool surface. This is the strongest credential-isolation story in the CLI-harness category — Module 5's "keep credentials outside the agent's reach" realized as an architectural property.

**Shell/exec/write paths**: `bash`, `write_file`, and `edit` execute inside the container. A compromised agent process can affect the container filesystem and make network calls only if the container's network policy permits. Blast radius is bounded by the container, not the host — the defining difference from Pi/Aider/Codex CLI.

**Injection test (reasoned)**: OpenCode still has no untrusted-content tagging on file reads. A file read via `read` that contains injected instructions enters context as raw content (Module 2.4 Vector 1, ASI01). The sandbox contains the *blast radius* of compliance; it does not prevent the *injection itself*. Same gap as Pi/Aider; the sandbox just makes the consequences less catastrophic.

## Score & Synthesize

| Module | Score | Key decision | vs Aider |
| --- | --- | --- | --- |
| 1 Loop | 4 | ReAct + client/server | = |
| 2 Tools | 4 | ~15, LSP-integrated | = (more tools, but justified by LSP) |
| 3 Context | 4 | repo-map + session truncation | = |
| 4 Memory | 4 | session-based + server-side persistence | +1 |
| 5 Sandbox | 4 | Docker (server containerized) | **+3** |
| 6 Permission | 3 | session-scoped | = |
| 7 Errors | 3 | standard | = |
| 8 State | 3 | server-side | = |
| 9 Verification | 2 | limited | -1 |
| 10 Subagents | — | n/a | = |
| 11 Observability | 3 | structured (server-side) | = |
| 12 Prompt | 4 | ~5k | = |
| **TOTAL** | **34/60** | | **+2 vs Aider** |

The +2 over Aider comes almost entirely from the sandboxing advantage (+3 on Module 5, partially offset by -1 on verification). The client/server architecture is the enabler — without it, Docker sandboxing of the loop is impractical in a CLI context.

### Architect's Verdict

> *OpenCode optimizes for remote-capable, sandboxed coding sessions via client/server architecture — the loop runs in a Docker container, the client is a stateless UI. It sacrifices simplicity (the largest codebase in the category) and verification (no built-in test-gate). Build on OpenCode for remote/team coding sessions requiring sandboxing; it is the most architecturally mature CLI harness at scale.*

### MLSecOps Relevance

> *The client/server split enables real sandboxing (Module 5) — the server is containerized, credentials can be kept outside the agent's reach. This is OpenCode's defining security property: it is the thinnest CLI harness that can credibly claim multi-tenant-ready isolation.*

### 3 things OpenCode does better

1. **Client/server = sandboxable**: the only CLI harness where Docker sandboxing is architecturally native. Module 5's outside-sandbox pattern, realized.
2. **LSP integration**: precise code navigation (go-to-definition, find-references) as tools, not just text search. Module 2 done right.
3. **Remote sessions**: connect from any client; the server persists. Enables team/shared sessions, headless runs, and reconnecting to long tasks.

### 3 things to fix

1. **Add computed verification (test gate)** — Module 9 is weak; the most production-mature CLI harness should not ship without a verification hook.
2. **Legibility** — the large codebase (~25k+ LOC) reduces legibility vs Pi/Aider; documentation of the client/server boundary would help.
3. **Add untrusted-tagging on file reads** — same injection gap as Pi/Aider (Module 2.4). The sandbox contains blast radius; it does not prevent injection.

---

## References

1. **OpenCode source** — the client/server reference for the CLI-harness category.
2. **DD-01 (Pi)** — the thin baseline; same schema-first tool pattern, opposite thickness.
3. **DD-02 (Aider)** — the thin-medium comparison; same category, monolithic vs client/server.
4. **DD-04 (Codex CLI)** — same total score (34/60), opposite bet (language-level vs architecture-level).
5. **DD-06 (oh-my-opencode)** — the meta-harness layered on top of OpenCode.
6. **Module 0.1** — thickness spectrum; OpenCode as the medium-thick reference.
7. **Module 5** — inside vs outside sandbox; OpenCode's client/server enables the outside pattern.
8. **Module 2.4** — untrusted-content tagging (the missing injection defense).