Out Plane
hangar

hangar create

Create a Hangar and start it.

writes--dry-run

Creates a Hangar and starts it. The agents are installed on its first start, each in a window of its own, and without --agent you get claude-code and codex. --terminal-only installs none, and the Hangar opens on a plain shell.

Variables and variable groups are set here as well. Each agent signs in from its own window with your account, and an agent that reads an API key from a variable can be given one here with --env instead. env set --hangar and env group assign --hangar change them later, and a change applies the next time the Hangar starts.

--repo and --branch pick a GitHub repository to clone into the home directory under its own name, once, on the first start. A private one is read through the GitHub installation you granted, as for app create, and --public-repo reads a public one without it; repos lists what you can pick. To push from the Hangar, sign in to GitHub in its terminal, as Push from a Hangar describes. --repo needs outplane v0.2.15 or newer.

The command returns while the Hangar is still starting. Poll hangar get until status is ready, then connect. The name is permanent, follows the application rule of letters and numbers, 5 to 45 characters, and is shared with applications.

Usage

outplane hangar create <NAME> [flags]

Arguments

ArgumentTypeDescription
NAMEstringLetters and numbers, 5 to 45 characters. Permanent. Required. Must match ^[a-zA-Z0-9]{5,45}$.

Flags

FlagTypeDescription
--agentstringsCoding agent to install, repeatable. Without it, claude-code and codex are installed. One of codex, claude-code, pi, omp, devin, opencode, cursor. Repeatable.
--terminal-onlyboolInstall no agents. Not valid with --agent.
--envstringsKEY=VALUE, repeatable. Values are never printed back. Repeatable.
--env-groupstringsShared variable group to assign, by name or id, repeatable. Where two set the same key, the one given later wins. Repeatable.
--idle-timeoutstringHow long the Hangar may sit idle before it pauses, as a duration or never. Idle means no output in its terminal and no key from anyone connected. Defaults to 30m. One of 15m, 30m, 1h, 2h, 6h, 12h, 24h, never.
--repostringGitHub repository to clone on the first start, as owner/name. Requires --branch.
--branchstringBranch to clone, usually main. Required with --repo.
--public-repoboolThe repository is public, so no installation is needed to read it. Only with --repo.

The global flags apply as well.

Output

FieldTypeDescription
idstring
namestringImmutable and lower case. Unique in the team among Hangars and applications together.
displayNamestring | nullThe name as it was typed at creation.
statusstringEffective state, read as app list reads an application's: paused outranks the rest. deploying while it starts, ready once it runs, failed when it could not start, crashed when it stopped unexpectedly and is restarting, or unknown:N. The field to branch on.
pausedbool
agentsarrayThe coding agents installed, by id. Empty for a terminal-only Hangar.
sizestringInstance type code, e.g. op-46. Set by the platform.
diskGbintThe disk's size in GB. Set by the platform.
idleTimeoutMinutesint | nullHow long it may sit idle before it pauses, in minutes: 15, 30, 60, 120, 360, 720 or 1440. null for never. Changed with hangar update.
portsarrayThe ports open for its dev servers, lowest first: {port, scheme, public, url, internal}. url is null on a private port; internal is name:port, where the team's applications reach it.
repositorystring | nullOwner/name on GitHub, cloned into ~/<name> on its first start. null for none. Set at creation and never changed.
branchstring | nullThe branch cloned. null without a repository.
publicSourceboolThe repository is read without a GitHub installation.
createdAtstring | nullRFC 3339, UTC.
envCountintHow many variables were set. Values are never returned.
envGroupsarrayThe names of the variable groups assigned, in the order given.
changedboolFalse for a dry run.

Examples

With the agents the console preselects

outplane hangar create myhangar

With one agent and no idle timeout

outplane hangar create myhangar --agent codex --idle-timeout never

With a repository cloned in on its first start

outplane hangar create myhangar --repo acme/web --branch main

With a variable and a shared group

outplane hangar create myhangar --env LOG_LEVEL=debug --env-group shared

