GenerateSaaS

AI agents

The desktop app's AI surface - Chat, Automations, and the AI settings screens - running on your hosted models or on the user's own coding CLIs.

The desktop app chats on your models out of the box, and gains a second runtime when the user brings their own: their installed coding CLIs (Claude Code, Codex, Grok, OpenCode) do the work on their machine, under their own logins, driven by the agent runtime the app forks. config.desktop.agents in packages/config/src/desktop.mjs gates the whole surface, which every desktop project ships in source - so turning it on is a config change, not a re-scaffold.

FieldDefaultDescription
enabledtrue when scaffolded with AI, else falseWhether the AI surface renders and the app forks the runtime. Off, the app is a plain client shell: no AI pages, no side panel, no provider ever contacted.
userAutomationstrueWhether end users may author their own background automations (false ships only builder-registered ones).
backgroundfalseWhether agent work continues after the window closes. On, end users get a Keep running after I close the window switch (see Automated agents).
sidePanel{ chat: true, terminal: true, default: "chat" }Which side-panel tabs ship and which opens first (see Terminal and side panel).
maxChatsPerAgent20Chat conversations kept per agent on the user's machine; a new chat past the cap deletes the oldest. 0 means no limit.
defaultModelunsetThe model a default run uses, as a device selection key (e.g. "claude-code:claude-opus-4.8"). Unset, a fresh chat follows your hosted default and meters credits, exactly like web; set it to a CLI and default runs happen on that user's machine under their own subscription. It is a pointer: users who never chose, and users who reset, follow whatever default your next build ships.

enabled is a runtime gate, not a packaging one. The runtime is a second entry built from this app's own source (out/main/daemon-entry.js), so every desktop build ships it. Flipping enabled to true in a project generated WITHOUT AI turns the screens on but leaves the engine source out - re-run the CLI (init or update) with --ai to add it.

Where it lives

Chat and Automations are top-level sidebar pages; the AI configuration surfaces are runs of the Settings rail. Each renders only when its own gate is on.

SurfaceWhereShown when
Chat/chat, plus a side-panel tabthe AI surface is on
Automations/automationsthe AI surface is on (see Automated agents)
ModelsSettingsthe AI surface is on - the providers, the default model, and the runtime's own controls
TasksSettingsat least one builder task targets the desktop
MCP serverSettingsconfig.mcpServer is enabled - an authenticated endpoint external agents use to drive the app
IntegrationsSettingsthe AI surface is on and config.ai.enabled - the services users connect their accounts to. An empty catalog shows the empty state, never a hidden entry

The right side panel carries a Chat tab (the same persisted conversation) and a Terminal tab (the user's own CLI).

What runs, and where

The selected model decides, and it decides per turn.

LaneWhere it runsWho paysReaches your backend
A hosted model (built-in or the user's own key)your server, via /ai/chatyour credits, or the user's provider keyyes - metered server-side
A connected coding CLIthe user's machine, in a work folder, audited locallythe user's own CLI subscriptiontools only - see below

A coding-CLI chat gets the same app tools the in-app chat has (account data, automations, your own capabilities, and the web tools whenever a search engine is configured): while the user is signed in, the app serves the product's tool manifest to the CLI over a loopback MCP and executes each call on your backend under that user - the AI itself never touches your server. A web_search or web_extract call made there is metered to that user exactly as the same call in web chat is. Each new conversation lists the backend's current manifest, so a tool you add or rename on the server reaches the next new chat without restarting the app.

Four device tools ride that same MCP and need no account at all, because their work happens on the machine:

ToolWhat it does
list_local_automationsLists this device's automations, built-ins included.
create_local_automationSchedules a new one on this device.
update_local_automationChanges one (a built-in takes only its enable flag).
delete_local_automationRemoves one.

They are scoped to the active project, and they keep working signed out or with your backend down - which is the whole point: a CLI asked to schedule something locally can comply either way. The backend tools are the half that needs a session, so signed out the chat still works, with the device tools alone.

Automations, per-task overrides and the Terminal are the on-device lane only: fired by the runtime against a CLI, never a hosted model. Automations and the Terminal mount the same app tools a CLI chat does. A running Terminal keeps them when the backend session expires or the project changes: the app renews the session behind the same loopback address. Integrations are the one part that is not on-device: the connection lives in your backend, so the tools it contributes are the ones web chat gets. The app stores no model credential of its own on either lane.

On this page