HappierDocs
Apps and interface

CLI sessions

Create, list, control, and script sessions from the CLI.

This page focuses on session lifecycle and session control from the CLI.

If you’re looking for install/auth/server profiles first, start at CLI.

The same canonical action catalog also powers the app, session agents, voice, and the external MCP server. That is why the session CLI, the built-in action surface, and external MCP controls all describe the same session operations in different transports.

Session identifiers

Most commands accept either:

  • a full <session-id>
  • or an unambiguous prefix (<session-id-or-prefix>)
  • (often) an exact session tag if the session metadata is available locally (--tag from session create)

If the prefix matches multiple sessions, the command fails and prints candidates (use --json for structured output).

Attach vs resume

Use attach when the session is still running and you want to reconnect to the live local/provider process:

happier attach <session-id>

Use resume to continue a session without checking its state first:

happier resume <session-id>

Short version:

  • attach = reconnect to a running session
  • resume = attach if running and attachable; otherwise reopen an inactive vendor-resumable session

For the full workflows, see Attach to a running session and Resume inactive sessions.

Create a session

happier session create --title "My session" --message "Hello"

Target a different directory:

happier session create --path /path/to/repo --title "Repo session"

Backend targeting (--backend)

--backend expects a backend target key:

happier session create --backend "agent:<agent-id>"
happier session create --backend "acpBackend:<backend-id>"

When in doubt, inspect the canonical schema and available options via the action catalog:

happier session actions describe session.spawn_new --json

List sessions

happier session list

Scripting-friendly:

happier session list --json

Useful filters:

happier session list --active
happier session list --archived
happier session list --resumable

Status

happier session status <session-id-or-prefix>

Live status (when supported):

happier session status <session-id-or-prefix> --live

Messaging

Send a user message:

happier session send <session-id-or-prefix> "ping"

Wait for the agent to become idle:

happier session send <session-id-or-prefix> "ping" --wait --timeout 60

Or wait without sending:

happier session wait <session-id-or-prefix> --timeout 60

Notes:

  • --wait can time out if the agent is offline/busy or if the backend does not emit an “idle” signal.
  • --permission-mode lets you override the permission intent for a single send.
  • --model lets you target a specific model for that message when the backend supports it.
  • --json + explicit timeouts are recommended for scripts.

Choosing one message identity (--local-id)

Development builds let CLI coordinators choose the message's localId before sending:

happier session send <session-id-or-prefix> "ping" --local-id 'board-wake-42' --json

Keep that exact ID when correlating the send result with session history or retrying a send. IDs must be nonblank and cannot begin with -. The relay rejects the reserved agent-transition: prefix. This override belongs to the CLI; MCP and voice tools continue using host-generated IDs.

History

Get recent transcript rows:

happier session history <session-id-or-prefix> --limit 20

Scripting / debugging variants:

happier session history <session-id-or-prefix> --json
happier session history <session-id-or-prefix> --format raw --include-meta --json
happier session history <session-id-or-prefix> --format raw --include-meta --include-structured-payload --json

Use compact when you want a simpler text-focused view. Use raw when you need provider payloads, metadata, or structured tool/message records.

Session control

Stop a session:

happier session stop <session-id-or-prefix>

Archive / unarchive:

happier session archive <session-id-or-prefix>
happier session unarchive <session-id-or-prefix>

Update metadata:

happier session set-title <session-id-or-prefix> "New title"
happier session set-model <session-id-or-prefix> <model-id>
happier session set-permission-mode <session-id-or-prefix> <mode>

Permission intent (set-permission-mode and --permission-mode)

Happier stores a provider-agnostic permission intent for each session.

Preferred inputs:

  • read_only
  • default
  • auto
  • yolo

Older spellings such as read-only, safe-yolo, workspace_write, acceptEdits, and bypassPermissions remain accepted. They normalize into compatible session metadata, so JSON output can retain an older wire spelling. Legacy plan permission input remains available for providers that map it to a session mode.

Use it in either place:

happier session set-permission-mode <session-id-or-prefix> read_only
happier session send <session-id-or-prefix> "ping" --permission-mode auto

Notes:

  • set-permission-mode updates the session’s persisted intent.
  • session send --permission-mode ... is a one-message override.
  • The exact allowed operations still depend on the backend/provider and your account policy.
  • Use --json to see the normalized intent stored/used.

These session control commands map to canonical actions such as:

  • session.title.set
  • session.model.set
  • session.permission_mode.set
  • session.stop
  • session.archive
  • session.unarchive
  • session.wait.idle
  • session.message.send
  • session.run.start
  • session.run.send
  • session.run.stop

That is what makes them available not just from the CLI, but also from external MCP hosts and session agents when the relevant surface is enabled.

Approvals and action gating

Session control commands are implemented as actions.

That means:

  • each action can be enabled/disabled per surface (UI / CLI / session-agent / voice / external MCP)
  • each action can optionally require approval per surface

When a command is approval-gated, the CLI returns an “approval request created” payload instead of executing immediately. Approve/deny in the app Inbox:

Decide approvals from the CLI (advanced)

For automation-heavy workflows, the same approval flow is also available through the generic action executor.

Example:

# 1) run an approval-gated command
happier session set-title <session-id> "New title" --json

# 2) approve it through the generic action path
happier session actions execute <session-id> approval.request.decide \
  --input-json '{"artifactId":"<approval-artifact-id>","decision":"approve"}' \
  --json

This is the same approval object that the app Inbox shows. Most users should review in the app, but scripted operators can decide approvals through the action surface when that fits their workflow.

Actions (advanced scripting)

Discover actions:

happier session actions list --json
happier session actions describe <action-id> --json

Execute an action:

happier session actions execute <session-id> <action-id> --input-json '<json>' --json

Current JSON envelopes:

  • session actions list --json returns data.actionSpecs
  • session actions describe <action-id> --json returns data.actionSpec
  • session actions execute ... --json returns data.result

Execution runs

Execution runs are the structured “run” layer for multi-step flows (review / plan / delegate / voice agent):

happier session run start <session-id> --intent <intent> --backend <backend-target-key> --permission-mode auto --json
happier session run list <session-id> --json
happier session run get <session-id> <run-id> --json
happier session run send <session-id> <run-id> "message" --json
happier session run stop <session-id> <run-id> --json
happier session run wait <session-id> <run-id> --timeout 300 --json

Execution-run inputs use the same preferred read_only, default, auto, and yolo vocabulary. Older workspace_write, safe-yolo, acceptEdits, and bypassPermissions inputs remain accepted; returned run state retains the compatible read_only / workspace_write wire projection.

Advanced run control:

happier session run action <session-id> <run-id> <action-id> --input-json '<json>' --json
happier session run stream-start <session-id> <run-id> "message" --json
happier session run stream-read <session-id> <run-id> <stream-id> --cursor 0 --json
happier session run stream-cancel <session-id> <run-id> <stream-id> --json

On this page