Files
boocode/boocode_code_review_v2.md
indifferentketchup 7b4f41b26f docs: roadmap shipping-state update + external code-review v2 findings
Update boocode_roadmap.md's shipped section through v2.6.4 (provider lifecycle,
persistent agent sessions, cursor/copilot retirement) and add
boocode_code_review_v2.md — a point-in-time external-fork lift/cross-check
findings doc (Paseo + opencode + llama.cpp + the second fork sweep), companion
to the standing boocode_code_review.md inventory.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 02:28:13 +00:00

40 KiB
Raw Blame History

BooCode — External Code Review v2 (lift findings)

Last updated: 2026-05-31

A point-in-time findings doc, not a standing inventory. It consolidates two reconnaissance passes against the upstream forks at /opt/forks/ and decides, per area, what BooCode should do about it. Pin it so the same upstreams aren't re-evaluated from scratch next month.

Companion docs: boocode_code_review.md is the standing external-repo inventory (every repo BooCode references, why each earned its row, license analysis). boocode_roadmap.md is the canonical shipping-state / version-ordering source. This v2 doc is the action layer on top of both: "given what's upstream as of 2026-05-31, here's the lift/cross-check/re-derive/n-a call." Reconcile shipping state via the roadmap when in doubt; fold durable rows back into boocode_code_review.md.

Sources feeding this doc

  1. Paseo recon (Sam) — two passes: a Phase 2/3 server-manager recon and a claude-transport recon. Conclusions consolidated by area below (§2a). AGPL-3.0 — pattern-only, no code lift, ever.
  2. Three-fork agent sweep (this session, 2026-05-31) — read-only general-purpose agents over anomalyco/opencode (MIT, code-liftable), getpaseo/paseo (AGPL, pattern-only), ggml-org/llama.cpp (consumed via llama-swap/sidecar — adopt features/flags, not C++). Detail in §2§4.
  3. Second fork sweep (this session, 2026-05-31) — 8 read-only agents over the remaining 11 repos in /opt/forks/ (conductor, superset, openchamber, happy, cline, qwen-code, amp-acp, pi-acp, claude-code, goose, unsloth). Detail in §5; high-value items folded into §1.

Caveats

  • /opt/forks/llama.cpp is a shallow clone (90 commits, ~5 days visible). llama.cpp findings are read from source as it stands today; "what changed when" attribution is limited. git fetch --unshallow before the next review.
  • /opt/forks/opencode arrived shallow (rooted 2026-05-25); the agent ran git fetch --unshallow and re-surveyed the real 6-week window. opencode also did a v2 Effect/event-sourced rewrite (packages/core/, packages/llm/) — most of that churn is architecturally divergent and ruled out.
  • HEADs at review time: paseo 41cb1af (main, v0.1.87), opencode 1afa9e3 (dev, ~v1.15.13), llama.cpp aa46bda8 (detached).

Verdict legend

Verdict Meaning
LIFT Take it. Flavor noted: code-lift (MIT), pattern-lift (AGPL/clean-room re-impl), config-adopt (new upstream flag), drop-our-code (upstream now does it → delete ours).
RE-DERIVE Idea is right, their impl is insufficient/divergent for our needs — write fresh, don't adapt theirs.
CROSS-CHECK We already have it; confirmed current vs upstream. No action.
TRACK Behavioral/external change to be aware of. No code action now.
N-A Not liftable into our architecture, or reduces to a separate decision.

1. Net actionables (priority roll-up)

Updated after the second fork sweep (2026-05-31, §5). New items from that sweep are tagged ⁺.