Create one and read its id and state in a pipeline

outplane hangar create myhangar --json --fields id,status
{
  "id": "3f2b1c4e-0000-0000-0000-000000000000",
  "status": "deploying"
}

Check the request without sending it

outplane hangar create myhangar --terminal-only --dry-run --json
{
  "agents": [],
  "changed": false,
  "id": null,
  "idleTimeoutMinutes": 30,
  "name": "myhangar"
}

What to Know

  • Creating starts the Hangar. The command returns as soon as it exists, with status deploying; outplane hangar get <name> reports when it is ready, and outplane hangar connect is refused with hangar.not_running until then.
  • A Hangar that is created but cannot start still exits 0, with status failed. Its name stays taken until it is deleted.
  • The name is stored in lower case, and the name as typed becomes the display name. name in the result is the one other commands take.
  • Applications and Hangars share one set of names. A name an application already has is refused with exit 6 and hangar.name_taken, although hangar list does not show it.
  • A team has a fixed maximum number of Hangars. Reaching it is exit 7 with hangar.limit_reached; retrying never helps, and deleting one makes room.
  • Without --agent, claude-code and codex are installed, as in the console. --terminal-only installs none.
  • Without --idle-timeout, the Hangar pauses after 30 minutes idle. With an idle timeout, the platform checks every 5 minutes and pauses a Hangar whose terminal has had no output in any window and no key from anyone connected for that long, so 30m pauses it 30 to 35 minutes after the last activity. A paused Hangar keeps its disk, its ports and its variables, and outplane hangar resume starts it again. outplane hangar update --idle-timeout changes it later.
  • The size and the disk are set by the platform, not by a flag. Under --dry-run they are null, as are id and status.
  • Variable values are never echoed back; envCount reports how many were set. A variable set with --env wins over a group's, and between groups the one given later wins. A group used only at build reaches nothing here, because a Hangar never builds. outplane env set --hangar and outplane env group assign --hangar change them afterwards, and a change applies the next time the Hangar starts.
  • --env-group takes a name or an id. Each one is resolved with a request of its own before anything is sent, under --dry-run as well.
  • --repo is cloned into ~/<name> once, on the first start, at --branch, which it requires. A clone that fails is not tried again: the Hangar's terminal says why and gives the command to clone it by hand. The repository cannot be changed afterwards. --branch or --public-repo without --repo is hangar.repository_required.
  • A private repository is read through the GitHub installation of the user whose token this is, as for app create; --public-repo skips that. hangar.repository_unavailable means the platform cannot see it, and the error points at outplane repos and the page that grants access.
  • Out Plane only clones. To push, and to fetch a private repository later, sign in to GitHub in the Hangar's terminal with gh auth login, or with a token for that repository.
  • Everything the server would refuse is checked first, so an error names the field. The exceptions are the name being taken, the team's limit, and whether the repository and its branch can be read, which only the server knows.

Errors

Beyond 0 for success, this command exits with:

ExitKindMeaning
2usageInvalid arguments, unknown flag, or client-side validation failure.
3authNot authenticated, token revoked or expired, or forbidden for this team.
5not_foundThe named resource does not exist, or is not visible to this credential.
6conflictThe resource already exists, or a concurrent change won.
7quotaPlan limit reached or payment required. Not a rate limit; retrying will not help.
8upstreamThe Out Plane API returned a server error.

The code on the error object is one of hangar.name_invalid, hangar.name_reserved, hangar.name_taken, hangar.agent_invalid, hangar.agent_duplicate, hangar.agent_conflict, hangar.idle_timeout_invalid, hangar.env_group_duplicate, hangar.repository_invalid, hangar.branch_required, hangar.repository_required, hangar.repository_unavailable, hangar.limit_reached, envgroup.not_found, envgroup.ambiguous, env.reserved_key, env.reserved_prefix, usage.missing_argument, usage.empty_argument, usage.bad_assignment, usage.duplicate_key, context.no_team. Branch on that, or on the exit status. The message is prose and changes.

On this page