Conversation
Integrate OpenClaw as a first-class AgentBackend in the CLI daemon, following the same pattern as Claude/Codex/Gemini. The daemon spawns an OpenClaw session process that connects to the gateway via WebSocket and translates the protocol to Happy's AgentMessage format. - OpenClawSocket: WebSocket client with request/response correlation, reconnection, and Ed25519 device auth - OpenClawBackend: Custom AgentBackend mapping OpenClaw chat events to Happy's message types (delta, thinking, tool-call, status) - runOpenClaw: Session entry point with zero-config auto-detection from ~/.openclaw/openclaw.json, abort handling with inTurn guard - controlServer: Fix /spawn-session missing agent field in Zod schema - daemon/run: Add openclaw to agent resolution and tmux spawning Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add OpenClaw to the agent selection flow, CLI detection, profile compatibility, model/permission modes, translations, and avatar icons. - Agent cycling: claude -> codex -> openclaw -> gemini -> claude - CLI detection via `command -v openclaw` on remote machine - Profile compatibility with openclaw: false default - OpenClaw permission/model mode options - Avatar flavor icon badge (icon-openclaw @1x/@2x/@3x) - Translations for all 11 languages - Session info flavor display Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…eading config file Use `openclaw status --json` for the gateway URL (cross-platform, respects remote/tailscale configs). For the token, resolve config file path via OPENCLAW_CONFIG_PATH env var, falling back to ~/.openclaw/openclaw.json. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…olution Config file path resolution now follows the same priority as the openclaw binary: OPENCLAW_CONFIG_PATH > OPENCLAW_STATE_DIR/openclaw.json > ~/.openclaw/openclaw.json. Works cross-platform via os.homedir(). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds `yarn env:new` to create isolated, fully-wired dev environments with auto-allocated ports, PGlite database, and CLI support. No Docker or external databases needed. Commands: env:new, env:list, env:use, env:remove, env:server, env:web, env:cli Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Spaces in asset filenames cause images to silently fail to load in monorepo setups due to a double-encoding bug in the Expo/Metro/iOS URL chain. Root cause: 1. Expo's ensureOtaAssetHashesAsync (getAssets.js) applies encodeURIComponent() to the directory path in httpServerLocation when ?unstable_path= is present (monorepo mode), encoding / to %2F 2. React Native's AssetSourceResolver.assetServerURL() concatenates this encoded directory path with the unencoded asset name (which contains a literal space for files like "Abstract 1.png") 3. iOS URL(string:encodingInvalidCharacters:true) sees the space and re-encodes the URL — but in doing so, it also re-encodes the % in existing %2F sequences, producing %252F (double-encoding) 4. Metro server receives %252F, URLSearchParams decodes one level to %2F (not /), so the resolved path contains literal "%2F" directory segments that don't exist on disk → 404 Why images without spaces work: when the URL has %2F but no invalid characters (no spaces), iOS URL(string:) recognizes the URL is already valid and preserves %2F as-is. The server then decodes %2F → / and resolves the correct file path. This is monorepo-specific because only the unstable_serverRoot config triggers the ?unstable_path= publicPath format, which in turn triggers Expo's encodeURIComponent encoding of the directory path. Workaround: rename all brutalist asset files to use hyphens instead of spaces (e.g. "Abstract 1.png" → "Abstract-1.png"). A proper fix should be upstreamed to Expo — ensureOtaAssetHashesAsync should not apply encodeURIComponent to the directory path for ?unstable_path= (dev mode) URLs, only for ?export_path= (production export) URLs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove the ENABLE_SESSION_PROTOCOL_SEND feature flag that created a mutual exclusion gate between legacy (role:'user') and session protocol (role:'session' envelope) user messages. The flag was never enabled anywhere, and its either-or design meant CLI-sent user messages were silently dropped by normalizeRawMessage() since the CLI always sends session protocol envelopes while the flag defaults to off. Both formats are now always accepted and rendered. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove the HAPPY_VARIANT/HAPPY_HOME_DIR mismatch warning from CLI startup and always hide thinking messages in the app (previously gated behind experiments flag). Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
- Add real CLI model versions: opus 4.6, sonnet 4.6, haiku 4.5 - Add per-model effort levels and defaults (claude 3, codex 4) - Add dontAsk permission mode, OpenClaw permission/model modes - Add worktree support flag per agent flavor - Update AgentInput: hide permission when default, show colored icon (play-forward/pause) for non-default modes, remove model mode display - Fix modeHacks capitalizing plan/build to lowercase - Lowercase all permission labels in translations - Add gemini auto_edit/plan permission modes across all languages Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
New session composer with real agent configurations: - Config box: machine, path, agent+model+effort, permission, worktree - Auto-collapses config to path row when typing, expands when cleared - Generic picker modal for machine/path/worktree selection - Per-mode icons: play-forward for acceptEdits/bypass, pause for plan - Monochrome agent icons, no text selection on web - Send button sticky to bottom-right, input grows to 240px max - Native bottom sheet (formSheet iOS, slide-up Android), web popover Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
- Add cross-platform CLI detection utility (detectCLI.ts) that runs at daemon boot and re-checks every 20s on keep-alive - Add cliAvailability field to MachineMetadata schema (CLI + app side) - Remove all profile-related code from happy-cli (persistence, run.ts, spawn options) - Delete profile/wizard files from happy-app (15 files including ProfileEditForm, NewSessionWizard, useCLIDetection hook, etc.) - Remove environmentVariables from SpawnSessionOptions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nd translations Clean up all remaining profile and wizard references: - Remove profile schemas, fields, and functions from settings.ts - Remove environmentVariables from SpawnSessionOptions in ops.ts - Remove profile props and UI from AgentInput.tsx - Remove profile settings item from SettingsView.tsx - Remove wizard pick screen routes from _layout.tsx - Remove enhanced session wizard toggle from features.tsx - Delete unused SessionTypeSelector component - Clean up settings.spec.ts to remove profile test cases - Remove profiles and newSession translation sections from all 10 languages - Add placeholder new session screen at /new route Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace placeholder with the session composer screen wired to: - Real machines from useAllMachines() with online/offline status - Real paths from session history per selected machine - CLI availability filtering from machine.metadata.cliAvailability - Session spawning via machineSpawnNewSession() with agent type - Auto-select first online machine on mount - Persist lastUsedAgent to settings Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…reen Wire up onKeyPress handler to MultiTextInput so Enter sends on web when agentInputEnterToSend setting is enabled (Shift+Enter for newline). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ng response format
Three bugs in the Codex MCP elicitation flow:
1. MCP SDK's ElicitRequestSchema uses strict Zod objects that strip
codex_call_id, codex_command, codex_cwd from params. Fixed by
rebuilding the schema with z4mini.looseObject() to preserve them.
2. Client.setRequestHandler checks def.value for method literal but
z4mini.literal() uses def.values. Fixed by reusing the original
method schema from ElicitRequestSchema.
3. Response format was { decision: 'approved' } but MCP expects
action: 'accept'|'decline'|'cancel' and Codex additionally reads
decision. Fixed by returning both fields.
Also adds experiments/codex.ts standalone test script that confirms
the full permission flow works end-to-end.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…oute Prevents stacking multiple composer screens when pressing "new session" button repeatedly. router.navigate reuses the existing screen if already focused. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…spacing - Add ActivityIndicator to send button while session is spawning - Hide CodexReasoning, GeminiReasoning, think, and change_title tools - Reduce desktop bottom padding and horizontal padding on wide screens Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a "CLI Availability" section showing installation status of Claude, Codex, Gemini, and OpenClaw CLIs with last detection timestamp. Data comes from daemon-side detection via machine metadata. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The new session screen tracked the user's selected permission mode and model but never wrote them to the session record before sending the initial message. sync.sendMessage() reads these from storage, so the first message always arrived at the daemon with permissionMode: "default". Now sets updateSessionPermissionMode/updateSessionModelMode on the session immediately after creation, before sendMessage is called. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Persist the new-session form (prompt, machine, path, agent, model, permissions) across navigation via a Zustand store backed by MMKV. Show offline machines in the machine picker with "last seen" timestamps, gray out config options when the selected machine is offline, and display an offline help banner. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When "new worktree" is selected, create a git worktree via machineBash before spawning the CLI session in that directory. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Add listWorktrees() that queries `git worktree list --porcelain` via machineBash and populates the worktree picker with existing worktrees. Users can now pick an existing worktree instead of always creating new ones. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
…ession delete Merge createWorktree.ts and generateWorktreeName.ts into a single worktree.ts module. Export shared WORKTREE_PATH_MARKER constant and isWorktreePath() helper. Add removeWorktree() and call it (best-effort) when deleting a session that was in a worktree. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
… call When Claude Code automatically calls EnterPlanMode, detect the tool call in the message stream and switch the session's permission mode to plan, so the input bar reflects the mode change without manual intervention. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Replace DANGEROUSLY_LOG_TO_SERVER_FOR_AI_AUTO_DEBUGGING env var approach with a dedicated local log receiver server + app setting. The app can now point at prod sync server for data while sending console logs to a separate local server for debugging. - New package: happy-app-logs — minimal HTTP server (~90 lines) that writes to ~/.happy/app-logs/ and stdout - App: new Log Server URL setting on dev screen (MMKV-persisted) - App: remoteLogger.ts reads from MMKV/EXPO_PUBLIC_LOG_SERVER_URL - Environments: replaced EXPO_PUBLIC_DANGEROUSLY_* with EXPO_PUBLIC_LOG_SERVER_URL pointing to localhost:8787 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove reconnect handler that fired fetchMessages for all 150 sessions simultaneously, causing JS thread to block for seconds. Session metadata and permissions are still refreshed via sessionsSync; messages are fetched lazily per-session when viewed (SessionView already re-fetches on realtimeStatus change). - Remove SwiftUI ContextMenu wrapper (Host/ContextMenu from @expo/ui) from session list FlatList items — 148 native SwiftUI views were causing layout measurement failures (items rendered at 0 height) and severe performance degradation. Long-press now opens the same PopoverMenu used on web. ActiveSessionsGroup still uses native menus (only ~5 items, not virtualized). - Add FlatList performance props (windowSize, maxToRenderPerBatch, initialNumToRender, removeClippedSubviews). - Reduce message validation error logging from 3x console.error with full JSON dump per unrecognized message type to a single console.warn line. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SwiftUI <Host matchContents> from @expo/ui causes height measurement instability in FlatList - views report different heights on different measurement passes, corrupting layout when scrolling back to previously seen items. Remove SessionActionsNativeMenu (SwiftUI ContextMenu) from all list components: SessionsList, ActiveSessionsGroup, and ActiveSessionsGroupCompact. ChatHeaderView keeps it (single static instance, not in a list). Also remove long-press/context menu handling from session list items for now - will re-add with a non-SwiftUI approach later. NOTE: @expo/ui SwiftUI Host components should never be used inside virtualized lists (FlatList/FlashList). Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Resume session is experimental and not ready for all users. Add expResumeSession setting (default: false) with toggle in Features settings screen. When disabled, resume button is hidden from session view, session info, and context menus. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
codex app-serverruntime420brutalist image renames), which inflates file count but is not the main product change. This was needed after the mono repo migration for dev builds to resolve assets correctly.Testing
yarn weblocally and exercise the new session flow in Expo web.Major additions
Neutral
Deletions
Changes By Area
1. Simpler session creation and profiles deprecation
/newWhy remove profiles for now?
2. Codex architecture redesign
happy-cliCodex integration from the legacy MCP client tocodex app-server3. Session resume, machine RPC, and quick actions
happy-agentmachine listing, spawn, resume, and send-with-yolo supporthappy-agentin sourced envs and gate the in-app resume UX behindexpResumeSession4. Notifications, routing, and logging
happy-app-logsplus explicit API/log server URLs in dev settings5. Agent/backend coverage and new providers
6. Dev environments and fixtures
environments/7. App polish and bug fixes
http(s)links