# Item Source Verdict Maps to Effort
1 Retire the AGPL tool-call parser + html-to-md — llama-server parses qwen3.x <tool_call>/<function=> server-side; both lifted files are confirmed AGPL-3.0-only (§5k); swap html-to-md to a permissive lib llama.cpp + unsloth⁺ LIFT · drop-our-code license-debt / inference; new batch M, staged + gated on jinja
2 Warm-ACP backend (goose/qwen) — one spawn, one session/new, many prompts; validated by qwen's own qwen --acp reference impl (the "qwen ACP was HTTP-only" premise is stale) Paseo recon + qwen-code⁺ LIFT · pattern v2.6 Phase 2 M
3 ⁺ Fuzzy patch applier for edit_file — exact→whitespace→Levenshtein match ladder + unicode canon + multi-occurrence guard; BooCoder's edit_file is exact-.includes-or-throw today cline⁺ LIFT · code edit/diff robustness (local-model drift) M
4 ⁺ git stash create + private-ref checkpoint — per-turn workspace snapshot capturing all state incl. external-agent edits (BooCode rewind only undoes its own queued edits) cline⁺ LIFT · code checkpoint/restore UX M
5 ⁺ opencode lifecycle hardening — health monitor + crash auto-restart + busy-aware restart + port reclaim + stall-detecting SSE; MIT, same warm-server architecture (supersedes the paseo RE-DERIVE — better source) openchamber⁺ LIFT · pattern/code v2.6 Phase 3 M
6 Post-interrupt stale-terminal guard — confirmed correctness bug in opencode-server.ts opencode/paseo (verified) LIFT · pattern (bugfix) v2.6 Phase 1/2 S (~½ day)
7 ⁺ Parse qwen/claude stream-json NDJSON in PTY fallback — today stdout is sliced opaque; one parser serves both (Claude-Code-compatible schema) qwen-code⁺ LIFT · pattern v2.6 Phase 2 / dispatch parsing S
8 ctx/token usage for opencode sessionssession.next.step.ended already on the wire opencode + paseo (converged) LIFT · code v2.6 Phase 1 UX SM (~80150 LoC)
9 Claude continuity + transport--resume via hook/jsonl-watcher → claudeSessionId; happy proves the @anthropic-ai/claude-agent-sdk path (resolves the SDK-vs-PTY decision — lean SDK) Paseo recon + happy⁺ LIFT · code + decision claude-provider batch M
10 ⁺ Universal-agent notify-hook → normalized status — inject a hook into each PTY agent's config, normalize ~30 event names → 5 states; gives goose/qwen/claude real working/blocked/done signals superset⁺ (clean-room, ELv2) RE-DERIVE v2.6 Phase 2/3 status MH
11 New sampling knobs top_n_sigma, dry_* family; --reasoning-budget llama.cpp LIFT · config-adopt AGENTS.md frontmatter + validator allowlist S
12 ⁺ File-provenance compaction ledger (## Files Read/Modified) + MistakeTracker (heterogeneous-failure recovery) cline⁺ LIFT · pattern context-mgmt / recovery SM
13 Bundle/watch: stall-timeout + retry/backoff (opencode); worktree-archive cascade (paseo); LRU-bound caches; subagent permission demux; tool-pair-atomic prune cross-check (cline)⁺; diff-line→agent re-prompt (superset)⁺ mixed WATCH Phase 2/3, review UX, resilience varies

Headline: #1 stays the strategic win and is now settled, not speculative — the unsloth recon confirmed both lifted files are AGPL-3.0-only (§5k); the only gate is the jinja config check (§6). The second sweep added four genuinely-new code lifts: #3 fuzzy patch applier and #4 git-stash checkpoint (both cline, both directly fix where BooCoder's write/edit surface is weakest for local models), #5 openchamber lifecycle hardening (the concrete, MIT, same-architecture answer to v2.6 Phase 3 — supersedes the weaker paseo re-derive), and #7 stream-json parsing (cheap, shared by qwen+claude PTY). #2 Phase-2 warm-ACP is now de-risked by qwen's own reference impl. #9 resolves the claude direction (lean SDK).


2. Paseo (AGPL-3.0 — pattern-only)

2a. Consolidated recon, by area (Sam's two passes)

Area Verdict One-line
OpenCode server lifecycle CROSS-CHECK Paseo hand-rolls the spawn (not createOpencodeServer), waits for "listening on" on stdout, port-0 allocation, concurrent callers wait on one startPromise, no OPENCODE_SERVER_PASSWORD. Same shape BooCode shipped in v2.6.1 — nothing to lift.
OpenCode crash recovery + reconnect RE-DERIVE → superseded Lazy restart-on-demand (exit handler nulls the server, next getCurrentServer() respawns), no active supervision; resumeSession does not verify the session exists on disk before resuming. Insufficient for Phase 3. Update (2nd sweep): openchamber (§5c) has a better, MIT, same-architecture version — health-monitor state machine + crash auto-restart + busy-aware restart. Lift from openchamber, not paseo.
Warm-ACP supervision (goose/qwen) LIFT · pattern SpawnedACPProcess: one spawn, one session/new, many prompts; child lives for the session not the turn; per-turn abort = connection.cancel({sessionId}) without killing the child; child-exit fires turn_failed (no restart). Clean signal split; integrates against BooCode's existing acp-dispatch.ts. This is the Phase 2 lift — and qwen-code (§5f) ships its own qwen --acp reference impl that validates the whole approach.
OpenCode reasoning dedup CROSS-CHECK streamedPartKeys keyed reasoning:${partID}; delta adds the key, final part skips if present, cleared per turn. Identical to v2.6.1.
Claude transport N-A Paseo uses @anthropic-ai/claude-agent-sdk in stream-json mode, not PTY. Getting Paseo's transport means adopting the SDK — net-new integration, not a lift.
Claude continuity LIFT · code claude --resume <sessionId> across turns: capture the session id from claude's output, store it, pass --resume next turn; claude re-reads its transcript and continues. Small change to BooCode's PTY dispatch (run with --output-format stream-json, parse the id, persist, resume). The actionable claude finding.
Claude streaming/parsing N-A Structured events (tool calls, reasoning, partials) come from the SDK; PTY degrades to scraping. Adopting structured claude streaming = adopting the SDK — separate decision.
Claude session persistence CROSS-CHECK Same describePersistence/resumeSession shape BooCode already has for opencode; claude slots in. Neither Paseo nor BooCode verifies the transcript exists on disk before resume (shared open question — see §5).

Recon's net: LIFT = warm-ACP supervision (Phase 2) + claude --resume continuity (standalone batch). RE-DERIVE = OpenCode crash recovery (Phase 3). Everything else cross-check or n/a. The two n/a claude items both reduce to one deferred decision: adopt @anthropic-ai/claude-agent-sdk or stay PTY.

2b. Additional findings (this session's Paseo agent sweep)

These came from the broader agent pass, not the targeted Phase 2/3 recon. Where they touch the same code as §2a, the §2a recon is authoritative.

Finding Verdict Notes
Post-interrupt stale-terminal suppression (paseo 1d38aac) LIFT · pattern (bugfix) See §3 #3 — verified to be a live bug in BooCode. Highest-confidence paseo item.
Provider-agnostic AgentUsage normalized usage/cost frame LIFT · pattern Converges with opencode's session.next.step.ended (§3 #4). Paseo's {inputTokens, cachedInputTokens, outputTokens, totalCostUsd, contextWindowMax/Used} is the target shape for normalizing across providers; do the opencode slice first.
Worktree-archive → cascade-archive agents + schedule cleanup (paseo b6103a5) WATCH → adopt in Phase 3 Soft-delete (keep archivedAt), single archive event fans out to children + downstream rows, Promise.allSettled so one failed delete doesn't abandon the rest. Right shape for the v2.6 Phase 3 worktree reaper.
Server retire/refcount + LRU-bound caches (paseo server-manager.ts, leak-fix f20393d) WATCH (low confidence) The agent read a retire-set/refcount mechanism; the §2a server-manager recon concluded "nothing to lift." Treat the lifecycle as cross-check (§2a wins). The one durable takeaway: bound the per-session/per-worktree Maps in the warm opencode server (long-lived daemon → unbounded caches leak). Confirm against §2a before acting.
Subagent permission forwarding (paseo 44863ec) WATCH (gated) opencode task tool spawns child sessions; forward permission.asked from tracked children by parentID demux. Blocked: BooCode's opencode-SSE path has zero permission handling today (runs auto-approve). Reachable only after BooCoder builds opencode-SSE permission cards at all. Ties to v2.4.

3. OpenCode (MIT — code-liftable)

# Finding Evidence Verdict Notes
1 Consume the fuller session.next.* event set in opencode-server.ts packages/core/src/session/event.ts:105-365; BooCode handles only ~5 arms (opencode-server.ts:215-311) LIFT · code Events already in the installed @opencode-ai/sdkno dep bump. High-value arms: step.ended ({tokens{input,output,reasoning,cache},cost} → #4 below); compaction.{started,delta,ended} (warm server auto-compacts mid-conversation; today shows as a silent context gap); tool.progress, tool.input.{started,delta}, retried, step.failed.
4 ctx/token usage for opencode (the high-value slice of #1) event.ts:117-135 LIFT · code Closes the roadmap-named gap: "opencode/goose/qwen/claude dispatch with no ctx/token usage; only native boocode tracks ctx." Mirror BooChat's existing 'usage' WS frame on the coder side; accumulate per (chat, agent). Converges with paseo AgentUsage (§2b).
2 Stalled-stream chunk-timeout (wrapSSE + header timeout) provider/provider.ts:40-96 (f965db9, c7e1fc5) WATCH · pattern BooChat's stream-phase.ts has no server-side stall timeout — a hung llama-swap stream relies entirely on the frontend 60s discard_stale watchdog. ~40-60 LoC to wrap the fullStream loop with a per-chunk timeout firing the existing abort path. Low incidence on a single local instance; do it if stuck rows recur.
3 Retry-with-backoff + retryability classifier (session/retry.ts) session/retry.ts, message-v2.ts:1155 (14e0b9b) WATCH · pattern BooChat has zero retry logic. delay() parses retry-after[-ms] headers w/ exp-backoff fallback; retryable() classifies transient-5xx / rate-limit / context-overflow-exclusion. Strip the Go-billing arms. Pairs naturally with #2. llama-swap rarely emits retry-after, so value is mostly transient-5xx/stall retry.
MCP auth file-lock (mcp/auth.ts, fa73ec4) N-A (deferred) Serializes concurrent OAuth token refreshes. Can't trigger — BooCode's config schema rejects OAuth MCP servers until secret storage lands (roadmap). Note for when OAuth MCP is un-deferred.

Confirmed current (cross-check, no refresh needed): compaction algorithm (incl. tail_start_id/splitTurn post-fix — verified identical), two-tier prune, truncate, run-loop (BooCode drives off live result.toolCalls, not a history scan — not vulnerable to opencode's interrupted-tool re-prompt bug), doom-loop guard, MCP client, permission ruleset. Ruled out: v2 Effect/event-sourced core, packages/llm/ native runtime (diverges from the AI SDK v6 BooCode just adopted), adaptive-reasoning (cloud-Anthropic only), acp-next (BooCoder is the ACP client).


4. llama.cpp (consumed via llama-swap / llama-sidecar — adopt features, not C++)

4a. Retire the AGPL tool-call parser — LIFT · drop-our-code

llama-server moved to a template-learning PEG auto-parser + lazy grammar that parses qwen3.5/3.6's tool markup server-side into OpenAI tool_calls.

  • Evidence: common/chat-auto-parser-generator.cpp, common/chat-diff-analyzer.cpp (1570 lines), common/chat-peg-parser.cpp; shipped models/templates/Qwen3.5-4B.jinja (uses BooCode's exact Pattern-2 <tool_call><function=…><parameter=…> + <think>); server emits structured tool_calls in both non-streaming and streaming (tools/server/server-chat.cpp:421-577), reasoning split into reasoning_content/reasoning_content_delta. tool_choice=required + grammar-constrained calls exist (common/chat.cpp:290-300).
  • Gate (the one open question): only fires if llama-server runs with --jinja + a qwen3.x template. BooCode already treats --jinja/--chat-template* as managed flags (llama-args-validator.ts:92-102) and sends tools/toolChoice:'auto' through the AI SDK (stream-phase.ts:202,438) — the path is wired; the unknown is whether the live llama-swap/sidecar model config passes --jinja (§5).
  • What's missing: no qwen3.x-named native handler — qwen3.6 rides the generic template-driven path. The template teaches Patterns 1 (<tool_call>{json}) and 2 (<function=…>) but not Pattern 3 (<invoke name=…>), the Anthropic-shape residue qwen drifts into.
  • Staged plan (do not delete blind — CLAUDE.md notes qwen3.6 was unreliable):
    1. Confirm --jinja + Qwen3.5 template are live (add the flags if not).
    2. Validate native tool_calls against real qwen3.6 streaming for one release, behind a feature flag.
    3. Trim tool-call-parser.ts to a clean-room <invoke>-only fallback (~250 of 427 lines deletable; rewrite the remainder without Unsloth/AGPL provenance). Net: AGPL-3.0 liability eliminated even if a thin fallback stays.

4b. Config-level adopts — LIFT · config-adopt (pass straight through llama-swap as OpenAI-compat body fields; no binary upgrade)

  • New sampling params (server-task.cpp:279-290): top_n_sigma, xtc_probability/threshold, typical_p, the dry_* repetition family (dry_multiplier/base/allowed_length/penalty_last_n/sequence_breakers), frequency_penalty, repeat_penalty. top_n_sigma + dry_* are the high-value pair for an agentic model prone to loops — ties to the doom-loop sentinel. Surface in AGENTS.md frontmatter + the validator allowlist.
  • --reasoning-budget N (LLAMA_ARG_THINK_BUDGET) + --reasoning on|off|auto, default reasoning_format=auto: server-side cap on qwen3.6 thinking (cheaper turns) without prompt hacks, and reasoning_content arrives as a separate field — BooCode could consume it directly instead of scraping <think>.

4c. Behavioral changes — TRACK (no code action; awareness)

  • SSE headers sent at slot-start (0821c5fcf): in stream mode, HTTP 200 + headers flush when prompt processing begins, before the first token. BooCode keys its stale-stream timer on token activity, not header arrival → safe, but time-to-headers semantics shift. Also task_params.stream default flipped true → false — harmless for BooCode (always sets stream), but any llama-swap/sidecar code omitting stream now defaults to non-streaming.
  • /props router-mode dummy n_ctx:0 (server-models.cpp:1170-1173): llama.cpp gained a native multi-model router; its bare /props (no ?model=) returns n_ctx:0. BooCode reads /upstream/<model>/props which resolves to a specific model → still correct today. Silent failure mode only if a bare router /props is ever hit: ctx_max=0 → rejected → negative-cache masks the misconfig → compaction budget degrades. (Aside: the native router could eventually replace llama-swap — separate evaluation.)
  • LLAMA_ARG_ env-prefix unification (6b4e4bd58): confirm the sidecar's LLAMA_* env vars use the LLAMA_ARG_ prefix.

4d. SKIP

  • Native Anthropic Messages API in llama-server (test_compat_anthropic.py) — BooCode is OpenAI-compat via the AI SDK; switching wire formats buys nothing. (Minor TRACK: could in principle back a local "claude-compatible" provider — net-new feature, not a lift.)
  • Qwen 3.5/3.6 TP granularity fix (8b0e0db60) — only relevant if running qwen3.6 across 3 GPUs with tensor-parallel; then it's a binary-upgrade correctness fix, not an API change.
  • HTTP ETags / --api-key-file / timeout bump — irrelevant behind Authelia + llama-swap.

5. Second fork sweep (2026-05-31) — 11 repos

Read-only agent review of everything else in /opt/forks/ except the three already covered (paseo/opencode/llama.cpp), BooCode's own llama-sidecar, and codecontext/codesight (skipped on request). Repos: conductor, superset, openchamber, happy, cline, qwen-code, amp-acp, pi-acp, claude-code, goose, unsloth. Shallow clones (history-limited but source intact): cline, qwen-code, amp-acp, pi-acp, claude-code, goose, unsloth. Full: conductor, superset, openchamber, happy.

5a. openchamber (openchamber/openchamber, MIT — code-liftable)

Multi-runtime (web/PWA/Electron/VS Code) GUI for opencode-as-warm-server — the closest architectural sibling to BooCoder's backend. Stronger than BooCode in exactly one dimension: opencode process-lifecycle hardening (BooCode's v2.6 Phase 3 frontier). Divergence shaping every lift: openchamber runs one global opencode server + one /global/event stream; BooCode runs per-(chat,agent) sessions with per-session event.subscribe({directory}) — so these are pattern/code-adaptation lifts, not drop-ins.

# Finding Evidence (HEAD a394a877) Verdict Maps to
5c Lifecycle hardening: health monitor + crash auto-restart + busy-aware restart packages/web/server/lib/opencode/lifecycle.jsrunHealthCheckCycle (L896), HEALTH_CHECK_MAX_CONSECUTIVE_FAILURES=20, shouldSkipRestartForBusySessions+STALE_BUSY_GRACE_MS (L872/838), startHealthMonitoring 15s (L938), triggerHealthCheck (L930). BooCode's opencode-server.ts:143 literally comments "recovery is Phase 3" LIFT · pattern v2.6 Phase 3 (#5)
Port reclaim before respawn (killProcessOnPort lsof+kill, waitForPortRelease net.connect poll) lifecycle.js:44,101, used in restartOpenCode L595 LIFT · code (S) Phase 3
Stall-detecting SSE reader + Last-Event-ID replay (2048-event ring, 20s stall-abort) lib/event-stream/upstream-reader.js:110-131, global-hub.js:88-149 LIFT · pattern (the stall-timer half is S, high-value) hardens runSessionEventLoop
OPENCODE_SERVER_PASSWORD scheme confirmed = Authorization: Basic base64("opencode:"+pw), rotate-on-restart packages/vscode/src/opencode.ts:55-65,786; lifecycle.js:458 CROSS-CHECK → LIFT · config closes a known unknown (BooCode runs the warm server unsecured on loopback)
Worktree layout/reaper mirrors opencode's <data>/worktree/<projectID>/; removeWorktree saga packages/vscode/src/gitService.ts:1062,1874 CROSS-CHECK Phase 3 reaper; check BooCode's worktree paths align with opencode's expected layout

Ruled out: warm-ACP/goose/qwen/claude (openchamber is opencode-only), SSE part-translation/reasoning-dedup (BooCode's is more complete), Arena-equivalent, permission cards — all already-better-in-BooCode or N-A.

5b. cline (cline/cline, Apache-2.0 — code-liftable)

Re-architected into a layered SDK. Two strong code lifts that hit exactly where BooCoder's write/edit surface is weakest for local quantized models.

# Finding Evidence (HEAD 31a118f) Verdict Maps to
5d git stash create + private-ref checkpoint — per-turn snapshot of full dirty worktree, GC-safe, invisible to git stash list, restorable with conversation-trim in sync sdk/packages/core/src/hooks/checkpoint-hooks.ts:177-253; session/checkpoint-restore.ts:161-189 LIFT · code+pattern (#4) checkpoint/restore — captures external-agent edits BooCode's rewind can't
5e Fuzzy patch applier — exact→trimEndtrim→Levenshtein≥0.66 ladder + unicode canon (dashes/curly-quotes/nbsp) + multi-occurrence guard; unmatched→warning not throw extensions/tools/executors/apply-patch-parser.ts:347-431,58-83; editor.ts:133-143 LIFT · code (#3) BooCoder edit_file is exact .includes-or-throw (pending_changes.ts:111)
File-provenance carry-forward## Files {Read,Modified} ledger merged across compactions, deterministic extensions/context/compaction-shared.ts:351-410 LIFT · pattern (#12) context-mgmt
MistakeTracker — counts heterogeneous consecutive failures (api/invalid-tool/exec), injects recovery guidance + resets vs hard-stop runtime/safety/mistake-tracker.ts:82-142 LIFT · pattern (#12) complements doom-loop (which only catches identical repeats)
Tool-pair-atomic compaction eviction (BFS over tool_use_id, turn-boundary cut) extensions/context/basic-compaction.ts:181-205 CROSS-CHECK verify selectPruneTargets never orphans a tool_result

Ruled out: prompt-caching (Anthropic cache_control markers — N-A, llama.cpp auto-prefix-caches), stream retry (delegated to AI SDK — same as BooCode), MCP marketplace, hub/daemon (multi-client — BooCode is single-process).

5f. qwen-code (QwenLM/qwen-code v0.17.0, Apache-2.0 — code-liftable)

The "qwen = one-shot PTY because ACP was HTTP-only" premise is obsolete. qwen now ships a full stdio-ACP agent, a qwen serve HTTP+SSE daemon, and a Claude-Code-compatible stream-json protocol.

# Finding Evidence Verdict Maps to
Warm qwen --acp is real — multi-session Map<sessionId,Session>, loadSession/unstable_resumeSession, setSessionMode/unstable_setSessionModel, stdio NDJSON via @agentclientprotocol/sdk packages/cli/src/acp-integration/acpAgent.ts:308,322-351,384-568 CROSS-CHECK → LIFT · pattern (#2) v2.6 Phase 2 — validates the openspec plan; wire goose/qwen to acp-dispatch.ts
5g stream-json = Claude-compatible NDJSON (system/assistant/result/stream_event with content_block_delta text/thinking/tool deltas, usage, session_id) — BooCode parses none of it (dispatcher.ts:406 slices stdout opaque) nonInteractive/types.ts:88-262, StreamJsonOutputAdapter.ts LIFT · pattern (#7) one parser serves qwen and claude PTY fallbacks
Resume primitives --resume <uuid|title> / --continue / --session-id <uuid> / --fork-session config/config.ts:825-985,1668-1721 LIFT · config mint a stable per-(chat,agent) UUID; parity with claude --resume
qwen serve daemon + @qwen-code/sdk (HTTP+SSE, Last-Event-ID replay ring, better than opencode's SSE) commands/serve.ts:51-266; packages/sdk-typescript/src/daemon/* TRACK stdio-ACP is cheaper now; mine its SSE-reconnect design when hardening opencode SSE (converges w/ openchamber 5c)

Note: BooCode ships @agentclientprotocol/sdk@^0.22.1 (newer than qwen's ^0.14.1) — same package family, BooCode ahead; cross-check the v0.14↔v0.22 initialize/capability handshake before relying on unstable_resumeSession (the unstable_ prefix signals churn). Ruled out: the rewind commit (c699738) is a qwen-TUI history-count fix, not a wire event — N-A.

5h. happy (slopus/happy, MIT — code-liftable)

Mobile/remote client that drives Claude Code via the @anthropic-ai/claude-agent-sdk (NOT PTY). A working existence-proof for BooCode's claude SDK-vs-PTY decision.

# Finding Evidence (HEAD 21c6ced) Verdict Maps to
Claude Agent SDK in streaming-input mode — one persistent query() fed a PushableAsyncIterable<SDKUserMessage>; structured system/init (tools/skills/mcp), assistant, result, tool parts — no stdout scraping claude/sdk/query.ts, claude/claudeRemote.ts:152-259; dep @anthropic-ai/claude-agent-sdk@^0.2.96 LIFT · pattern + resolves the decision → lean SDK (#9) claude-provider direction
5i --resume continuity via SessionStart-hook + JSONL watcher → captures Claude's UUID as claudeSessionId, fed back as SDK resume:; reconnect-safe (treatExistingAsProcessed) claude/utils/generateHookSettings.ts, sessionScanner.ts, claude/session.ts:113-127 LIFT · code (#9) cleanly separates Claude's UUID from BooCode's (chat_id,agent) key; transport-independent — pays off even on PTY
canUseTool permission callback — single chokepoint, live setPermissionMode, bash-prefix allow-cache claude/claudeRemote.ts:134,169, permissionHandler.ts CROSS-CHECK cleaner integration point than parsing PTY permission prompts
Local↔remote single-session handoff (TTY ⇄ SDK share one Claude UUID); E2E socket.io relay claude/loop.ts:77-115; api/encryption.ts TRACK / N-A relay N-A (Authelia owns auth); handoff only if BooTerm⇄CoderPane session-continue is ever wanted

5j. superset (superset-sh/superset, Elastic License 2.0 — source-available, PATTERN-ONLY)

Electron macOS "code editor for AI agents"; runs every agent as a raw PTY process and learns state purely from hooks the agents POST back (no editor↔agent protocol, tracks zero tokens/cost). All items clean-room only.

# Finding Evidence (HEAD 7f3e5b3) Verdict Maps to
5j Universal-agent lifecycle hooks → normalized status — inject a notify hook into each agent's native config (~/.claude/settings.json, ~/.codex/hooks.json, opencode plugin), POST {terminalId,eventType,agent}; server collapses ~30 vendor event names → 5 states apps/desktop/.../agent-setup/*, templates/notify-hook.template.sh, host-service/.../map-event-type.ts RE-DERIVE (#10) gives BooCode's PTY agents (goose/qwen/claude) real working/blocked/done state it lacks today
Worktree destroy saga — preflight inspect (dirty/unpushed) + ordered failure semantics + in-flight guard host-service/.../workspace-cleanup.ts RE-DERIVE Phase 3 worktree reaper
Out-of-process PTY daemon w/ crash supervision + adoption (circuit-breaker, adopted-PID liveness poll) host-service/.../DaemonSupervisor.ts RE-DERIVE / TRACK Phase 3 (BooTerm tmux already does some)
Diff-line → agent-comment re-prompt loop (select lines → send to existing session or new agent) apps/desktop/.../DiffPane/AgentCommentComposer/* RE-DERIVE review/diff UX frontier

Ruled out: token/cost (superset tracks none — BooCode ahead), permission cards (BooCode's intercept-and-render is richer; superset just chimes + bypass-flags the agent), editor↔agent protocol (there is none), all SaaS/cloud/billing plumbing.

5k. unsloth (unslothai/unsloth) — decision-settling: CONFIRMED AGPL-3.0-only

The lifted parser + HTML→MD converter ARE AGPL-3.0; the v2 clean-room recommendation stands. Unsloth is dual-licensed: core unsloth/ lib = Apache-2.0 (LICENSE, pyproject.toml), but the studio/ subtree = AGPL-3.0-only — dedicated studio/LICENSE.AGPL-3.0, studio/package.json "license":"AGPL-3.0-only", README §line 262 carves Studio out explicitly, and both lifted files carry per-file SPDX headers (studio/backend/core/inference/{tool_call_parser.py,_html_to_md.py}# SPDX-License-Identifier: AGPL-3.0-only). BooCode's ports already carry the AGPL SPDX header (obligation on-record). Network-served ⇒ AGPL §13 network-copyleft is the live liability. HTML→MD can be replaced outright by a permissive lib (turndown / node-html-markdown); the tool-call parser needs a clean-room rewrite from spec (the <tool_call>/<function=> grammar is short and re-derivable).

5l. conductor (conductor-oss/conductor, Apache-2.0, Java) — LOW / near-NONE

Confirmed Netflix/Orkes Conductor — enterprise distributed workflow engine (5600 commits, Spring/Flyway/Cassandra), not the Mac Claude-Code app. Wrong scale + wrong substrate (polling workers + Redis queues vs BooCode's single-user Postgres LISTEN/NOTIFY), and BooCode already sourced its task-DAG/dispatcher/pipelines/human_inbox from agent-hub + Roo Boomerang. One worth-a-glance reference: the retry/backoff/timeout taxonomy (TaskDef.java RetryLogic{FIXED,LINEAR,EXP} + TimeoutPolicy, delay formula in DeciderService.java:634-680, with jitter + total-time-budget guard) — BooCode has no retries today; copy the field set + three formulas when retries land. Everything else (decider-replay engine, 24 task mappers, fork-join, sub-workflow, human-task) = N-A, already-covered or wrong-scale.

5m. ACP provider candidates — amp-acp SKIP, pi-acp WATCH

Both are config-only adds to BooCode's v2.3 catalog ({extends:'acp', label, command, env}) and both use @agentclientprotocol/sdk@~0.22/0.12, proto v1 — wire-compatible with BooCode's own @agentclientprotocol/sdk@0.22.1 (see correction in §6).

  • amp-acp (tao12345666333/amp-acp, Apache-2.0): adapter for Sourcegraph Amp. npx -y amp-acp + AMP_API_KEY. SKIP — Amp is a paid cloud product with no self-host / no BYO-key / no local-model path; can't point at llama-swap. Keep only as the canonical "does add-from-catalog work" smoke entry (lowest-risk Apache-2.0 ACP adapter).
  • pi-acp (svkozak/pi-acp, MIT): bridge for pi (spawns pi --mode rpc). npx -y pi-acp, pi free + self-hostable, dynamic model discovery. WATCH — but found no evidence pi supports an OpenAI-compatible/llama-swap base URL (cloud BYO-keys only today) + v0.0.27 maturity ("MVP", MCP not wired). Re-evaluate if pi adds a local provider — then it's a strong config-only ADD.

5n. claude-code & goose — low/cosmetic

  • claude-code (anthropics/claude-code, depth-1): the public issue-tracker/docs repo, not source. Thin. No stream-json schema doc (keep relying on observed output). Notables: CLAUDE_CODE_SESSION_ID env injected into Bash-tool subprocesses (hook↔session correlation); examples/settings/*.json permission/sandbox shapes; SKILL.md frontmatter is simpler (name/description/version) than BooCode's eval.yaml. The one example hook (bash_command_validator) is the same family BooCode already vendored. Nothing net-new liftable.
  • goose (block/goose, depth-1, Apache-2.0 Rust → pattern-only): the AAIF/Linux-Foundation move is cosmetic — binary goose, goose acp invocation, and ~/.config/goose/ config path all UNCHANGED; only org/URLs changed (block/gooseaaif-goose/goose). Watch: grep BooCode install docs for block/goose URLs (will eventually 404). For v2.6 Phase 2: goose ACP supports multi-session + mid-session model/mode switch + session persistence, but no loadSession/resume method surfaced → cross-restart resume looks thinner than opencode's; don't assume opencode-style agent_sessions resume works identically for goose.

6. Open decisions / things to think about

  1. The jinja gate (blocks #1, the top item). Is --jinja + a qwen3.x template live in the llama-swap/sidecar model config? Read-only to answer, but the config may live with the sidecar on sam-desktop (100.101.41.16) — needs Sam's OK before any SSH. This single check decides whether the AGPL-parser retirement is actionable now or needs a config change first.
  2. Claude transport: SDK vs PTY — now evidenced, leaning SDK. happy (§5h) is a working existence-proof that @anthropic-ai/claude-agent-sdk in streaming-input mode drives Claude Code with structured events (tool calls, reasoning, system/init tool/skill/mcp lists, usage) and clean continuity — richer than PTY stdout-scraping. Decision narrowed to: adopt the SDK (net-new integration, ~100-line streaming-input pump) vs. stay PTY + just add --resume. Independent of warm-ACP Phase 2. Note the continuity mechanism (§5i hook + jsonl-watcher → claudeSessionId) is transport-independent, so ship it either way.
  3. stream-json parser is shared infrastructure, not a per-agent chore. qwen-code (§5g) and claude-code emit the same Claude-Code-compatible NDJSON. One parser keyed on type / stream_event.event.type unlocks tool/reasoning/usage surfacing for both qwen and claude PTY fallbacks (today both are sliced opaque). Decide whether to build it as a shared module now (cheap) rather than twice later.
  4. Transcript/session verification before resume (shared gap). Neither Paseo nor BooCode (nor openchamber, nor goose's ACP) verifies the session/transcript exists on disk before resuming — true for opencode, claude, qwen. Folds into v2.6 Phase 3 (crash recovery + active supervision, now lifting from openchamber §5c). Decide whether "resume blindly, recover on failure" is good enough for single-user, or worth a pre-resume existence check. Caveat: goose ACP exposes no loadSession/resume (§5n) → its cross-restart resume needs a different design than opencode's.
  5. Usage and status normalization scope. Two converging gaps: (a) tokens/cost — the opencode token slice (#8) converges with paseo AgentUsage; (b) liveness/status — superset's notify-hook pattern (§5j, #10) is the only way to know whether a one-shot PTY agent (goose/qwen/claude) is working / blocked-on-permission / done. Decide whether to design one normalized per-(chat,agent) "agent telemetry" shape (tokens + status) up front so all providers slot in, or ship opencode-token-only and generalize at Phase 2.
  6. Correction — ACP SDK package. This doc and the roadmap state BooCode uses @zed-industries/agent-client-protocol; the live apps/coder/package.json actually declares @agentclientprotocol/sdk@^0.22.1 (verified installed). Both amp-acp and pi-acp use the same package, so the "version-drift" worry is moot. Worth correcting in boocode_roadmap.md's lift table on the next pass.

7. Housekeeping

  • Stale .bak in the working tree: apps/server/src/services/inference/tool-phase.ts.bak-20260531 (today, 15.5 KB). Violates CLAUDE.md's "don't accumulate .bak-*". Dated today and tool-phase.ts is on the active path — may be an in-progress safety copy. Confirm before removing.
  • Unshallow /opt/forks/llama.cpp (git fetch --unshallow) before the next review so commit-level attribution is possible. (opencode was unshallowed mid-review; cline/qwen-code/amp-acp/pi-acp/claude-code/goose/unsloth remain shallow but their source was intact.)
  • Grep BooCode install docs/scripts for block/goose URLs — goose moved to aaif-goose/goose (§5n); old release URLs will eventually 404.
  • Correct the ACP-SDK package name in boocode_roadmap.md's lift table → @agentclientprotocol/sdk@0.22.1 (§6.6).

8. Roadmap mapping (where each actionable lands)

Roadmap slot Items from this review
v2.6 Phase 2 (warm ACP goose/qwen) #2 warm-ACP backend — validated by qwen's own qwen --acp (§5f); #7 parse qwen/claude stream-json in the one-shot fallback
v2.6 Phase 3 (lifecycle hardening) #5 openchamber lifecycle hardening (health monitor + crash restart + port reclaim + stall-SSE — §5c, supersedes the paseo re-derive); worktree-archive cascade (paseo) + superset destroy-saga (§5j); LRU-bound caches; pre-resume session verification
v2.6 Phase 1 UX #6 interrupt-bug fix; #8 opencode token/ctx usage; richer SSE arms (compaction surfacing)
Write/edit robustness (NEW batch) #3 fuzzy patch applier + #4 git-stash checkpoint (cline §5b) — both directly harden BooCoder's edit/rewind surface for local models
Cross-agent telemetry (NEW) #10 superset notify-hook → normalized status for PTY agents (§5j); pairs with #8 token usage
Standalone claude-provider batch #9 --resume via hook/jsonl-watcher (§5i) + the SDK-vs-PTY decision (now lean-SDK, §6.2); #12 MistakeTracker + file-provenance ledger (cline)
Inference / license-debt batch #1 AGPL parser retirement (AGPL confirmed §5k; gated on the jinja check §6.1); #11 sampling/reasoning-budget config adopts
BooChat resilience (opportunistic) stall-timeout + retry/backoff (opencode); tool-pair-atomic prune cross-check (cline §5b)
Provider catalog amp-acp = keep as add-from-catalog smoke test only (§5m); pi-acp = WATCH for a local-provider mode
Deferred / gated subagent permission demux (needs opencode-SSE permission cards first); MCP auth lock (needs OAuth MCP un-deferred); qwen serve HTTP backend (stdio-ACP cheaper)
Not actionable conductor (wrong scale — only the retry-taxonomy reference §5l); claude-code public repo (docs only §5n)