Skip to content

CLI doesn't propagate sandboxConfig to session metadata, web app defaults to 'default' permission mode #625

@ZiggyGameDev

Description

@ZiggyGameDev

Bug Description

When sandboxConfig.enabled: true is set in ~/.happy/settings.json along with a profile that has defaultPermissionMode: "bypassPermissions", the web app (app.happy.engineering) still sends permissionMode: "default" with every new session's first messages. This causes permission prompts to appear on the phone/web despite the user configuring bypass mode.

The Android app exhibits the same behavior — both platforms intermittently send "default" for new sessions.

Root Cause

The CLI's runClaude() function creates session metadata without including sandbox configuration:

// packages/happy-agent/src/index.ts (or dist/index-B3gQr6vs.mjs ~line 5000)
let metadata = {
    path: workingDirectory,
    host: os.hostname(),
    version: packageJson.version,
    os: os.platform(),
    machineId,
    homeDir: os.homedir(),
    happyHomeDir: configuration.happyHomeDir,
    happyLibDir: projectPath(),
    happyToolsDir: resolve(projectPath(), "tools", "unpacked"),
    startedFromDaemon: options.startedBy === "daemon",
    hostPid: process.pid,
    startedBy: options.startedBy || "terminal",
    lifecycleState: "running",
    lifecycleStateSince: Date.now(),
    flavor: "claude"
};
// No sandbox field ^^^

Meanwhile, the web app's permission resolution in packages/happy-app/sources/sync/messageMeta.ts checks:

function isSandboxEnabled(metadata): boolean {
    const sandbox = metadata?.sandbox;
    return !!sandbox && typeof sandbox === 'object' && sandbox.enabled === true;
}

Since session.metadata.sandbox is never set by the CLI, isSandboxEnabled() always returns false, and the web app falls through to 'default' for every new session.

Evidence from Logs

Analyzed all ~/.happy/logs/ files across multiple sessions (v0.13.0). Pattern:

  • 439 messages with sentFrom + permissionMode metadata
  • Both android and web intermittently send "default" (88 and 78 times respectively)
  • Every new session starts with "default" until the user manually changes it
  • The [loop] Permission mode updated from user message to: default log confirms the CLI receives "default" from the app
  • Permission prompts (sendToAllDevices "Permission Request") only occur when permissionMode: "default" was sent
  • Once the user manually switches a session to bypass mode on the app, subsequent messages correctly send "bypassPermissions" — but this resets on every new session

Suggested Fix

Include sandbox config in session metadata when creating sessions:

const settings = await readSettings();
// ...
let metadata = {
    // ... existing fields ...
    sandbox: {
        enabled: settings?.sandboxConfig?.enabled ?? false
    }
};

This would allow the web app's isSandboxEnabled() check to work as documented in docs/permission-resolution.md.

Alternatively

The defaultPermissionMode from the active profile could also be propagated — either in session metadata or via a separate mechanism — so the web/mobile apps can resolve the correct mode without relying solely on sandbox status.

Environment

  • Happy CLI: v0.13.0
  • Claude Code: v2.1.42
  • Platform: Windows 11 Pro (win32/x64)
  • Node: v24.6.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions