Snapshot of where opencode + Qwen3-Coder + MCPs + Kimi-Linear + voice + Phoenix tracing land today, plus in-flight (oc-tree, kimi-linear context ramp) and next (ComfyUI) items with pointers to per-project NEXT_STEPS.md guides.
4.7 KiB
oc-tree — resumption guide
Open this file first when picking the work back up.
What this project is
A Python TUI sidecar that subscribes to opencode serve's SSE event
stream and renders a live tree of sessions → messages → tool calls in a
terminal pane next to the opencode TUI. Subagents nest under their
parent via session.created.info.parentID.
Roadmap entry: localgenai/Roadmap.md → "Layer 0: Cross-cutting
capabilities" → "Observability — partial" + prioritized step #12.
Phoenix (opencode/.opencode/plugin/phoenix-bridge.js) already handles
the external deep-trace store. oc-tree is the glanceable "what's it
doing right now" pane that lives in-harness (well, in tmux next to it).
Where we are
- Plan agreed: Python + textual, lives at
localgenai/oc-tree/. - Phases: M0 → M1 → M2 → M3 → M4. See descriptions in this repo's task
list (
TaskList) or the roadmap entry. - M0 — DONE (skeleton).
uv syncinstalls cleanly;oc-treeandoc-tree-probeentry points resolve. Imports verified. - M0 — AWAITING USER ACTION (schema verification). Probe is built
but hasn't been run against a live
opencode serve. Three open schema questions still unanswered.
What blocks progress
User needs to run the probe against a real opencode session and report back. Without these answers, M2's reducer design is guesswork.
Run in a tmux pane while opencode serve is up:
cd ~/Documents/obsidian/localgenai/oc-tree
uv run oc-tree-probe
Drive opencode through a session that hits all three triggers:
- Spawn a Task-tool subagent
- Trigger at least one permission prompt
- Make at least one regular tool call (Read/Bash/etc.)
Ctrl-C the probe. Then run:
# Q1: does session.created.info.parentID populate for subagents?
jq -r 'select(.type=="session.created") | .raw.properties.info.parentID' \
/tmp/oc-tree-probe.jsonl
# Q2: does message.part.updated carry full part or delta?
jq -c 'select(.type=="message.part.updated") | .raw.properties.part' \
/tmp/oc-tree-probe.jsonl | head
# Q3: what permission.* events actually fire?
jq -r '.type' /tmp/oc-tree-probe.jsonl | grep -i permission | sort -u
Paste the output (or the JSONL file path) into the next session.
What happens next
Once probe answers are in:
- Mark M0 complete, start M1 (flat session list) — textual app, live-updating list of sessions with status, no nesting yet. Proves the reducer + render loop. Independent of the schema answers, so could start in parallel.
- M2 (tree view) — needs probe answers to know:
- Whether to nest by
parentIDdirectly (Q1 yes) or fall back to inferring subagents fromTasktool-part response payloads. - Whether the part-update reducer replaces by
partID(Q2 = full part) or merges a delta (Q2 = delta). - What permission events to render (Q3).
- Whether to nest by
- M3 (reconnect + state rebuild) — heartbeat watchdog, REST replay on disconnect. Driven by sst/opencode#15149/#22198 known leaks.
- M4 (polish) — keybindings, theme, tmux layout doc.
File layout
localgenai/oc-tree/
├── pyproject.toml uv project (textual, httpx, httpx-sse)
├── README.md user-facing readme
├── NEXT_STEPS.md this file
├── .python-version 3.11
└── src/oc_tree/
├── client.py OpenCodeClient: REST + SSE
├── probe.py schema-verification CLI
├── __main__.py stub for `oc-tree` (real TUI in M1)
└── widgets/ empty (populated in M1+)
Key references
- opencode server docs: https://opencode.ai/docs/server/
- Authoritative schema:
GET /docon a runningopencode serve(do not hardcode — fetch per-version). - sst/opencode#7451 — no per-session SSE endpoint; we filter
/eventclient-side. - sst/opencode#6573 — Task subagent over
opencode servemay have bugs; this is what Q1 verifies. - sst/opencode#11424 —
message.part.updatedsometimes replays full state; this is what Q2 verifies. - sst/opencode#15149, #22198 — SSE disconnect leaks; informs M3 shutdown discipline.
Decisions worth not relitigating
- Python + textual chosen over Go+Bubbletea (faster iteration, matches stack — uvx already in use) and Node+ink (worse SSE/UI ergonomics; phoenix-bridge.js doesn't justify matching).
- Read-only v1. No sending messages, no editing. Just visibility.
- Lives in
localgenai/oc-tree/rather than its own repo; can be extracted later if it warrants a standalone release. - State rebuild via REST on every (re)connect rather than trusting
SSE catchup or
Last-Event-ID(server doesn't honor it).