Session Launch
Spawn a revision-pinned interactive session from the CLI with the same launch parameters the web start-session form sends.
Coming soon. rensei session launch is merged into rensei-tui's main branch and code-complete, but it has not shipped in a tagged release yet (the latest release as of this page is v0.14.27). Until a release ships it, launch sessions from the web start-session screen instead - see Interactive Sessions. This page documents the shipped behavior in advance so scripts can be written against it; check rensei --version once a release carries it.
rensei session launch spawns an interactive PTY session with exactly the parameters the web start-session form sends: the same revision-pinned execution-axis selection, the same initial-prompt handling, and the same two-call shape underneath (read the project's authorized launch options, then submit a pinned selection built from them). Anything you can launch from the browser you can launch from a script, a runbook, or a smoke test, in one command.
The PTY session host and the wire protocol carrying keystrokes and screen updates are OSS, documented at donmai.dev/docs/sessions. This page covers the platform CLI's launch surface.
Auth precondition
rensei session launch requires a user login:
rensei auth add --userThe interactive-session routes accept a human user identity only. An org API key (rsk_*) or a project-scoped token carries no user identity, so it can neither launch nor drive an interactive session. This is the same auth posture as rensei session attach, and it is checked twice: if a named auth context is active and it is not a user login, the CLI refuses locally before sending any request; a bare non-user token (for example via --token-stdin) is not provably a user token client-side, so it is sent and the platform itself refuses with 403. See Troubleshooting for the exact message each path prints.
Selection rules
Every selector (--pool, --profile, --harness, --repo) accepts either the option's id or its display name, matched case-insensitively against the project's current, authorized launch options - the same list the web picker renders. --repo additionally matches the repository's owner/name path, with or without its provider prefix: acme/api and github:acme/api both resolve.
- Unmatched or ambiguous values fail closed. A value that matches nothing, or that matches more than one option, refuses the launch and lists every option the project actually offers (id, label, and availability) instead of guessing.
- Omitted axes fall back to the project's default for that axis. Every axis is optional; a launch that pins none of them still succeeds, materialized by the platform's own default cascade at dispatch.
- Options are checked, not hidden. An option that resolves but is not currently
available(for example, a pool the resolved profile cannot run on) is still accepted, with a note that the platform may refuse the launch. The CLI defers to the platform's own dispatch-time validation rather than second-guessing it.
Harness derivation is not an independent axis
The launch-options route returns one harness option per model profile per candidate harness, because one profile's execution cell can legitimately declare several harnesses (a byok profile might derive both claude and pi). Because of that:
- An overridden
--profilewith no--harnessderives the harness from that profile: its firstavailablecandidate, exactly as the web picker does, taggedprofile-derivedin the resolved selection. It never falls back to the project's default harness, which likely belongs to a different profile and would be refused at dispatch. --harnessgiven without a profile that derives it refuses the ambiguity and names the model profile(s) that do derive it, with a hint to pass--profilealongside it.
Client-side bounds
Three bounds are enforced locally, before any request is sent, using the exact limits the platform applies - so a violation is reported instantly instead of after a round trip:
| Flag | Bound |
|---|---|
--handle | 1 to 64 characters after trimming. A value that trims to empty is refused rather than silently dropped, since an addressable session was asked for. |
--max-duration | Must be a positive number of seconds. 0, the flag's own default, means no cap; a negative value is refused. |
--prompt / --prompt-file | 1023 UTF-8 bytes after trimming, measured in bytes rather than characters (accented characters and emoji cost more than one byte each). An over-limit prompt is refused with its measured size, never silently truncated. |
Flags
| Flag | Web form counterpart | Description |
|---|---|---|
--project <slug> | The project the start-session screen is opened in | Project slug to launch in. Defaults to the active project. |
--handle <name> | The session-name field (shown when the firing template declares an agentHandle parameter) | Durable A2A handle for the session, 1 to 64 characters. Omit to launch unaddressable. |
--pool <id|name> | Capacity pool selector | Capacity pool id or display name. |
--profile <id|name> | Model profile selector | Model profile id or display name. |
--harness <id|name> | Harness selector (auto-derived once a profile is picked) | Harness id or display name, e.g. claude, codex. |
--repo <id|name|owner/name> | Repository selector | Repository id, display name, or owner/name path. |
--branch <name> | None - the one documented exception | Branch the session's workspace checks out. Needs a resolved repository. |
--worktree <name> | None - the one documented exception | Worktree directory name for the session's workspace. Needs a resolved repository. |
--setup-command <cmd> | None - the one documented exception | Command run once the workspace is checked out. Needs a resolved repository. |
--prompt <text> | "Prompt and limits" panel, initial prompt | Seed prompt injected as the session's first input. |
--prompt-file <path> | Same panel | Read the seed prompt from a file. - (stdin) is not supported. |
--max-duration <seconds> | Same panel, max duration | Maximum session duration in seconds. |
--local-auth / --no-local-auth | Same panel, local-auth toggle | Declare local auth available or unavailable for this session. Omit to take the platform's own per-pool default; the two flags are mutually exclusive. |
--capability <key>=on|off (repeatable) | Capabilities & providers toggles | Toggle one capability/provider. Keys: memory, a2a, codeIntel, architecture, credential, issueTracker, kit, model. Absence leaves the platform's Composer-resolved default (enabled); only an explicit off disables one. |
--wait | None - CLI-only | Block until the session is active or terminal. |
--wait-timeout <duration> | None - CLI-only | How long --wait blocks before giving up. Default 5m. |
--attach | None - CLI-only | Attach your terminal once the session is active. Implies --wait. |
--json | None - CLI-only | Emit the launch result, the resolved selection, and the final status as one JSON object on stdout. Every human-readable line moves to stderr so a script can parse stdout cleanly. |
--dry-run | None - CLI-only | Print the resolved request body as JSON without launching. Still reads the project's live launch options (and so still needs a valid project and auth); only the launch POST is skipped. |
The workspace bootstrap flags (--branch, --worktree, --setup-command) are the one documented exception to "the same parameters the web form sends." The start-session screen does not offer them, even though the launch route accepts them - today they reach the platform from the spawn and workflow-node paths only. They layer on top of the resolved repository and require one: pass --repo (or rely on the project's repository default) alongside any of them, or the launch is refused - see Troubleshooting.
Examples
# Plain launch with a seed prompt.
rensei session launch --project acme --handle cfo --prompt "audit Q3 spend"# Preview the exact request body without launching.
rensei session launch --project acme --dry-run --json# Launch on a specific pool and block until the session comes up.
rensei session launch --project acme --pool studio --wait# Launch unaddressable and drop straight into the terminal.
rensei session launch --handle scratch --attach# Seed from a file and bootstrap a workspace on a resolved repository.
rensei session launch --project acme --pool studio --repo acme/api \
--branch feat/quarterly-close --worktree quarterly-close \
--setup-command "pnpm install" --prompt-file ./brief.md --attach# Script-friendly: launch, wait for it to come up, capture the session id.
SESSION_ID=$(rensei session launch --project acme --wait --json | jq -r .sessionId)
echo "launched $SESSION_ID"Semantics
A launch returns as soon as the session is admitted and dispatched, in status provisioning - that is not yet running. --attach implies --wait; both block until the session reaches active, bounded by --wait-timeout (default 5m), and exit non-zero if the session ends or fails before it does.
A client-side --wait timeout means the outcome is UNKNOWN, not failed. The launch POST itself already succeeded (the session id is in hand) before --wait starts polling, so a timeout only means the session has not reached active yet inside the wait window - it may still come up. Worse, if the launch request itself times out before any response arrives, the platform may have admitted the session anyway (admission commits durable rows and consumes quota before it answers). Either way, check rensei session list before retrying: retrying blind may create a second session and draw quota twice.
If --wait/--attach are omitted, the command prints attach with: rensei session attach <id> so the session id is never the only thing you have to go find yourself.
Troubleshooting
409/422/429 responses are typed refusals: internal/api/interactive.go's Remedy() unwraps each into the one-sentence guidance quoted below (the platform's own prose is written for the web form and would tell you to "refresh the page," which does not apply to a CLI). 403 is different and is not covered by Remedy() at all - one 403-shaped case is caught entirely client-side before any request is sent, and the other reaches the platform and is surfaced with the platform's own message, verbatim, with no CLI-synthesized remedy.
| Status | Code | Cause | Remedy |
|---|---|---|---|
| (local preflight, no request sent) | - | Not authenticated, or the active named auth context is not a user login (for example an org API key) | Quoted verbatim from the CLI. Unauthenticated: not authenticated - run 'rensei auth add --user' first. Named non-user context active: interactive sessions need a user login, but the active auth context "<name>" is a org_token - run 'rensei auth add --user' and select it with --auth. Org API keys carry no user identity, so they cannot drive a terminal. |
| 409 | INTERACTIVE_LAUNCH_SELECTION_INVALID | The pool, profile, harness, or repository you resolved changed, or is no longer available to you, since the launch options were read | The named axis changed or is no longer available; re-run the command (it re-reads the options) or pick another value. |
| 409 | INTERACTIVE_COMPOSITION_DENIED | The project's Agent Composer cannot be composed with the resolved selection | The project's Agent Composer cannot be composed for this launch; if fields are named, they are the unsatisfied Composer inputs. |
| 409 | INTERACTIVE_LAUNCH_NOT_CONFIGURED, reason WORKSPACE_BOOTSTRAP_NO_REPOSITORY | --branch / --worktree / --setup-command were passed but no repository resolved | --branch/--worktree/--setup-command need a repository to apply to; pass --repo or drop them. |
| 409 | INTERACTIVE_LAUNCH_NOT_CONFIGURED, other reason codes | An org configuration gap blocks the launch | Org configuration gap (named by the reason code); fix it where the message points, then relaunch. |
| 422 | AUTH_MODE_UNAVAILABLE | No configured authentication mode is viable for the resolved profile/pool | No configured authentication mode is viable for this project; wire a credential or model profile that is. |
| 422 | CREDENTIAL_CONTENT_UNSATISFIABLE | The wired credential cannot supply what the resolved execution cell needs | The wired credential cannot satisfy this execution cell's requirements; missing env vars are named when known. |
| 429 | (quota) | The org's interactive-session quota is exhausted | Quota exhausted (current/limit shown when known); wait for a session to end and retry. |
| 403 | (access denied) | A bare non-user token (for example via --token-stdin) reached the platform and turned out to have no access to the project, or the org is not entitled to interactive sessions | Not synthesized by the CLI: the platform's own message is surfaced verbatim (no attach access to this interactive session: <platform message>). Check the account's project access, or switch to a user login (rensei auth add --user); see Auth precondition. |
Related pages
- Interactive Sessions - the execution-axis picker, initial-prompt handling, presence/driver model, and reconnect behavior this command mirrors
- donmai.dev - Sessions - the OSS PTY host and wire protocol canonical reference
- Quotas & Plans - concurrency, duration, and monthly-hour limits by plan