You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Architecture proposal: introduce a headless Cherry Runtime and app-server boundary
Summary
Would the maintainers be open to gradually separating Cherry Studio's AI and Agent runtime from the Electron application behind a stable, transport-neutral application-server boundary?
The goal is not to rewrite Cherry Studio or split the repository immediately. The proposal is to preserve the existing behavior while evolving the current architecture toward:
Electron Renderer / Future CLI / Other Clients
│
Runtime Client API
│
IPC Adapter / Local RPC Adapter
│
Cherry Runtime Host
┌──────────────┼─────────────────┐
│ │ │
AiStreamManager Agent Sessions Tool Approval
│
Runtime Driver Interface
┌───────────┼───────────┐
│ │ │
AI SDK Pi Claude Code / DSH
This is similar in spirit to headless app-server boundaries such as Codex App Server, where rich clients communicate with a reusable runtime through a defined protocol.
Current architecture
Cherry Studio already has many of the right foundations:
Renderer communication is routed through IpcChatTransport.
IPC handlers are mostly thin adapters.
AiStreamManager owns active stream lifecycle.
Main owns persistence and approval state.
AgentSessionRuntimeService provides a shared session host.
AgentSessionRuntimeDriver isolates Pi, Claude Code, and DSH runtime behavior.
Shared transport types already live under @shared/ai/transport.
The primary remaining coupling is that the runtime is still constructed and accessed as part of the Electron Main process:
Some stream APIs directly accept Electron WebContents.
Runtime services resolve dependencies through the application-global service registry.
Persistence, files, approvals, windows, and runtime lifecycle do not yet have an explicit application boundary.
Electron IPC is effectively both the product transport and part of the runtime API.
Proposed direction
Introduce an internal CherryRuntimeHost or similarly named application boundary.
It would expose transport-neutral operations such as:
Electron IPC would become one adapter over this interface. A future local app server could expose the same operations through versioned JSON-RPC over stdio or a local socket.
The runtime host would continue owning:
turn and stream lifecycle;
Agent Session connections;
runtime driver selection;
tool execution and approval state;
persistence coordination;
MCP and skill integration;
event streaming and recovery.
The Electron renderer would remain responsible for presentation and user interaction.
Why this may be valuable
1. Clearer ownership boundaries
The runtime can be reasoned about and tested without requiring an Electron window. Electron-specific behavior stays in transport adapters.
2. More reliable long-running Agent work
Agent turns, approvals, persistence, and recovery remain owned by a durable runtime host rather than by a particular renderer or UI surface.
3. Additional clients without duplicating Agent logic
A future Cherry CLI, IDE integration, automation interface, or alternate desktop surface could reuse the same runtime instead of building another Agent implementation.
4. Stronger integration testing
The complete Agent lifecycle could be tested through one protocol:
Tests would not need to reach into internal services or construct Electron WebContents.
5. More stable extension points
Runtime capabilities, protocol versions, and supported operations could be negotiated explicitly instead of being inferred from renderer and Main implementation details.
Incremental implementation
This proposal should be implemented as several behavior-preserving changes rather than one large refactor.
Phase 1: remove Electron types from stream lifecycle APIs
Make AiStreamManager consume only transport-neutral listeners.
Move all WebContents handling into an Electron IPC adapter.
Preserve existing stream, detach, abort, persistence, and approval behavior.
Add contract tests for listener attach/detach and renderer loss.
Phase 2: introduce the runtime application facade
Add a narrow CherryRuntimeHost facade over the existing services.
Route current AI IPC handlers through the facade.
Keep the runtime in-process.
Avoid moving files or changing persistence schemas unnecessarily.
Phase 3: define a versioned local protocol
Reuse existing shared transport schemas where possible.
Define lifecycle primitives such as session/thread, turn, event, approval, and terminal result.
Add initialization and capability negotiation.
Keep the first transport local-only, preferably stdio.
Phase 4: optional headless app server
Package the runtime host as a local app-server entry point.
Let Electron launch and supervise it.
Preserve an in-process mode during migration.
Evaluate a CLI or test client only after the protocol stabilizes.
Phase 5: dependency ports
Gradually replace application-global dependencies with explicit ports for:
persistence;
managed files;
provider configuration;
secrets;
runtime process management;
notifications and client event delivery.
This phase should be driven by actual extraction needs rather than performed as a broad dependency-injection rewrite.
Non-goals
This proposal does not initially require:
splitting Cherry Studio into multiple repositories;
exposing a network-accessible server;
supporting remote unauthenticated clients;
rewriting the Electron renderer;
replacing AI SDK, Pi, Claude Code, or DSH;
changing database schemas;
changing existing chat or Agent behavior;
making internal APIs permanently public before the boundary is validated.
Security considerations
The first app-server transport should remain local-only.
Existing invariants must be preserved:
Main/runtime remains the writer of persistence and approval state.
Renderer or client disconnect must not automatically authorize or abort work.
Tool approvals remain associated with the correct turn and client.
Filesystem and process permissions remain enforced by the runtime.
Secrets and provider credentials should not be included in protocol events.
Protocol clients should declare capabilities during initialization.
Open questions
Is a transport-neutral, headless Cherry Runtime a direction the project wants?
Should the initial boundary remain internal and experimental?
Would maintainers prefer an in-process facade before introducing any RPC transport?
Should the protocol build on the existing @shared/ai/transport schemas?
Which lifecycle should be the primary protocol abstraction: topic, Agent Session, or a more general thread/turn model?
Would a focused first contribution removing WebContents from AiStreamManager APIs be welcome?
If the direction is accepted, I would be interested in contributing the first behavior-preserving slice and its regression tests.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Architecture proposal: introduce a headless Cherry Runtime and app-server boundary
Summary
Would the maintainers be open to gradually separating Cherry Studio's AI and Agent runtime from the Electron application behind a stable, transport-neutral application-server boundary?
The goal is not to rewrite Cherry Studio or split the repository immediately. The proposal is to preserve the existing behavior while evolving the current architecture toward:
This is similar in spirit to headless app-server boundaries such as Codex App Server, where rich clients communicate with a reusable runtime through a defined protocol.
Current architecture
Cherry Studio already has many of the right foundations:
IpcChatTransport.AiStreamManagerowns active stream lifecycle.AgentSessionRuntimeServiceprovides a shared session host.AgentSessionRuntimeDriverisolates Pi, Claude Code, and DSH runtime behavior.@shared/ai/transport.The primary remaining coupling is that the runtime is still constructed and accessed as part of the Electron Main process:
WebContents.Proposed direction
Introduce an internal
CherryRuntimeHostor similarly named application boundary.It would expose transport-neutral operations such as:
Electron IPC would become one adapter over this interface. A future local app server could expose the same operations through versioned JSON-RPC over stdio or a local socket.
The runtime host would continue owning:
The Electron renderer would remain responsible for presentation and user interaction.
Why this may be valuable
1. Clearer ownership boundaries
The runtime can be reasoned about and tested without requiring an Electron window. Electron-specific behavior stays in transport adapters.
2. More reliable long-running Agent work
Agent turns, approvals, persistence, and recovery remain owned by a durable runtime host rather than by a particular renderer or UI surface.
3. Additional clients without duplicating Agent logic
A future Cherry CLI, IDE integration, automation interface, or alternate desktop surface could reuse the same runtime instead of building another Agent implementation.
4. Stronger integration testing
The complete Agent lifecycle could be tested through one protocol:
Tests would not need to reach into internal services or construct Electron
WebContents.5. More stable extension points
Runtime capabilities, protocol versions, and supported operations could be negotiated explicitly instead of being inferred from renderer and Main implementation details.
Incremental implementation
This proposal should be implemented as several behavior-preserving changes rather than one large refactor.
Phase 1: remove Electron types from stream lifecycle APIs
AiStreamManagerconsume only transport-neutral listeners.WebContentshandling into an Electron IPC adapter.Phase 2: introduce the runtime application facade
CherryRuntimeHostfacade over the existing services.Phase 3: define a versioned local protocol
Phase 4: optional headless app server
Phase 5: dependency ports
Gradually replace application-global dependencies with explicit ports for:
This phase should be driven by actual extraction needs rather than performed as a broad dependency-injection rewrite.
Non-goals
This proposal does not initially require:
Security considerations
The first app-server transport should remain local-only.
Existing invariants must be preserved:
Open questions
@shared/ai/transportschemas?WebContentsfromAiStreamManagerAPIs be welcome?If the direction is accepted, I would be interested in contributing the first behavior-preserving slice and its regression tests.
All reactions