Files
tutti/docs/architecture/desktop-backend-access.md
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

7.6 KiB

Desktop Backend Access

This document records the desktop backend access model for tutti. The planned shared business-stream protocol is documented in Business Event Stream.

Decision

tuttid is the local product backend for tutti.

Desktop uses a dual-path model:

  • renderer -> tuttid for business capabilities and streaming transports
  • renderer -> preload -> main for Electron and OS capabilities

main -> tuttid remains available for a small number of host-assisted flows, but it is not the default business access path.

Why

This model keeps one business authority while improving three areas that are awkward under a main-process relay-only design:

  • streaming transports such as WebSocket and SSE
  • CLI access to the same local product backend
  • desktop feature work that should not require a manual IPC wrapper for every daemon capability

The goal is not to make Electron main irrelevant. The goal is to stop using it as a broad business transport relay.

Ownership Model

tuttid

tuttid owns:

  • business rules
  • durable local state
  • domain workflows
  • backend contracts shared by desktop and CLI

main

main owns:

  • daemon lifecycle supervision
  • loopback endpoint discovery and session-token issuance
  • desktop-only logging and diagnostics
  • Electron and OS integrations
  • host-assisted flows that require both native capability and daemon access

main must not become a second business core.

preload

preload owns the narrow renderer-facing desktop SDK.

It should expose:

  • runtime configuration needed to reach the managed local backend
  • narrow resolved route helpers for managed transport families when renderer should not assemble route-local WebSocket URLs itself
  • explicit host capabilities such as file pickers, window control, shell open, notifications, and similar native actions
  • a small number of host-assisted commands when renderer cannot complete the flow alone

It should not expose:

  • a generic invoke(channel, payload) surface for ordinary renderer work
  • transport policy details beyond the minimum needed to reach the managed local backend

renderer

renderer owns:

  • UI
  • view state
  • direct business calls to tuttid
  • direct SSE / WebSocket consumption when the stream is business-facing

Renderer should treat tuttid as the backend and window.tutti as the host capability surface.

Default Routing Rule

When adding or changing a desktop capability, choose the path by responsibility.

Direct renderer -> tuttid

Use for:

  • ordinary query and command APIs
  • workbench and workspace data
  • search, list, get, update, save
  • terminal and agent streams
  • business event subscriptions

Business event subscriptions and bidirectional business event publishing should follow the shared event-stream contract rather than route-local ad hoc socket payloads.

Direct renderer -> main

Use for:

  • file and directory pickers
  • shell reveal and shell open
  • notifications
  • menus, tray, clipboard, window lifecycle, updater
  • any capability that requires Electron or OS APIs

Host-assisted renderer -> main -> tuttid

Reserve for flows that require both native host authority and daemon authority in one operation.

Examples:

  • choose an export destination, then ask tuttid to write backend-owned data
  • open a file or resource whose resolution depends on daemon-owned metadata plus native shell behavior
  • choose a host directory, then pass that directory to a host capability that needs explicit filesystem input

These flows should stay explicit and few.

Transport Policy

Desktop transport follows these rules:

  • tuttid binds to loopback only
  • desktop prefers a managed random loopback port over a fixed public port
  • main discovers or allocates the endpoint, then provides renderer with runtime config
  • business streaming uses HTTP, SSE, and WebSocket directly where appropriate

This favors a product-style local backend over a desktop-private relay model.

Desktop Capability Classification

The desktop surface should be designed as three explicit capability groups.

Backend Business Capabilities

These belong on the direct renderer -> tuttid path:

  • health, availability, and backend bootstrap checks
  • workspace catalog queries and mutations
  • workbench snapshot load and save
  • workspace file listing, search, creation, deletion, and upload flows
  • streaming business APIs such as terminal, agent, and event streams

Terminal streams and business event streams are both direct business transports, but they should remain separate protocol surfaces because they serve different semantics.

Workspace file APIs on this path should stay logical-path based, for example /workspace/..., rather than exposing host absolute paths as part of the business contract.

This is the default path for business-facing desktop product behavior.

Host Capabilities

These belong on the direct renderer -> main path through preload:

  • system locale and system theme signals
  • host-side preference sync needed for Electron-only side effects
  • updater state and update actions
  • file and directory pickers
  • dropped-path resolution
  • workspace window display and dashboard display
  • shell reveal, shell open, native preview affordances
  • window creation, focus, and replacement
  • notifications, menu actions, tray, clipboard, and similar Electron or OS APIs

These capabilities should stay explicit on surfaces such as window.tutti.host.*, window.tutti.update.*, and window.tutti.platform.*.

Host capability rules:

  • host adapters should normalize Electron-native outputs into durable product values before returning to renderer
  • host window commands should stay window-oriented and avoid hiding backend mutations inside IPC handlers

Preference ownership rule:

  • renderer should read and write user desktop preferences through tuttid
  • main should stay limited to system-environment inputs and host-only effects such as theme application

Host-assisted Compound Flows

These belong on the renderer -> main -> tuttid path:

  • resolve and open a local file whose authority crosses daemon metadata and host shell behavior
  • read local preview content when host file access is still part of the product contract

Use this path when host absolute-path resolution is required at runtime. Do not push that resolution into the workspace catalog or ordinary business DTOs.

These flows should stay narrow, named, and intentional. They are not a second business transport layer.

Update capability rule:

  • preload-facing update configuration remains a typed contract, so main/update/* should validate supported channel and policy values instead of silently coercing unknown fields

Security Constraints

Moving business traffic to managed loopback requires explicit guardrails:

  • bind only to 127.0.0.1 or equivalent loopback
  • prefer random allocated ports over fixed defaults
  • require explicit desktop-issued authentication or capability material for renderer-visible backend access
  • keep untrusted content, external webviews, and arbitrary browser surfaces off the desktop backend path
  • keep preload surfaces narrow even when renderer can talk to tuttid

Renderer visibility of a local backend is acceptable only when the backend is treated as a real product surface, not as an unguarded internal helper.

CLI Relationship

This model supports a cleaner CLI story:

  • CLI talks to tuttid as a client of the same local product backend
  • desktop renderer talks to the same backend
  • main stays a host supervisor, not a CLI dependency

That shared backend contract should reduce duplication across desktop, CLI, and tests.