Strategic Analysis: Fork Maintenance
Our fork (randomm/opencode) has diverged from upstream (anomalyco/opencode) with 93 files changed (56 new, 33 modified, 4 deleted, +6,597/-1,222 lines). This issue documents findings and recommended strategy to reduce maintenance burden while preserving our key differentiators.
Our Three Differentiators
1. Non-blocking Async Task Tool (HIGH maintenance burden)
What: Tasks run asynchronously and return immediately. Parent agent continues working while tasks execute in background. Includes slot-based concurrency (max 5), check_task polling tool, and auto-wakeup on completion.
Scope:
tool/task.ts — 238 lines changed (+158 insertions)
session/index.ts — 603 lines changed (+592 insertions) ← main conflict zone
session/prompt.ts — 356 lines refactored
tool/check_task.ts — 164 lines NEW
session/tools.ts — 221 lines NEW (extracted from prompt.ts)
util/tasks.ts — 68 lines NEW
Invasiveness: HIGHLY INVASIVE — deep session lifecycle changes in session/index.ts and session/prompt.ts, exactly the files upstream actively develops.
Upstream PR viability: Medium — requires architectural buy-in. Would need backward compatibility (blocking mode as option).
2. Lightweight TUI — oclite (LOW maintenance burden)
What: Separate minimal TUI. Currently implemented in two forms:
- Raw ANSI (
cli/lite/) — 527 lines, 6 files
- React/Ink (
cli/ink/) — ~1,840 lines, 35 files
Invasiveness: 100% ADDITIVE — all new files, zero modifications to upstream code.
Can be fully decoupled as standalone thin client:
- Infrastructure already exists:
opencode serve command, SDK --attach flag
- Replace
createInProcessFetch() with real HTTP fetch → ~2-3MB client binary
- Architecture:
opencode serve --port 4096 + oclite connects via SDK over HTTP
- Eliminates all TUI files from fork diff
Upstream PR viability: Easy — fully isolated, no conflicts.
3. rg Tool — Unified Search (LOW maintenance burden)
What: Replaces separate grep + glob tools with unified rg tool using ripgrep. Two modes: content search (default) and file listing (files_only=true).
Scope:
tool/rg.ts — 222 lines NEW
tool/rg.txt — 13 lines NEW
tool/registry.ts — 8 lines changed
- Deleted:
glob.ts, glob.txt, grep.ts, grep.txt
Invasiveness: LOW — clean replacement, only 8-line registry edit.
Upstream PR viability: High — clear improvement, simpler API, better performance.
Recommended Strategy: Decouple + Contribute + Minimize Fork
Step 1: Decouple oclite as standalone thin client
- Connect to vanilla
opencode serve via HTTP SDK
- ~2-3MB binary, zero backend dependencies
- Eliminates all 35+ TUI files from fork diff
Step 2: Contribute rg tool upstream as PR
- Clean improvement, easy to pitch
- Only 2 new files + 8-line registry edit
- Eliminates 6 files from fork diff
Step 3: Keep async task tool as focused fork
- This is the real differentiator worth maintaining
- Reduces fork surface from 93 files to ~10-15 files
- Use shuvcode-style automated sync for everything else
- Only conflict zone:
session/index.ts and session/prompt.ts
Net Result
Fork surface drops from 93 files to ~10-15 files. Upstream sync becomes manageable. Vanilla opencode improvements flow automatically for everything except the task system.
Alternative Strategies Considered
A: Upstream everything (eliminate fork)
- PR all three features upstream
- Pro: Zero maintenance burden
- Con: Async tasks require architectural buy-in, may be rejected or delayed
- Con: Loss of control over direction
B: Stay forked with automated sync (shuvcode approach)
- GitHub Actions workflow monitors upstream releases
- Auto-merge with conflict resolution rules
- Fork-specific files tracked in manifest
- Pro: Full control, automated 80% of syncs
- Con: Still 93 files to maintain, conflicts in session/* files
C: Plugin-based approach
- Async task tool as plugin
- Pro: Zero fork needed
- Con: Plugin hooks don't support core tool replacement or session lifecycle changes
- Con: rg tool and TUI can't be plugins
Active Fork Ecosystem (for reference)
| Fork |
Stars |
Relevance |
| Clouder0/overcode |
24 |
Most similar — async agents, parallel workers, inter-agent messaging |
| Latitudes-Dev/shuvcode |
66 |
Community QA layer — cherry-picks upstream PRs, automated sync |
| OneOfLzx/opencode-sentinel |
21 |
Enterprise/air-gapped deployment |
Key upstream PRs to watch:
Action Items
Strategic Analysis: Fork Maintenance
Our fork (
randomm/opencode) has diverged from upstream (anomalyco/opencode) with 93 files changed (56 new, 33 modified, 4 deleted, +6,597/-1,222 lines). This issue documents findings and recommended strategy to reduce maintenance burden while preserving our key differentiators.Our Three Differentiators
1. Non-blocking Async Task Tool (HIGH maintenance burden)
What: Tasks run asynchronously and return immediately. Parent agent continues working while tasks execute in background. Includes slot-based concurrency (max 5),
check_taskpolling tool, and auto-wakeup on completion.Scope:
tool/task.ts— 238 lines changed (+158 insertions)session/index.ts— 603 lines changed (+592 insertions) ← main conflict zonesession/prompt.ts— 356 lines refactoredtool/check_task.ts— 164 lines NEWsession/tools.ts— 221 lines NEW (extracted from prompt.ts)util/tasks.ts— 68 lines NEWInvasiveness: HIGHLY INVASIVE — deep session lifecycle changes in
session/index.tsandsession/prompt.ts, exactly the files upstream actively develops.Upstream PR viability: Medium — requires architectural buy-in. Would need backward compatibility (blocking mode as option).
2. Lightweight TUI — oclite (LOW maintenance burden)
What: Separate minimal TUI. Currently implemented in two forms:
cli/lite/) — 527 lines, 6 filescli/ink/) — ~1,840 lines, 35 filesInvasiveness: 100% ADDITIVE — all new files, zero modifications to upstream code.
Can be fully decoupled as standalone thin client:
opencode servecommand, SDK--attachflagcreateInProcessFetch()with real HTTP fetch → ~2-3MB client binaryopencode serve --port 4096+ocliteconnects via SDK over HTTPUpstream PR viability: Easy — fully isolated, no conflicts.
3. rg Tool — Unified Search (LOW maintenance burden)
What: Replaces separate
grep+globtools with unifiedrgtool using ripgrep. Two modes: content search (default) and file listing (files_only=true).Scope:
tool/rg.ts— 222 lines NEWtool/rg.txt— 13 lines NEWtool/registry.ts— 8 lines changedglob.ts,glob.txt,grep.ts,grep.txtInvasiveness: LOW — clean replacement, only 8-line registry edit.
Upstream PR viability: High — clear improvement, simpler API, better performance.
Recommended Strategy: Decouple + Contribute + Minimize Fork
Step 1: Decouple oclite as standalone thin client
opencode servevia HTTP SDKStep 2: Contribute rg tool upstream as PR
Step 3: Keep async task tool as focused fork
session/index.tsandsession/prompt.tsNet Result
Fork surface drops from 93 files to ~10-15 files. Upstream sync becomes manageable. Vanilla opencode improvements flow automatically for everything except the task system.
Alternative Strategies Considered
A: Upstream everything (eliminate fork)
B: Stay forked with automated sync (shuvcode approach)
C: Plugin-based approach
Active Fork Ecosystem (for reference)
Key upstream PRs to watch:
Action Items
createInProcessFetch()with HTTP SDK clientopencode serve