a789495a98
FreeBSD Smoke / FreeBSD Smoke (x86_64) (push) Has been cancelled
CI / Quality Guardrails (push) Has been cancelled
CI / Build & Test (macos-latest) (push) Has been cancelled
CI / Build & Test (ubuntu-latest) (push) Has been cancelled
CI / Build & Test (windows-latest) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / PowerShell Syntax (push) Has been cancelled
CI / Windows Cross-Target Check (Linux) (push) Has been cancelled
487 lines
14 KiB
Markdown
487 lines
14 KiB
Markdown
# Jcode Desktop Architecture Direction
|
|
|
|
Status: Proposed
|
|
Updated: 2026-04-25
|
|
|
|
This document captures the initial direction for a desktop application for Jcode under these constraints:
|
|
|
|
- no Electron/Tauri/web-app shell
|
|
- no general UI framework
|
|
- very high performance
|
|
- low idle resource use
|
|
- very custom product UI
|
|
- primary developer machine may be Linux
|
|
- most early users are expected to be on macOS
|
|
|
|
The goal is to make the desktop client a first-class Jcode surface without forking the Jcode runtime or turning the app into a heavyweight IDE clone.
|
|
|
|
See also:
|
|
|
|
- [`DESKTOP_STABLE_HOST_RELOAD_STARTUP.md`](./DESKTOP_STABLE_HOST_RELOAD_STARTUP.md)
|
|
- [`DESKTOP_SUPERAPP_WORKSPACE.md`](./DESKTOP_SUPERAPP_WORKSPACE.md)
|
|
- [`DESKTOP_CODEBASE_ARCHITECTURE.md`](./DESKTOP_CODEBASE_ARCHITECTURE.md)
|
|
- [`CLIENT_CORE_PRESENTATION_SPLIT_PLAN.md`](./CLIENT_CORE_PRESENTATION_SPLIT_PLAN.md)
|
|
- [`MULTI_SESSION_CLIENT_ARCHITECTURE.md`](./MULTI_SESSION_CLIENT_ARCHITECTURE.md)
|
|
- [`SERVER_ARCHITECTURE.md`](./SERVER_ARCHITECTURE.md)
|
|
- [`MEMORY_BUDGET.md`](./MEMORY_BUDGET.md)
|
|
|
|
## Executive summary
|
|
|
|
Build Jcode Desktop as a small Rust desktop client with a custom GPU-rendered UI. The app should connect to a local Jcode server/daemon that owns sessions, tools, agent execution, persistence, and permissions.
|
|
|
|
The frontend should be optimized as a render/input surface:
|
|
|
|
- Linux should be a first-class development platform.
|
|
- macOS should be the first-class product/distribution platform.
|
|
- The UI should not depend on Linux-only desktop concepts.
|
|
- The UI should not be a web view.
|
|
- The UI should not embed the agent runtime directly.
|
|
- Rendering should be on-demand, virtualized, and measurable from day one.
|
|
|
|
Recommended initial stack:
|
|
|
|
| Area | Decision |
|
|
|---|---|
|
|
| Frontend language | Rust |
|
|
| Backend/runtime | Existing Rust Jcode server/session runtime |
|
|
| Process model | Desktop frontend + local Jcode daemon/server |
|
|
| Window/input layer | Thin platform layer, likely `winit` initially |
|
|
| Rendering | `wgpu` with a custom 2D renderer |
|
|
| UI architecture | Retained UI tree with dirty tracking |
|
|
| Layout | Small custom layout system, not CSS/DOM |
|
|
| Text | Dedicated text layout/raster cache, likely `cosmic-text`/`swash` or platform-backed text later |
|
|
| Protocol | Versioned typed local event protocol |
|
|
| Persistence | Server-owned session/event persistence |
|
|
| Product identity | Agent operating console / mission control |
|
|
|
|
## Product stance
|
|
|
|
Jcode Desktop should not start as a full IDE and should not look like a conventional chatbot.
|
|
|
|
The differentiated product is a **keyboard-driven, Niri-like agent workspace superapp** for local development. The first-class object is not a chat window, but a workspace containing many navigable surfaces:
|
|
|
|
- agent sessions
|
|
- activity/task views
|
|
- diffs and changed files
|
|
- file/diff/tool surfaces
|
|
- optional future surfaces
|
|
- settings/debug/tool surfaces
|
|
|
|
The app should help users:
|
|
|
|
- supervise autonomous coding work
|
|
- inspect tool activity
|
|
- manage background tasks
|
|
- review changed files
|
|
- respond to permission prompts
|
|
- resume and coordinate sessions
|
|
- navigate many related surfaces spatially
|
|
|
|
The desktop client should complement the TUI/CLI, not replace it.
|
|
|
|
## Platform strategy
|
|
|
|
### Development host: Linux
|
|
|
|
Linux should support the fastest inner loop:
|
|
|
|
- launch the desktop client locally
|
|
- run renderer stress tests
|
|
- run protocol integration tests
|
|
- benchmark memory/frame/layout/text performance
|
|
- debug the UI engine without a Mac in the loop
|
|
|
|
The Linux build should be real, not a fake simulator. It should render through the same UI engine and exercise the same protocol/view-model paths as macOS.
|
|
|
|
### Product target: macOS first
|
|
|
|
Most early users are expected to be on macOS, so macOS polish should be a product requirement even if day-to-day development happens on Linux.
|
|
|
|
Mac-specific work that should not be postponed too long:
|
|
|
|
- native `.app` bundle
|
|
- app icon and menu bar integration
|
|
- command-key shortcuts
|
|
- system light/dark appearance
|
|
- Retina rendering correctness
|
|
- trackpad scrolling quality
|
|
- native clipboard behavior
|
|
- file/open-with integration
|
|
- code signing and notarization path
|
|
- good behavior under Mission Control, Spaces, and full-screen windows
|
|
|
|
### Avoid Linux-shaped product assumptions
|
|
|
|
Because the developer may use Linux, the architecture should explicitly avoid baking in assumptions that work well only with a Linux window manager.
|
|
|
|
Do not make these hard dependencies:
|
|
|
|
- Niri-style external spatial window management
|
|
- X11-specific APIs
|
|
- Wayland-only behavior
|
|
- terminal-first session workflows
|
|
- Linux notification semantics
|
|
- global shortcuts that are unavailable or hostile on macOS
|
|
|
|
The existing Linux/Niri workflow should remain excellent, but desktop product quality should be judged primarily against macOS expectations.
|
|
|
|
## Process architecture
|
|
|
|
Use a split process architecture:
|
|
|
|
```text
|
|
Jcode Desktop Frontend
|
|
- window/input
|
|
- custom rendering
|
|
- local view model
|
|
- transient UI state
|
|
- surface-local state
|
|
- protocol client
|
|
|
|
Jcode Server/Daemon
|
|
- sessions
|
|
- agent runtime
|
|
- tool runtime
|
|
- background tasks
|
|
- persistence
|
|
- permissions
|
|
- model/provider configuration
|
|
```
|
|
|
|
The server remains the source of truth for:
|
|
|
|
- canonical session history
|
|
- streaming events
|
|
- tool execution
|
|
- file edits
|
|
- background tasks
|
|
- permission state
|
|
- persisted configuration
|
|
|
|
The desktop frontend owns only surface-local state:
|
|
|
|
- selected session/surface
|
|
- draft input
|
|
- cursor and text selection
|
|
- scroll offsets
|
|
- pane sizes
|
|
- focused panel
|
|
- local command palette state
|
|
- render caches
|
|
|
|
This aligns with the multi-session model where a server-owned session can be shown by different clients or surfaces over time.
|
|
|
|
## Local protocol direction
|
|
|
|
The desktop app should consume a versioned, typed event stream rather than periodically fetching complete session snapshots.
|
|
|
|
Early protocol properties:
|
|
|
|
- local-first transport
|
|
- explicit protocol version
|
|
- capability negotiation
|
|
- append-only session events
|
|
- streaming deltas for assistant/tool output
|
|
- resumable subscriptions by event cursor
|
|
- compact events for high-volume tool output
|
|
- server-owned permission requests
|
|
|
|
Possible transports:
|
|
|
|
1. Existing Jcode server channel, if compatible with desktop needs.
|
|
2. Unix domain socket on Linux/macOS and named pipe on Windows.
|
|
3. Stdio JSON protocol for early prototypes and test harnesses.
|
|
|
|
Avoid localhost HTTP as the default unless there is a strong reason. It creates a larger local security surface than a user-owned socket/pipe.
|
|
|
|
Example event families:
|
|
|
|
```text
|
|
session.created
|
|
session.updated
|
|
surface.attached
|
|
message.created
|
|
message.delta
|
|
message.completed
|
|
tool.started
|
|
tool.output.delta
|
|
tool.completed
|
|
task.started
|
|
task.progress
|
|
task.completed
|
|
workspace.changed
|
|
git.changed
|
|
permission.requested
|
|
permission.resolved
|
|
error
|
|
```
|
|
|
|
## Rendering architecture
|
|
|
|
Use a custom renderer rather than a native widget hierarchy or web view.
|
|
|
|
Recommended layers:
|
|
|
|
```text
|
|
Platform window/input
|
|
-> input normalizer
|
|
-> app state/view model
|
|
-> retained UI tree
|
|
-> layout
|
|
-> text layout/cache
|
|
-> display list
|
|
-> GPU renderer
|
|
```
|
|
|
|
Core rules:
|
|
|
|
- no continuous render loop when idle
|
|
- render only on input, data events, animations, or explicit invalidation
|
|
- virtualize every unbounded list
|
|
- separate layout cost from paint cost
|
|
- cache shaped text by content/font/width
|
|
- use stable IDs for dirty tracking
|
|
- make debug/performance counters visible in-app
|
|
|
|
The renderer should initially support:
|
|
|
|
- rectangles
|
|
- rounded rectangles
|
|
- borders
|
|
- solid fills
|
|
- clipping
|
|
- scroll containers
|
|
- text runs
|
|
- monospaced blocks
|
|
- simple icons or vector-like primitives
|
|
- image support later
|
|
|
|
Defer:
|
|
|
|
- blur effects
|
|
- complex shadows
|
|
- animation framework
|
|
- SVG-heavy rendering
|
|
- full markdown renderer
|
|
- full terminal emulator
|
|
- embedded code editor
|
|
|
|
## UI architecture
|
|
|
|
Use a retained UI tree with immediate-style builder ergonomics.
|
|
|
|
Rationale:
|
|
|
|
- transcripts are long-lived and streamed incrementally
|
|
- tool outputs can be large
|
|
- panes need stable focus/selection state
|
|
- dirty tracking matters for resource use
|
|
- accessibility will eventually need stable semantic nodes
|
|
- multi-session surfaces need stable identity
|
|
|
|
The model should not imitate the DOM/CSS stack. A small product-specific layout system is enough:
|
|
|
|
- row
|
|
- column
|
|
- stack
|
|
- split pane
|
|
- fixed size
|
|
- flex fill
|
|
- scroll container
|
|
- virtual list
|
|
- overlay/modal
|
|
- intrinsic text measurement
|
|
|
|
## Text strategy
|
|
|
|
Text is one of the hardest parts of this project and should be treated as a core system, not a detail.
|
|
|
|
The desktop client needs:
|
|
|
|
- Unicode shaping
|
|
- font fallback
|
|
- monospace code/tool output
|
|
- wrapping
|
|
- incremental append layout
|
|
- selection/copy
|
|
- input cursor behavior
|
|
- command palette text input
|
|
- markdown-ish transcript styling
|
|
- ANSI-like tool output styling eventually
|
|
|
|
Initial recommendation:
|
|
|
|
- use a Rust text stack such as `cosmic-text`/`swash` if dependency review is acceptable
|
|
- maintain a GPU glyph atlas
|
|
- cache shaped lines/runs by stable block ID and available width
|
|
- specialize streamed append paths so new output does not re-layout the whole transcript
|
|
|
|
Mac-specific text quality should be evaluated early. If Rust text rendering is not good enough on macOS, consider platform-backed text for macOS while preserving the same higher-level text layout API.
|
|
|
|
## Performance and resource budgets
|
|
|
|
Initial budgets should be measured on both Linux development machines and representative macOS hardware.
|
|
|
|
| Metric | MVP target | Long-term target |
|
|
|---|---:|---:|
|
|
| Cold launch to visible window | < 500 ms | < 150 ms |
|
|
| Frontend idle CPU | ~0% | ~0% |
|
|
| Frontend idle RSS | < 100 MiB | < 50 MiB |
|
|
| Input-to-paint latency | < 32 ms | < 16 ms |
|
|
| Scrolling | 60 fps | 120 fps-capable |
|
|
| Fake transcript stress case | 100k blocks usable | 100k blocks smooth |
|
|
| Full transcript re-layout on append | forbidden | forbidden |
|
|
| Unbounded retained visible nodes | forbidden | forbidden |
|
|
| Renderer frame when idle | forbidden | forbidden |
|
|
|
|
Required early instrumentation:
|
|
|
|
- frame time
|
|
- layout time
|
|
- text shaping time
|
|
- display-list build time
|
|
- GPU submit time
|
|
- visible node count
|
|
- total retained node count
|
|
- glyph atlas size
|
|
- text cache size
|
|
- protocol event backlog
|
|
- daemon round-trip latency
|
|
- frontend RSS if available
|
|
|
|
A debug HUD should exist in the prototype before real Jcode integration is considered complete.
|
|
|
|
Example HUD:
|
|
|
|
```text
|
|
frame 1.8ms | layout 0.3ms | text 0.6ms | gpu 0.4ms
|
|
nodes 812 | visible 47 | glyph atlas 12.4 MiB | events 0 | daemon 2ms
|
|
```
|
|
|
|
## MVP scope
|
|
|
|
The first UI milestone should prove the engine before proving every product workflow.
|
|
|
|
### Milestone 1: custom shell with fake data
|
|
|
|
Success criteria:
|
|
|
|
- launches a native desktop window from Linux
|
|
- renders through the custom GPU pipeline
|
|
- shows session sidebar, transcript, composer, and activity panel
|
|
- handles mouse, keyboard, focus, and scrolling
|
|
- renders fake streamed transcript data
|
|
- virtualizes a 100k-block transcript
|
|
- idles at near-zero CPU
|
|
- exposes performance/debug HUD
|
|
- has screenshot or golden-state tests where practical
|
|
|
|
### Milestone 2: protocol connection
|
|
|
|
Success criteria:
|
|
|
|
- connects to local Jcode server/daemon
|
|
- lists sessions
|
|
- attaches to a session/surface
|
|
- subscribes to event stream
|
|
- sends a user prompt
|
|
- streams assistant/tool events into the transcript
|
|
- can stop/cancel an active run
|
|
- recovers from daemon restart or disconnect gracefully enough for development use
|
|
|
|
### Milestone 3: useful agent console
|
|
|
|
Success criteria:
|
|
|
|
- activity center for background tasks/tool calls
|
|
- permission request overlay
|
|
- workspace/git status panel
|
|
- changed-file list
|
|
- open external editor/diff action
|
|
- session search/filter
|
|
- macOS app bundle prototype
|
|
|
|
## Crate layout proposal
|
|
|
|
Do not put the whole desktop app in the root crate.
|
|
|
|
Suggested structure:
|
|
|
|
```text
|
|
crates/
|
|
jcode-desktop-protocol/ # shared protocol/event types if not already covered by server types
|
|
jcode-desktop-ui/ # UI tree, layout, text/cache abstractions, renderer-agnostic pieces
|
|
jcode-desktop-renderer/ # wgpu renderer and GPU resources
|
|
jcode-desktop/ # app shell, platform window, protocol client, product UI
|
|
```
|
|
|
|
If compile time becomes a problem, keep protocol/UI crates lightweight and gate GPU/window dependencies behind the final app crate.
|
|
|
|
## Dependency policy
|
|
|
|
“No frameworks” does not have to mean “no libraries.” It should mean no heavyweight app framework and no web-shell product architecture.
|
|
|
|
Likely acceptable dependencies:
|
|
|
|
- `wgpu` for rendering abstraction
|
|
- a very thin window/input layer such as `winit` for bootstrapping
|
|
- `cosmic-text`/`swash` or equivalent for text shaping/rasterization
|
|
- small serialization/protocol crates already consistent with Jcode
|
|
|
|
Avoid:
|
|
|
|
- Electron
|
|
- Tauri
|
|
- Qt
|
|
- Flutter
|
|
- GTK as the app framework
|
|
- WebView UI shell
|
|
- React/Vue/Svelte-style UI stack
|
|
- CSS/DOM-based architecture
|
|
|
|
If `winit` becomes limiting for macOS polish, the platform layer can grow direct AppKit support while preserving the renderer and UI model.
|
|
|
|
## macOS validation checklist
|
|
|
|
Because macOS is the primary user target, validate these early even if development happens on Linux:
|
|
|
|
- Retina scale factor correctness
|
|
- trackpad inertial scrolling
|
|
- text clarity compared with native apps
|
|
- keyboard shortcuts use Command rather than Control where appropriate
|
|
- system dark/light mode follows user preference
|
|
- window resizing and full-screen behavior feels native
|
|
- app menu and close/minimize/quit semantics are correct
|
|
- clipboard round-trips rich enough for code and transcripts
|
|
- local socket permissions are safe
|
|
- app bundle can launch/find the daemon reliably
|
|
|
|
## Open decisions
|
|
|
|
These should be resolved before implementation moves past the fake-data prototype:
|
|
|
|
1. Use `winit` initially or write direct platform shells from the start?
|
|
2. Use `wgpu` or direct Metal-first rendering?
|
|
3. Use `cosmic-text`/`swash` or platform text APIs?
|
|
4. Reuse the existing Jcode server protocol or introduce a desktop-specific event protocol crate?
|
|
5. Should the first desktop binary support multi-surface mode or only one active surface?
|
|
6. What is the minimum macOS version to support?
|
|
7. What is the first distribution path: local `.app`, Homebrew cask, or signed/notarized DMG?
|
|
|
|
## Recommended immediate next step
|
|
|
|
Create a fake-data desktop prototype that runs on Linux but measures the exact performance characteristics required by the eventual macOS product.
|
|
|
|
The prototype should not wait for a perfect daemon API. It should validate the expensive UI systems first:
|
|
|
|
- window creation
|
|
- renderer startup
|
|
- retained tree
|
|
- layout
|
|
- text cache
|
|
- virtualized transcript
|
|
- on-demand repaint
|
|
- debug HUD
|
|
|
|
Only after that should the real Jcode event stream be connected.
|