# OpenCode V2 Migration and Desktop Restructuring
## Summary
This branch replaces CodeNomad's OpenCode V1 SDK, custom plugin, and
per-workspace runtime architecture with the native OpenCode V2 client
and one shared OpenCode service. It intentionally ships no V1 runtime
fallback.
The scope includes native location ownership, Forms and Shell resources,
project-wide cursor pagination, bounded resident message windows,
streaming reconciliation, duplicate-folder instances, multi-window
Electron/Tauri behavior, content-addressed restore, worktree mutation
fencing, and reproducible desktop packaging.
The reviewed implementation head is `dea20996`. UI and server resolve
`@opencode-ai/client@beta` to `beta-18999`; the runtime CLI is managed
independently. The official comparison baseline remains `upstream/beta`
at `eb1ac54d73`.
Full details: [`MIGRATION_V2.md`](./MIGRATION_V2.md),
[`DESKTOP_V2_COMPARISON.md`](./DESKTOP_V2_COMPARISON.md), and
[`dev-docs/DEV_V2_CODE_REDUCTION.md`](./dev-docs/DEV_V2_CODE_REDUCTION.md).
## Stabilization Fixes
- Preserve manual scroll escape across pagination, remote updates,
capped-window shifts, tab changes, and desktop restore; only a local
prompt submission forces the bottom.
- Keep the timeline resident window capped at 200 messages. Ordered
window slides use Virtua shift, while reorder, pagination, and
non-aligned replacement remount with a fresh measurement epoch.
- Finalize the temporary `200 -> 201 -> 200` transition in a
generation-guarded microtask before paint and compensate followed
content growth from a `ResizeObserver` attached to the mounted Virtua
root.
- Keep all pending inbox prompts after delivered transcript messages in
native inbox admission order.
- Add a persisted `steer`/`queue` follow-up preference; the alternate
shortcut uses the inverse while idle sends remain `steer`.
- Edit a pending prompt only after authoritative inbox cancellation
succeeds, then restore its text, structured payload, files, and agent
references to the composer.
- Expose native `session.background` through the ownership-checked
proxy, a prompt action, and `Ctrl/Cmd+B`.
- Remove the duplicate model-selector "show all" action and make the
favorites toggle label reflect its current action.
- Restore permission/Form synchronization plus skill, reference,
MCP-resource, and websearch-provider reads in the reviewed proxy
allowlist.
- Validate and preserve native location workspace identities for
root/worktree requests, session moves/imports, cursors, and global
Forms.
## Capability Decisions
| Capability | Native V2 availability | CodeNomad `DEV-v2` decision |
Revisit or complete when |
| --- | --- | --- | --- |
| Assistant content mutation | `session.messageUpdate` authoritatively
replaces the text, reasoning, and tool content of a completed assistant
message. There is still no generic deletion of a complete delivered
message or mutation of user messages. | Restores individual
tool/reasoning deletion through the native update route. Arbitrary
whole-message deletion remains absent rather than locally simulated. |
Add broader deletion only if V2 exposes an authoritative operation for
the required message type. |
| Bulk tool and reasoning cleanup | No native bulk operation, but
`session.messageUpdate` can safely compose cleanup one assistant message
at a time. | Restores selected-group and full-session technical-part
cleanup through authoritative per-message updates. | A native bulk
operation is only needed if per-message updates become a measured
performance problem. |
| Delete-to-boundary / undo | `session.revert.stage` and
`session.revert.clear` use V2 staged-revert semantics instead of
arbitrary deletion. | Command-palette Undo uses `revert.stage`; Redo
clears the staged revert through `revert.clear`. | Revisit only if V2
adds broader authoritative transcript deletion. |
| Compaction | Native checkpoint compaction summarizes the older head
and retains a server-selected recent tail controlled by
`compaction.keep.tokens`. | Uses `session.compact`; there is no
message-level selective compaction. CodeNomad displays the partial
summary through the same reactive streaming path as text and reasoning,
then replaces it with the terminal summary. | Add scoped controls only
if V2 defines scoped compaction semantics. |
| Transcript pagination authority | Message pages expose only opaque
previous/next cursors. They provide no transcript revision, total,
absolute range, position, or random seek target. | Uses bounded cursor
traversal and a 200-message resident window, with defensive
reconciliation after destructive events. It cannot prove that pages
loaded across compaction or revert belong to one snapshot. | V2 adds
snapshot revision authority
([#43766](https://github.com/anomalyco/opencode/issues/43766)) and
navigable position metadata
([#44660](https://github.com/anomalyco/opencode/issues/44660)). |
| Full-session search | `session.list(search)` filters session titles
only. There is no server transcript-search endpoint returning message
identity, excerpt, navigable position, and transcript revision. |
Retained through exhaustive message-cursor traversal while keeping only
the 200-message resident window and collected matches. Large searches
still fetch every page. | V2 exposes transcript search
([#45801](https://github.com/anomalyco/opencode/issues/45801)) with a
target that composes with transcript revision and seek metadata. |
| Queued prompt management | Native inbox list, cancel, steer, and queue
operations cover authoritative follow-up delivery. The TUI's edit action
cancels a queued prompt before restoring it to the composer; it is not
an atomic inbox update. | Implements persisted primary `steer`/`queue`
delivery, inverse alternate shortcut, delivery switching, cancellation,
cancel-first composer restoration with structured payload retention, and
native-order timeline projection. | Revisit atomic editing or reordering
only if V2 adds an authoritative operation and a concrete product need
is established. |
| Background execution | Native `session.background` moves blocking
tools out of the foreground; Shell resources separately support listing,
bounded output, and removal. | Exposes `session.background` through the
proxy and UI with `Ctrl/Cmd+B`, and replaces the custom process manager
with native Shells. Unsupported controls such as rename remain removed.
| Add controls only when the native session or Shell APIs support them.
|
| Service lifecycle | V2 uses one shared externally owned service rather
than one runtime per workspace. | CodeNomad discovers or starts the
service. Stop Workspace evicts the native location after its final
logical owner is removed; application shutdown never stops the daemon. |
No parity work planned unless V2 changes service ownership semantics. |
## Validation
Migration gate (`878550ca`):
- UI and server TypeScript typechecks.
- 86 focused UI tests covering follow, pagination, queue ordering,
bottom pinning, shortcuts, delivery resolution, and model visibility.
- 64 focused server tests covering proxy ownership/location enforcement
and shared-service workspace identity.
- Production UI/server build.
- Tauri `cargo check` and all 121 Rust tests.
- `git diff --check`.
Timeline stabilization (`dea20996`):
- UI TypeScript typecheck and all 68 focused timeline, pagination,
request-authority, and restore tests.
- Tauri release build against the `beta-18999` lock.
- Native Developer Mode validation: no remount or empty frame during
capped shifts, same-cycle growth compensation, preserved manual escape,
and inactive-tab anchor restore within 0.3125 px.
## Remaining Gaps
- Active-session-location authority for MCP/plugin status.
- Optional interactive PTY, session export, and reference/MCP-resource
attachment UI.
- Desktop release signing/notarization hardening.
6.3 KiB
MVP Development Principles
Core Philosophy
Focus on functionality, NOT performance.
The MVP (Minimum Viable Product) is about proving the concept and getting feedback. Performance optimization comes later, after we validate the product with real users.
What We Care About in MVP
✅ DO Focus On:
-
Functionality
- Does it work?
- Can users complete their tasks?
- Are all core features present?
-
Correctness
- Does it produce correct results?
- Does error handling work?
- Is data persisted properly?
-
User Experience
- Is the UI intuitive?
- Are loading states clear?
- Are error messages helpful?
-
Stability
- Does it crash?
- Can users recover from errors?
- Does it lose data?
-
Code Quality
- Is code readable?
- Are types correct?
- Is it maintainable?
❌ DON'T Focus On:
-
Performance Optimization
- Virtual scrolling
- Message batching
- Lazy loading
- Memory optimization
- Render optimization
-
Scalability
- Handling 1000+ messages
- Multiple instances with 100+ sessions
- Large file attachments
- Massive search indexes
-
Advanced Features
- Plugins
- Advanced search
- Custom themes
- Workspace management
Specific MVP Guidelines
Messages & Rendering
Simple approach:
// Just render everything - no virtual scrolling
<For each={messages()}>
{(message) => <MessageItem message={message} />}
</For>
Don't worry about:
- Sessions with 500+ messages
- Re-render performance
- Memory usage
- Scroll performance
When to optimize:
- Post-MVP (Phase 8)
- Only if users report issues
- Based on real-world usage data
State Management
Simple approach:
- Use SolidJS signals directly
- No batching
- No debouncing
- No caching layers
Don't worry about:
- Update frequency
- Number of reactive dependencies
- State structure optimization
Process Management
Simple approach:
- Spawn servers as needed
- Kill on close
- Basic error handling
Don't worry about:
- Resource limits (max processes)
- CPU/memory monitoring
- Restart optimization
- Process pooling
API Communication
Simple approach:
- Direct generated Promise client calls
- Basic error handling
- Simple retry (if at all)
Don't worry about:
- Request batching
- Response caching
- Optimistic updates
- Request deduplication
Decision Framework
When implementing any feature, ask:
Is this optimization needed for MVP?
NO if:
- It only helps with large datasets
- It only helps with many instances
- It's about speed, not correctness
- Users won't notice the difference
- It adds significant complexity
YES if:
- Users can't complete basic tasks without it
- App is completely unusable without it
- It prevents data loss
- It's a security requirement
Examples
Virtual Scrolling: ❌ NO for MVP
- MVP users won't have 1000+ message sessions
- Simple list rendering works fine for <100 messages
- Add in Phase 8 if needed
Error Handling: ✅ YES for MVP
- Users need clear feedback when things fail
- Prevents frustration and data loss
- Core to usability
Message Batching: ❌ NO for MVP
- SolidJS handles updates efficiently
- Only matters at very high frequency
- Add later if users report lag
Session Persistence: ✅ YES for MVP
- Users expect sessions to persist
- Losing work is unacceptable
- Core functionality
Testing Approach
MVP Testing Focus
Test for:
- ✅ Correctness (does it work?)
- ✅ Error handling (does it fail gracefully?)
- ✅ Data integrity (is data saved?)
- ✅ User flows (can users complete tasks?)
Don't test for:
- ❌ Performance benchmarks
- ❌ Load testing
- ❌ Stress testing
- ❌ Scalability limits
Acceptable Performance
For MVP, these are acceptable:
- 100 messages render in 1 second
- UI slightly laggy during heavy streaming
- Memory usage grows with message count
- Multiple instances slow down app
These become unacceptable only if:
- Users complain
- App becomes unusable
- Basic tasks can't be completed
When to Optimize
Post-MVP Triggers
Add optimization when:
-
User Feedback
- Multiple users report slowness
- Users abandon due to performance
- Performance prevents usage
-
Measurable Issues
- App freezes for >2 seconds
- Memory usage causes crashes
- UI becomes unresponsive
-
Phase 8 Reached
- MVP complete and validated
- User base established
- Performance becomes focus
How to Optimize
When the time comes:
-
Measure First
- Profile actual bottlenecks
- Use real user data
- Identify specific problems
-
Target Fixes
- Fix the specific bottleneck
- Don't over-engineer
- Measure improvement
-
Iterate
- Optimize one thing at a time
- Verify with users
- Stop when "fast enough"
Communication with Users
During Alpha/Beta
Be honest about performance:
- "This is an MVP - expect some slowness with large sessions"
- "We're focused on functionality first"
- "Performance optimization is planned for v1.x"
Set expectations:
- Works best with <200 messages per session
- Multiple instances may slow things down
- We'll optimize based on your feedback
Collecting Feedback
Ask about:
- ✅ What features are missing?
- ✅ What's confusing?
- ✅ What doesn't work?
- ✅ Is it too slow to use?
Don't ask about:
- ❌ How many milliseconds for X?
- ❌ Memory usage specifics
- ❌ Benchmark comparisons
Summary
The MVP Mantra
Make it work, then make it better, then make it fast.
For CodeNomad MVP:
- Phase 1-7: Make it work, make it better
- Phase 8+: Make it fast
Remember
- Premature optimization is the root of all evil
- Real users provide better optimization guidance than assumptions
- Functionality > Performance for MVP
- You can't optimize what users don't use
Quick Reference
When in doubt, ask:
- Is this feature essential for users to do their job? → Build it
- Is this optimization essential for the feature to work? → Build it
- Is this just making it faster/more efficient? → Defer to Phase 8
MVP = Minimum Viable Product
- Viable = works and is useful
- Viable ≠ optimized and fast