feat: move chat into Experimental settings, default automations to chat
Summary
- Chat leaves PostHog. Desktop and mobile each get a device-local Settings → Experimental → Chat switch, off by default. With it on, ACP agents (Claude, Codex, OpenCode, Pi) open as a chat; every other agent opens a terminal. With it off, everything opens a terminal.
- Automations default to chat. Server-side automation runs ask for a chat whenever the agent supports ACP, with no flag or setting; the host still answers with a terminal for an agent it can't chat with.
- Presets bar is back on chat tabs. Agent presets already pick chat or terminal from the setting and ACP support.
Why / Context
Chat was gated by the acp-chat PostHog flag, so the audience was chosen per user in PostHog and people could not opt in themselves. Moving it to an Experimental switch makes it opt-in per device. Automations have no device to read a setting from, so they open as chat by default whenever the agent supports it.
How It Works
| Surface | Decides chat vs terminal from |
|---|---|
| Desktop | useAcpChatEnabled(): the persisted acp-chat store, default false (a stored null from before migrates to off) |
| Mobile | new acpChatStore (AsyncStorage, acp-chat-v1), default false |
| Automations (relay + cloud) | always chat: true; launchAgentSession checks sessions.capabilities and falls back to a terminal |
cloudWorkspace.create | new optional input surface: "chat" | "terminal"; when omitted, the old flag lookup (acpChatEnabled(userId)) |
In every path, chat needs both the gate and ACP support (acpHarnessForPreset / supportsCloudAgentChat / host capabilities).
Also:
- "Fork into chat" on terminal headers (gated by
agent-surface-fork) is hidden while Chat is off. Before this PR it was offered to people who had no chat at all. - "Track file changes per turn" shows only while Chat is on.
useIsChatTabActiveis deleted; it existed only to hide the presets bar.
Manual QA Checklist
Desktop dev app driven over CDP with real clicks. For "before", the same dev server ran main (changes stashed).
Before (main) | After | |
|---|---|---|
| Settings → Experimental | No Chat switch (account not in the flag) | Chat switch shown, off, nothing stored |
| Chat off: Claude preset | Terminal | Terminal ✅ |
| Chat off: terminal "CLI mode" menu | Offers Fork into chat | Only Fork session / Continue with another agent ✅ |
| Chat on: Claude preset | — | Chat pane ✅ |
| Chat on: Copilot preset (no ACP) | — | Terminal ✅ |
| Presets bar on a chat tab | Hidden | Shown ✅ |
- Turning Chat on reveals "Track file changes per turn"; the setting persists as
{enabled: true}(v1) - No console errors during the after runs
- Not run: mobile on a simulator (Experimental switch, chat gates)
- Not run: a real automation run end to end (covered by
hostSession.test.ts, including the unsupported-agent fallback)
Testing
bun run typecheckinapps/desktopandpackages/trpc: cleanapps/mobiletypecheck: same 188 errors asmain, none newbun testinpackages/trpcautomation + cloud-workspace (86), desktop settings / tasks / persisted-keys / chat adoption (148+44), all ofapps/mobile(248): passbun run check:i18n: clean (one new mobile string, translated in all 16 locales)biome check: clean
Design Decisions
- Per-device switch, not an account setting. An account column would need a migration in its own PR first (db-migrations / trpc-compat rules). The device switch matches desktop's existing experimental toggles; automations sidestep the problem by defaulting to chat.
- Omitted
surfacekeeps the flag lookup instead of meaning terminal: trpc-compat says a changed default must be opt-in, so released desktop/mobile builds, CLI, MCP and SDK behave as they did.
Risks / Rollout
- Behaviour change for current flag users: desktop and mobile users in
acp-chatlose chat until they turn the switch on. Intended: it's opt-in now. - Automations for everyone: owners who were not in the flag now get a chat for Claude/Codex/OpenCode/Pi automations. Other agents are unchanged.
- Client before API: a new desktop or mobile build calling an API without this change sends
surface; zod strips the unknown key and the server falls back to the flag. Harmless. - Rollback: revert the PR. No data or schema changes; the persisted
acp-chatstore reads back as before (enabled: truestays on).
Follow-ups
- Remove the
acp-chatflag andpackages/trpc/src/lib/acp-chat.tsonce no released build omitssurface.
Summary by cubic
Moves ACP chat for Claude, Codex, OpenCode, and Pi agents out of the acp-chat PostHog flag into a per-device Settings → Experimental → Chat switch, off by default, on desktop and mobile. Server-side automation runs now default to chat whenever the agent supports ACP and fall back to a terminal otherwise, without consulting the flag.
Behavior changes
- Users who had chat via the
acp-chatflag lose it until they turn the switch on. - "Fork into chat" on terminal headers is hidden while Chat is off; "Track file changes per turn" shows only while it's on.
- The presets bar is back on chat tabs.
API
cloudWorkspace.createaccepts an optionalsurface: "chat" | "terminal"; callers that omit it (released builds, CLI, MCP, SDK) keep the old flag lookup, so the input is additive.
Summary by CodeRabbit
- New Features
- Added an Experimental Settings option on mobile to open Claude and Codex sessions as chats, with translations across supported languages.
- Cloud workspace creation now supports choosing a chat or terminal session surface.
- Improvements
- Chat availability is managed through a saved setting across desktop and mobile, and workspace launches use that setting to select a session type.
- Automation-launched sessions now open as chats when the selected agent supports chat.