hangar create
Create a Hangar and start it.
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
| Argument | Type | Description |
|---|---|---|
NAME | string | Letters and numbers, 5 to 45 characters. Permanent. Required. Must match ^[a-zA-Z0-9]{5,45}$. |
Flags
| Flag | Type | Description |
|---|---|---|
--agent | strings | Coding agent to install, repeatable. Without it, claude-code and codex are installed. One of codex, claude-code, pi, omp, devin, opencode, cursor. Repeatable. |
--terminal-only | bool | Install no agents. Not valid with --agent. |
--env | strings | KEY=VALUE, repeatable. Values are never printed back. Repeatable. |
--env-group | strings | Shared variable group to assign, by name or id, repeatable. Where two set the same key, the one given later wins. Repeatable. |
--idle-timeout | string | How 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. |
--repo | string | GitHub repository to clone on the first start, as owner/name. Requires --branch. |
--branch | string | Branch to clone, usually main. Required with --repo. |
--public-repo | bool | The repository is public, so no installation is needed to read it. Only with --repo. |
The global flags apply as well.
Output
| Field | Type | Description |
|---|---|---|
id | string | |
name | string | Immutable and lower case. Unique in the team among Hangars and applications together. |
displayName | string | null | The name as it was typed at creation. |
status | string | Effective 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. |
paused | bool | |
agents | array | The coding agents installed, by id. Empty for a terminal-only Hangar. |
size | string | Instance type code, e.g. op-46. Set by the platform. |
diskGb | int | The disk's size in GB. Set by the platform. |
idleTimeoutMinutes | int | null | How 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. |
ports | array | The 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. |
repository | string | null | Owner/name on GitHub, cloned into ~/<name> on its first start. null for none. Set at creation and never changed. |
branch | string | null | The branch cloned. null without a repository. |
publicSource | bool | The repository is read without a GitHub installation. |
createdAt | string | null | RFC 3339, UTC. |
envCount | int | How many variables were set. Values are never returned. |
envGroups | array | The names of the variable groups assigned, in the order given. |
changed | bool | False for a dry run. |
Examples
With the agents the console preselects
outplane hangar create myhangarWith one agent and no idle timeout
outplane hangar create myhangar --agent codex --idle-timeout neverWith a repository cloned in on its first start
outplane hangar create myhangar --repo acme/web --branch mainWith a variable and a shared group
outplane hangar create myhangar --env LOG_LEVEL=debug --env-group sharedCreate 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, andoutplane hangar connectis 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 listdoes 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 resumestarts it again.outplane hangar update --idle-timeoutchanges 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 --hangarandoutplane env group assign --hangarchange 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 atoutplane reposand 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:
| Exit | Kind | Meaning |
|---|---|---|
2 | usage | Invalid arguments, unknown flag, or client-side validation failure. |
3 | auth | Not authenticated, token revoked or expired, or forbidden for this team. |
5 | not_found | The named resource does not exist, or is not visible to this credential. |
6 | conflict | The resource already exists, or a concurrent change won. |
7 | quota | Plan limit reached or payment required. Not a rate limit; retrying will not help. |
8 | upstream | The 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.