The status-bar branch bleed (T-421) is a symptom of a deeper gap: there is no single "open workspace X" primitive — only project.open() (in-place, same process, shared daemonBus) and newWindow() (blank detached process, no repo arg, no env scrub). T-367 and T-269 are the same root. - Q-51 (architecture): unify on WorkspaceService.open(root, target); open question of whether in-place switching survives at all vs a strict workspace⇒window⇒process⇒socket⇒bus⇒session-id 1:1 mapping. - T-422 epic owns the unification; T-421 reparented under it; T-423 builds the primitive and routes all entry points through it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
26 KiB
Open Questions — Architecture
IPC, events, canvas, window chrome, macOS signing, pql absorption, ticket persistence.
Q-1: Authorisation granularity on the IPC socket
- Status: Open
- Question: The daemon's token auth is coarse (allow all / deny all). Do we need per-subsystem grants later (e.g. restrict
git push), and if so, what's the model — capability tokens? An explicit grant table per client? Time-limited grants? - Context: Surfaced in the old ADR 0006 open-questions footer; deferred until Tier 1 is in real use.
- Triage (2026-05-17): Still open. Tier 1 has shipped but the IPC socket server itself is unimplemented (T-99). Re-evaluate once the socket lands and external CLI clients exist.
- Source: ADR 0006 (migrated to D-6).
Q-2: Back-pressure on event streams
- Status: Resolved → D-85
- Resolved (2026-06-06): Bounded per-subscriber ring buffer, drop-oldest, with a per-subscriber dropped-count surfaced as a gap marker — producer never blocks, subscribers never killed. The ring also serves the Q-3 cursor retention.
- Question: A subscriber that falls behind on
pane.output(a firehose) needs a policy: drop oldest, block producer, coalesce, or kill subscriber. Which? - Context: The event bus is in-memory; back-pressure policy is undefined. Defer until Tier 1 is in real use and we have a real firehose to measure against.
- Triage (2026-05-17): Still open. PTY panes ship and produce real firehoses, but no subscriber has fallen behind in observed use. Re-evaluate when a multi-client IPC scenario (T-99) makes this measurable.
- Source: ADR 0006 (migrated to D-6).
Q-3: Event persistence + audit/undo
- Status: Resolved → D-85
- Resolved (2026-06-06): In-memory cursor ring only in v1 (no disk); serves
clide events --since. If persistence is ever needed it is owned by the bus, not a subscriber-subsystem — reversing ADR 0006's unreasoned open-questions footer (it asserted "a subsystem that subscribes and writes — not a property of the bus" with no rationale, which is why it became this question). - Question: Events are in-memory only in v1. If a future need (audit log, undo history) wants persistence, is it a property of the bus or a subsystem that subscribes and writes?
- Context: ADR 0006 leaned "subsystem that subscribes and writes" but didn't commit.
- Triage (2026-05-17): Still open; no concrete trigger yet. Revisit when the first persistence requirement lands (likely Tier-6 audit/undo).
- Source: ADR 0006 (migrated to D-6).
Q-4: .canvas schema compatibility with Obsidian
- Status: Open — narrowed by D-91
- Question: Clide's canvas (Tier 5) should read/write something — either Obsidian's
.canvasJSON schema verbatim, a compatible-ish superset, or our own format. Each has trade-offs. - Context: Obsidian's canvas users might want their canvases portable; conversely, bending to Obsidian's schema constrains our canvas features.
- Narrowed (2026-06-10): D-91 sets the direction — clide's canvas uses its OWN HTML-
<canvas>-inspired JSON (the unified drawing-card schema), not Obsidian's.canvasnatively. Obsidian.canvasis treated as an import format, ingested by converting it into clide's JSON, so the same renderer can display it. What remains open here: the exact converter mapping and how lossless/round-trippable.canvasinterop needs to be. - Source: CLAUDE.md "Open questions" footer.
Q-5: IPC wire-format stability + schema_version:
- Status: Open
- Question: When do we freeze the IPC envelope / schema and introduce
schema_version:inpubspec.yaml? What's the bump policy for breaking changes? - Context: Covered partially by D-6's
v: 1starting point; CLAUDE.md flags this as "decide when the first real subcommand lands." - Source: CLAUDE.md "Open questions" footer.
Q-6: Window chrome — native frame vs frameless custom
- Status: Resolved → D-57
- Question: Does clide ship with the OS-native window frame (title bar, min/max/close from the WM) or a frameless custom chrome that gives us pixel control at the cost of reimplementing window controls per-platform?
- Context: Surfaced during Tier-0 plumbing discussion; resolved 2026-04-23 — frameless with per-column 24px hats.
- Source: 2026-04-21 planning.
Q-7: macOS app bundle signing / notarisation
- Status: Open
- Question: Distributing a signed macOS
.apprequires a Developer ID and a notarisation pipeline. Do we gate macOS builds on this (Tier 6), or ship unsigned with a known "right-click, open" user workflow for early testers? - Context: Linux is primary; macOS is a stretch target. Notarisation is a separate cost from the Flutter build.
- Source: 2026-04-21 planning.
Q-21: Pql absorbs planning vs keeps separate
- Status: Resolved → D-3 + D-39
- Question: Three shapes for planning tooling's long-term home: (A) Pql absorbs planning —
pql decisions …+pql ticket …subcommands; clide shells out. (B) Clide absorbs pql — reverse D-3, one big Dart tool. (C) Separate new binary just for planning. - Context: Resolved 2026-05-11 in favour of (A). pql 1.4.30 ships full planning surface (
pql decisions …,pql ticket …,pql plan …). Clide consumes via shell-out underlib/src/pql/. D-39 already encoded the intent; D-3 the wrap-don't-duplicate rule. The Python stopgap (D-40) was sunset on schedule. - Source: 2026-04-21 planning.
Q-23: SSH-remote development — run clide against a remote workspace
-
Resolved (2026-06-12): Shape (A) — execution remote, UI local — with the no-install ssh-exec footprint (user pick): stock OpenSSH only,
ssh -ttPTYs + ControlMaster exec channels, polling watcher, zero clide components on the remote (D-96). Naming/auth viassh://URI + system ssh in BatchMode (D-97); remote-tool contract with batched connect preflight (D-98); session + state identity re-keyed on (host, repo), amending D-41/D-77 (D-99). Implementation: T-329 epic, execution layer T-336. -
Question: Clide today assumes the workspace, the daemon, and the Flutter UI all run on the same machine. A growing class of users edits on remote systems (build servers, GPU boxes, cloud dev environments). What's the architecture for "open repo on host-B from UI on host-A"? Two shapes: (A) daemon-on-remote — clide's Dart daemon runs on the remote; the app talks to it over an SSH-tunnelled unix socket or a dedicated TCP socket (mTLS?), pty/process/filesystem work stays server-side; local app is pure UI. (B) filesystem-mounted — remote mounted via sshfs/9p/rclone, daemon runs locally against the mount; simpler but every fs op + git call crosses the network, and PTYs get complicated (local shell on remote filesystem? ssh-exec per command?). (A) matches VS Code Remote / JetBrains Gateway; (B) matches nothing load-bearing. Sub-questions either way: auth (ssh-agent? per-project keys? OIDC?), tmux / Claude session persistence semantics (does primary-per-repo re-key on host + repo?), multi-host identity in
.pql/pql.db, latency tolerance for the event stream, re-sync on disconnect. -
Context: Surfaced 2026-04-22 during Tier-1 planning. Not a Tier 1 concern — terminal + Claude panes land local-first — but the daemon/IPC seam decisions (notably
D-5andD-6) constrain the future answer. Worth scoping before Tier 6 (extension API) so third-party extensions don't accrue assumptions the remote path would have to unwind. The 2026-06-11 Fable review (fable-ous.md Part IV, Tier 3 #14) reframed the differentiator and ranked T-329 as undersold: the agent runs on the buildbox while permission prompts render natively local — VS Code Remote moves the editor; nobody remotes the agent control channel. That framing favours shape (A). -
Triage (2026-06-12): Shape (A) is effectively settled (T-329 epic locked: execution remote, UI + clipboard local, system ssh auth for v1). The model-independent backbone is proceeding: Phase 1 (T-331,
DaemonTransportseam) landed. What remains open is the footprint model — the user decision T-330 gates on:- No-install ssh-exec — zero remote footprint; stock
ssh -ttPTYs + ControlMaster command channels; watching degrades to polling; heavier subsystem surface locally. - Auto-pushed self-managed agent (VS Code Remote model) — clide deploys/version-checks a headless agent binary on connect; native inotify + stateful backend; but installs clide components on the remote, which the user has said they don't want to manage.
If (2), the agent sub-questions need answers before T-336 expands: placement (per-host
~/.clide/agentlikely), GC on disconnect/version-bump/repo-removal, multi-client sharing (IpcServer is already multi-connection, D-72), version skew (version-named binaries coexist). Either way the remote-tool contract needs a D-record: what must exist remotely (git/shell at minimum), whether pql is hard-required or degrades, and how a connect-preflight surfaces gaps. Evidence gap: the ControlMaster per-command latency probe (T-330) needs a reachable sshd — none in the dev environment; run it against a real remote before deciding if latency is the deciding factor. - No-install ssh-exec — zero remote footprint; stock
-
Source: 2026-04-22 planning (user-raised).
Q-22: Ticket persistence strategy
- Status: Resolved → D-67
- Question: Once Q-21 resolves in favour of (A), how do tickets handle shared team state? (1) Never commit (per-dev, ephemeral — works for solo). (2) Commit on milestone (settled-reach's sprint-close pattern — kanban has no natural equivalent,
releaseortier-cutis the closest). (3) Markdown mirror — every mutation writestickets/T-NNN.mdalongside SQLite; git-legible authoritative record; DB is rebuildable. (3) is probably the eventual answer. - Context: Resolved 2026-05-11 → option (3), evolved. Pql 1.4.x reshaped ticket persistence into append-only per-month
.pql/changelog/<table>/<YYYY-MM>.sqlfiles with inline LWW guards. Committed alongside code;pql.dbrebuildable from changelog +governance/*.md. Clide migrated on 2026-05-09. - Source: 2026-04-21 planning.
Q-25: Body text face — mono everywhere vs Josefin Sans UI + mono code
- Status: Open
- Question: The design handoff uses JetBrains Mono for all UI text (tab labels, file paths, status bar, sidebar labels), reserving Josefin Sans only for display/title text. Our current implementation uses Josefin Sans as the ambient UI face with JetBrains Mono only for code/terminal/diff surfaces. Which direction?
- Context: The design's "mono everywhere" rationale: clide is an IDE for people who like grids. The current Josefin Sans rationale: visual distinction between chrome text and code text, warmer feel. Both are valid — this is a feel decision, not a technical one.
- Triage (2026-05-17): Still open. The Josefin-Sans-as-UI-face implementation has shipped and is the current default; the design's "mono everywhere" direction remains unrealised. Convert to a D-record when the design call is made.
- Source: 2026-04-22 design handoff review.
Q-26: Small screen layout (< 1000px)
- Status: Open
- Question: Below 1000px window width, should clide switch to modal viewer/editor instead of split, or stack panels vertically? The spec defers this but flags it.
- Context: The interaction model defines breakpoints down to 1200px but punts on < 1000px. This matters for small laptops and tiling WM users who give clide half a screen.
- Source: 2026-04-22 interaction model spec (Wireframe — Flows v3), open question 1.
Q-27: Two-editor split
- Status: Open
- Question: Should clide support two files open in the editor simultaneously (horizontal split in the middle column)? The spec says resist until proven needed — feels like tabs creeping back.
- Context: D-48 deletes buffer tabs. A two-editor split would be the only way to compare files side-by-side without using the viewer ↔ editor swap. The diff view may cover most of this need.
- Source: 2026-04-22 interaction model spec (Wireframe — Flows v3), open question 2.
Q-28: Terminal strip scope — shell only or logs/errors/tests
- Status: Resolved → D-87
- Resolved (2026-06-06): Split by interaction. A bottom output dock hosts read-only output — logs + problems — toggled from a merged health/log status-bar widget (D-87). The terminal is NOT in the strip: it's an interactive surface, kept first-class in the editor pane (D-49). So "both, later" became "logs/problems yes, terminal no."
- Question: Is the app strip (bottom bar) purely a terminal shell + status, or does it also host tabs for logs, errors, and test output? Probably both, later.
- Context: The interaction model spec defines the app strip as 14px with terminal shell + daemon indicator + branch; expanding on focus. If it grows to host logs/errors/tests, it becomes a mini-panel with its own tab model.
- Source: 2026-04-22 interaction model spec (Wireframe — Flows v3), open question 3.
Q-29: Branch picker location
- Status: Open
- Question: The branch picker was moved out of the bottom status bar. Best place is inside the git section header (left panel), with a compact indicator in the app strip. Confirm or revise?
- Context: The interaction model spec suggests the git section header as the primary location. The app strip shows a compact indicator (branch name only) for at-a-glance awareness.
- Source: 2026-04-22 interaction model spec (Wireframe — Flows v3), open question 4.
Q-30: Focus behavior when editor is dirty and viewer is peeked
- Status: Open
- Question: When the editor has unsaved changes and the user peeks a viewer, where does focus land? The spec says prompt-bar-rule wins: focus stays in Claude.
- Context: This intersects D-47 (Claude is home) and D-49 (editor mode). If focus always snaps to Claude, the user must explicitly re-focus the editor to continue typing.
- Source: 2026-04-22 interaction model spec (Wireframe — Flows v3), open question 5.
Q-31: XWayland fallback for frameless — proper Wayland protocol needed
-
Status: Open (load-bearing workaround in place)
-
Question: The frameless window (D-57) currently forces
GDK_BACKEND=x11because GTK3 doesn't implement thexdg-decorationWayland protocol and KWin ignoresgtk_window_set_decorated(FALSE)on native Wayland. When do we replace this with a proper implementation? -
Context: The XWayland fallback works but has tradeoffs: one extra buffer copy per frame, degraded fractional-scaling on HiDPI (125%/150% gets blurry), loss of native Wayland touchpad gestures and per-window DPI, and slightly less reliable cross-app drag-and-drop. For an IDE these are tolerable but not ideal.
Current workaround (
Makefile):GDK_BACKEND=x11 flutter run -d linuxAlso set in the native runner:
gtk_window_set_decorated(window, FALSE)+gdk_window_set_decorations(gdk_win, 0)inlinux/runner/my_application.cc.Rollback if unstable: Remove
GDK_BACKEND=x11from the Makefileruntarget. The OS title bar returns but the app runs on native Wayland. Our hat bar renders below the OS bar (double chrome) until the proper fix lands.Proper fix — bypass GTK, talk
libwayland-clientdirectly:- Link
libwayland-clientinlinux/runner/CMakeLists.txt. - Generate protocol headers from
xdg-decoration-unstable-v1.xml(ships withwayland-protocolspackage) viawayland-scanner. - In
my_application.ccafter window realize: get thewl_displayviagdk_wayland_display_get_wl_display(), bind tozxdg_decoration_manager_v1from the registry, get the toplevel decoration object, callzxdg_toplevel_decoration_v1_set_mode(deco, MODE_CLIENT_SIDE). - ~100 lines C total. Needs
wayland-protocolsas a build dep. - The
GDK_BACKEND=x11env var is then removed.
Alternative timeline: Flutter moves to GTK4 (which has built-in xdg-decoration support). Track Flutter issue #94381. When it ships, drop all native decoration code and use
gtk_window_set_decorated(FALSE)— it will just work. - Link
-
Source: 2026-04-23 D-57 implementation.
Q-32: MCP tool surface — minimum slash-ide or extended clide tools?
- Status: Resolved → D-86
- Resolved (2026-06-06): Full
mcp__clide__*namespace, but generated from the co-registered command registry (D-74) that already feeds the CLI + palette — so breadth costs no hand-maintained second surface, and the extensions-first model needs registry-driven surfacing anyway. Per-command MCP opt-out for poor-fit verbs. - Question: D-68 commits clide to an
/ide-compatible MCP server. The minimum surface is the two tools Claude Code's/ideintegration currently expects:mcp__ide__getDiagnostics(lint/diagnostics for a file) andmcp__ide__executeCode(run code in a Jupyter kernel). Do we stop there, or also expose amcp__clide__*namespace with higher-leverage tools (open_file,goto_symbol,pql_query,pane_spawn,git_status, …) so MCP clients other than Claude Code (Cursor, Windsurf, VS Code Copilot) can drive clide as a real backend? - Context: The minimum surface keeps clide a good citizen in the
/ideecosystem and avoids duplicating the CLI in MCP form. The extended surface would let non-Claude-Code MCP clients integrate richly, but invites surface bloat (every CLI verb tempted to gain an MCP twin) and a maintenance second front. Note that for Claude-Code-in-a-clide-pane, the CLI surface already covers this — extended MCP tools serve external MCP clients only. - Source: D-68.
Q-33: MCP transport — SSE, WebSocket, stdio, or all?
- Status: Resolved → D-73
- Resolved (2026-05-19, drift-fixed 2026-06-06): SSE over HTTP only. Closed by D-73 (and confirmed in D-68's amendment) at the time, but this index was never flipped from Open. Re-confirmed 2026-06-06: stdio/WebSocket not added — D-73's reasoning (the always-running GUI is connected to, not spawned) still holds and no external process-spawn MCP client is a concrete need yet.
- Question: Claude Code's
/ideintegration connects via SSE-IDE or WS-IDE (URL passed at startup). MCP also supports stdio for process-spawn clients. Which transport(s) should clide's MCP server expose — SSE only (the most common/ideserver pattern), SSE + WS (broader compatibility), or all three including stdio? - Context: Transport choice affects discovery and lifecycle. SSE/WS need a port and a published URL, which collides with the
XDG_RUNTIME_DIRUnix-socket model used for the CLI; we'd likely publish the URL alongside the socket path (env var orXDG_RUNTIME_DIRdiscovery file). stdio is process-per-client and works for clients that prefer process-spawn over network. Decision interacts with Q-32 — if the surface stays at the/ideminimum, SSE alone is sufficient. - Source: D-68.
Q-34: How + when to surface the account/team token budget given upstream doesn't expose it
- Status: Open
- Question: The team-meta sidebar should show the account/subscription usage budget (5-hour + weekly limits, % used, reset times), but Claude Code does not expose this data programmatically under subscription (OAuth) auth (verified 2026-05-23, claude 2.1.150):
/usageis TUI-only,stats-cache.jsonholds activity counts only, the stream-jsonrate_limit_eventis undocumented and needs a billed turn, andclaude auth status --jsonshows plan only. So: what path do we take, and when do we act? Options — (a) wait for upstreamclaude usage --json/ a/v1/organizations/{org}/usage/subscriptionendpoint (open feature request anthropics/claude-code#44328); (b) an API-key usage path for key-auth users only; (c) scrape the undocumentedrate_limit_eventon a billed turn (fragile, version-pinned); (d) ship a partial budget (activity counts) and defer true limits. - Context: The only unshipped piece of the otherwise-complete native-Claude epic (T-132). Blocked on data availability, not on clide work — hence a question (when/how to revisit) rather than active scope. Option (c) interacts with D-75's "version-pinned coupling to CC internals" posture. Resolved by T-158 when a viable path lands.
- Source: 2026-06-09 — split out of T-132 / T-158 (was "blocked on upstream"); project memory
claude-usage-budget-not-exposed, GitHub anthropics/claude-code#44328.
Q-50: Web/WASM target after the dart:ffi pivot — fence, fix, or drop?
- Status: Open
- Question:
flutter build web --wasmno longer compiles: the tree-sitter FFI pivot and the native PTY both importdart:ffiunconditionally, which the wasm target forbids. That killsmake test-e2e/ui-dev/ui-smokeand the Playwright harness regardless of thecd appstaleness T-384 fixed. Options: (a) fence everydart:ffiimport behind conditional imports with web stubs (ongoing tax on every future native binding, for a target CLAUDE.md calls "a happy accident"); (b) keep the harness parked and re-evaluate if/when a web build matters (D-26's Playwright driver stays dormant); (c) drop the web target +tools/ui/harness formally and amend D-26/D-32. The guardrail says don't compromise desktop fidelity for web — (a) leans against it; (b) defers; (c) is honest but irreversible-ish. - Context: Surfaced 2026-06-12 while fixing T-384 (dead make targets). The mechanical path fixes (post app/-flattening) are done; the Gitea workflow's e2e job is withheld with a pointer here. The startup-regression gate (D-27) and integration tests are unaffected — only the browser/Playwright surface is blocked.
- Source: T-384 / 2026-06-11 Fable review (epic T-359).
Q-51: Unify workspace lifecycle on a single fenced open primitive
- Status: Open
- Question: There is no single "open workspace X" primitive — only two half-primitives in different layers.
project.open(root)(lib/kernel/src/project.dart) is the only repo-targeting path and is intrinsically in-place: it rebuilds services in the same process, reusing the shareddaemonBus.newWindow()(lib/builtin/menubar/src/file_actions.dart) spawns a blank detachedProcess.startwith no repo argument and no env scrubbing. To open a repo in a new window you must spawn a blank window and then run the in-place switch inside it. Should both fold behind oneWorkspaceService.open(root, {target: thisWindow | newWindow})that is the sole deriver of IPC identity from a root — and, more fundamentally, should in-place switching survive at all, or shouldworkspace ⇒ window ⇒ process ⇒ socket ⇒ bus ⇒ session-idbe strictly one-to-one so the leak/bleed class becomes structurally impossible? - Context: Surfaced 2026-06-14 from T-421 (status-bar branch bleeds across parallel windows). The same root cause — scattered, per-entry-point workspace lifecycle with no single fencing owner — already produced T-367 (in-place switch leaked the entire previous service set) and T-269 (kept the previous repo's Claude session). If in-place switching is abolished, the teardown burden those tickets patch disappears entirely. Relevant decisions: D-70 (per-workspace socket path), D-56 (one server per workspace), D-72 (multi-connection serial dispatch).
- Source: T-421 / 2026-06-14 user review.