> ## Documentation Index
> Fetch the complete documentation index at: https://orbit.nckrtl.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# instance

> Create, register, reconcile a renamed branch or domain, set up, clone, deploy, roll back, and remove Instances.

An Instance is one copy of a Project on one Node. On an `app-dev` Node it owns a checkout or worktree. On an `app-prod` Node it owns a Unix user and a production home with releases. The [Project type](/docs/reference/projects#project-types) decides whether it gets a Route.

[Applications](/docs/domains/applications) walks through the lifecycle. [Production release layout](/docs/reference/deployments), [Instance setup and teardown](/docs/reference/instance-setup), [Instance cloning](/docs/reference/instance-cloning), [Instance transfer](/docs/reference/instance-transfer), [Instance removal](/docs/reference/instance-removal), and [Database connections](/docs/reference/database-connections) own the contracts behind these commands.

## Commands

Instance JSON includes nullable `seed_path` and `seed_commit`. On `default`, these name its checkout and the last commit that deployed there. Read them before creating a linked worktree for `instance:register`; use that commit rather than a newer `origin/main`. Human tables keep their existing columns.

Every command accepts `--json`. Machine output never supplies consent. Human list commands use tables, with labeled records when the terminal is too narrow; detail commands show a tree and slow requests show progress. `instance:deploy` and `instance:rollback` return newline-delimited JSON (NDJSON) instead of one document.

Placement commands create, adopt, inspect, and remove an Instance on one Node.

| Command | Result |
| - | - |
| [`instance:create`](#orbit-instancecreate) | Create a development Instance on an app-dev Node and run its Project setup steps. |
| [`instance:register`](#orbit-instanceregister) | Adopt the current Git checkout or worktree as a managed Instance. |
| [`instance:setup`](#orbit-instancesetup) | Run the Project setup steps for one development Instance. |
| [`instance:setup-step:create`](#orbit-instancesetup-stepcreate) | Record one named setup step on a Project. |
| [`instance:setup-step:list`](#orbit-instancesetup-steplist) | List a Project's setup steps. |
| [`instance:setup-step:update`](#orbit-instancesetup-stepupdate) | Change one named setup step. |
| [`instance:setup-step:destroy`](#orbit-instancesetup-stepdestroy) | Remove one named setup step. |
| [`instance:teardown-step:create`](#orbit-instanceteardown-stepcreate) | Record one named teardown step on a Project. |
| [`instance:teardown-step:list`](#orbit-instanceteardown-steplist) | List a Project's teardown steps. |
| [`instance:teardown-step:update`](#orbit-instanceteardown-stepupdate) | Change one named teardown step. |
| [`instance:teardown-step:destroy`](#orbit-instanceteardown-stepdestroy) | Remove one named teardown step. |
| [`instance:list`](#orbit-instancelist) | List Instances. |
| [`instance:show`](#orbit-instanceshow) | Show one Instance with its Route, source, and deploy steps. |
| [`instance:rename`](#orbit-instancerename) | Record an already checked-out branch and change a development checkout's Route domain. |
| [`instance:transfer`](#orbit-instancetransfer) | Move a development Instance to another Node. |
| [`instance:destroy`](#orbit-instancedestroy) | Remove an Instance and its owned Processes, Schedules, and Route. |
| [`instance:logs`](#orbit-instancelogs) | Return the application log tail, or follow new lines. |

Release commands prepare and operate a production Instance.

| Command | Result |
| - | - |
| [`instance:clone`](#orbit-instanceclone) | Clone a candidate into a prepared production Instance. |
| [`instance:update`](#orbit-instanceupdate) | Change the deployment branch of a production Instance. |
| [`instance:deploy-step:create`](#orbit-instancedeploy-stepcreate) | Record one named deploy step. |
| [`instance:deploy-step:list`](#orbit-instancedeploy-steplist) | List deploy steps in phase and placement order. |
| [`instance:deploy-step:update`](#orbit-instancedeploy-stepupdate) | Change one named deploy step. |
| [`instance:deploy-step:destroy`](#orbit-instancedeploy-stepdestroy) | Remove one named deploy step. |
| [`instance:deploy`](#orbit-instancedeploy) | Deploy the configured branch as a fresh release. |
| [`instance:release:list`](#orbit-instancereleaselist) | List retained releases and the current selection. |
| [`instance:rollback`](#orbit-instancerollback) | Select one retained release. |
| [`instance:deployment:list`](#orbit-instancedeploymentlist) | List recorded deployment history, newest first. |
| [`instance:deployment:show`](#orbit-instancedeploymentshow) | Show one recorded deployment, its phases and steps, and its log. |

Attachment commands write a registered Database connection into stored Instance configuration.

| Command | Result |
| - | - |
| [`instance:database:add`](#orbit-instancedatabaseadd) | Add a Database connection and write prefixed stored environment keys. |
| [`instance:database:remove`](#orbit-instancedatabaseremove) | Remove a Database connection and clear those keys. |

Analytics commands publish the tracking hosts that send visits to the [analytics role](/docs/reference/analytics).

| Command | Result |
| - | - |
| [`instance:analytics:enable`](#orbit-instanceanalyticsenable) | Publish the tracking hosts of an Instance. |
| [`instance:analytics:show`](#orbit-instanceanalyticsshow) | Show the tracking hosts, their DNS records, and the script tag. |
| [`instance:analytics:disable`](#orbit-instanceanalyticsdisable) | Remove every tracking host. |

Dependency commands read and update the root packages of an Instance. [Instance dependencies](/docs/reference/instance-dependencies) owns the inventory and refresh rules.

| Command | Result |
| - | - |
| [`instance:dependencies:scan`](#orbit-instancedependenciesscan) | Record the Composer and JavaScript packages of one or every Instance. |
| [`instance:dependencies:update`](#orbit-instancedependenciesupdate) | Update the packages of a development Instance within their constraints. |

## orbit instance:create

Create a development Instance on a Node with the active `app-dev` role. A Node with the active `app-prod` role returns `instance.candidate_required`, including a repeat for an existing production Instance. Create a production Instance with [`instance:clone`](#orbit-instanceclone).

```bash theme={"dark"}
orbit instance:create <project> <node> <name> [options]
```

| Argument | Required | Meaning |
| - | - | - |
| `project` | yes | Numeric Project ID. |
| `node` | yes | Numeric Node ID. |
| `name` | yes | Instance name. `default` is reserved for the Project's default development source. |

| Option | Default | Meaning |
| - | - | - |
| `--root=PATH` | the Project root | Relative web-root override for this Instance. |
| `--domain=HOST` | generated | Explicit Route domain for the development source. Without it, Orbit generates a domain from the active Cluster TLD, then the Node TLD. |
| `--branch=BRANCH` | see [branch selection](/docs/domains/applications#create-a-development-instance) | Explicit source branch. |
| `--database-server=SLUG` | none | Create the Instance's database on this [Database server](/docs/reference/database-servers) before the setup steps run. Only for an Instance that this create makes; an Instance that finished setup returns `instance.database_server_existing`. See [database on a server](/docs/domains/applications#database-on-a-server). Needs access to the Gateway too. |

Development placement and branch selection follow the requested name.

| Creation input | Managed placement | Selected branch |
| - | - | - |
| `default` without `--branch` | `<node-apps-root>/<project-slug>/default` | The Project `default_branch`. |
| Another name without `--branch` | `<node-apps-root>/<project-slug>/<name>` | The matching origin branch, otherwise the existing local branch, otherwise a new branch from the fetched `default_branch` commit. |
| Any name with `--branch` | The placement for the requested name | The requested origin branch, otherwise the existing local branch, otherwise a new branch from the fetched `default_branch` commit. It need not match the Instance name. |

```bash theme={"dark"}
orbit instance:create 4 7 default
orbit instance:create 4 7 feature-one --branch=release --domain=feature.example.test
orbit instance:create 4 7 t3-1a2b3c4d --branch=t3code/1a2b3c4d
```

A requested origin branch keeps its existing selection behavior. Orbit does not reset an existing local branch to the default commit. A missing fetched `default_branch` when required returns `instance.branch_resolution_failed`, not a different fallback branch. An invalid Git branch name returns `validation.failed` before source changes.

A create that fails before activation removes its owned resources and Instance row without teardown. The response keeps the original error code. Once cleanup completes, a new create can select a different branch. If an interruption or incomplete cleanup leaves a pre-activation Instance, an identical retry resumes it; a retry that changes the root or `--branch` returns `instance.placement_conflict`. Incomplete cleanup reports `details.cleanup = "incomplete"` and a recovery command. An identical retry finishes a started cleanup first, without `--force`, and then creates the Instance. [`instance:destroy`](#orbit-instancedestroy) accepts `reserved`, `checkout_prepared`, and `source_resolved` for [pre-activation removal](/docs/reference/instance-removal#pre-activation-removal).

<Note>
  The Instance becomes active once Orbit has prepared the source, PHP runtime, Laravel URL, and Route. Setup runs after that. A successful create response also means every setup step succeeded; an empty list counts as success. The application can still fail for other reasons.
</Note>

A failed setup step removes the new Instance after the teardown steps run. A missing or non-executable setup command returns `instance.setup_step_unavailable` with `outcome: missing`, naming the step, Node, and exit 127 or 126. That classification and diagnostic survive rollback, including an incomplete or unconfirmed cleanup annotation. Other command failures return `instance.setup_step_failed`. See [Instance setup and teardown](/docs/reference/instance-setup#run-setup).

## orbit instance:rename

Record a Git branch that is already checked out, change the Instance's Route domain, or do both. Only an active development checkout is eligible. This command does not rename the Instance, move its directory, change its starting commit, or run Git commands that alter the checkout.

```bash theme={"dark"}
orbit instance:rename <instance> [--branch=BRANCH] [--domain=HOST] [--json]
```

| Argument | Required | Meaning |
| - | - | - |
| `instance` | yes | Positive numeric Instance ID. |

| Option | Default | Meaning |
| - | - | - |
| `--branch=BRANCH` | unchanged | Record this local branch. Symbolic `HEAD` must already name it. |
| `--domain=HOST` | unchanged | Replace the domain of the Instance's own single-target Project Route, including a generated Route. |
| `--json` | off | Return one Instance JSON document, or one error document, without prompts or progress. |

Supply at least one of `--branch` and `--domain`. Supplied values must be nonempty strings. The command needs no `--yes` or `--force`: it records intent and converges the Route without discarding source. In a terminal, an omitted Instance selector uses the shared Instance selection prompt; in noninteractive or JSON mode it returns `instance.id_invalid`. There is no implicit branch or domain selection.

Rename the branch locally before recording it. Orbit checks the managed checkout's identity and the supplied branch locally on the Node, with no origin access. A dirty or unpublished branch can be recorded. Normal removal still requires clean, published source.

```bash theme={"dark"}
# In the Instance checkout:
git branch -m t3code/login-redirect
orbit instance:rename 1 --branch=t3code/login-redirect
orbit instance:rename 1 --domain=login-redirect.acme.test
orbit instance:rename 1 --branch=t3code/login-redirect --domain=login-redirect.acme.test --json
```

A changed branch updates `selected_branch` and `branch_override`. Recording the already recorded branch is a no-op that preserves its existing override. A domain-only request does not change either branch field. The domain follows [Route replacement](/docs/reference/routes#change-an-instance-route-domain); Laravel's stored `APP_URL`, `.env`, and cached configuration follow it. Generated provenance stays generated, so a later Project slug or effective-TLD change can recompute the domain.

All supplied fields, checkout identity, the supplied branch, and domain availability are checked before mutation. A combined request with a branch mismatch or domain conflict changes nothing. A changed branch is recorded only after any requested domain convergence succeeds. An identical retry after a completed rename returns the Instance without creating an additional Route, including when the caller lost the success response. An incomplete Route replacement follows the existing recovery rules. If a full rollback before cutover deleted the failed replacement, an identical retry can reserve a fresh replacement; the changed branch is still recorded only after domain convergence succeeds. A different domain while replacement recovery is incomplete is refused. See [recorded branch behavior](/docs/domains/applications#record-a-renamed-branch) and [Route recovery](/docs/reference/routes#resume-or-refuse-a-change).

### Human output

The command shows truthful waiting feedback during the synchronous request, then the shared Instance detail tree. Project and Node labels use their slug and name. It does not show a Process selector or invent remote progress stages. The following abbreviated example shows the fields affected by a combined rename; the full tree also has the usual ID, placement, root, and Vite-port fields:

```text theme={"dark"}
┌  Instance: dev
│
├  Project           acme
│
├  Node              app-dev
│
├  Selected branch   t3code/login-redirect
│
├  Branch override   t3code/login-redirect
│
├  Domain            login-redirect.acme.test
│
└  URL               https://login-redirect.acme.test
```

A refusal shows the stable error code and a useful message, with no success tree. For example, `instance.branch_not_checked_out` tells the caller to check out the requested branch first. Success exits with status `0`; a refusal or failed convergence exits with status `1`.

### JSON and API output

The API is `POST /api/v1/instances/{instance}/rename` with optional `branch` and `domain`, for example `{"branch":"t3code/login-redirect","domain":"login-redirect.acme.test"}`. At least one field is required; null, empty, and wrong-type values are invalid. The MCP tool is `instance-rename`, with `instance_id` and the same optional fields.

Success returns the full Instance shape used by `GET /api/v1/instances/{instance}` and `instance:show --json`, including Project and Node identities, source and placement fields, `route`, `domain`, `url`, removal and transfer state, deploy steps, and `request_id`. It has no rename-specific envelope. This abbreviated JSON example selects fields from that response, not a separate response schema:

```json theme={"dark"}
{
  "id": 1,
  "name": "dev",
  "project": {"id": 1, "name": "Acme", "slug": "acme"},
  "node": {"id": 1, "name": "app-dev"},
  "source_layout": "checkout",
  "checkout_path": "/srv/orbit/apps/acme/dev",
  "selected_branch": "t3code/login-redirect",
  "branch_override": "t3code/login-redirect",
  "status": "active",
  "domain": "login-redirect.acme.test",
  "url": "https://login-redirect.acme.test"
}
```

Failures use the existing error shape, with the stable code under `error.code`, the message under `error.message`, and the request correlation ID under `error.request_id`. JSON output contains no human tree, prompt, or animation.

### Refusal codes

| Code | Meaning |
| - | - |
| `validation.failed` | Neither field was supplied, or a supplied value is null, empty, wrong-type, or an invalid Git branch name. |
| `instance.id_invalid` | The CLI Instance selector is missing in noninteractive mode or is not a positive numeric ID. |
| `instance.rename_unsupported` | The Instance is production or is not a development checkout, including linked worktrees. |
| `instance.rename_inactive` | The development checkout is not active and is not being removed. |
| `instance.lifecycle_busy` | Another lifecycle or environment operation owns the Instance, including removal, an incomplete transfer, or clone. |
| `instance.source_identity_invalid` | Local inspection cannot establish the managed checkout's path, ownership, layout, or Project origin identity. |
| `instance.branch_not_checked_out` | The supplied branch is not the current symbolic `HEAD`, including detached `HEAD`. |
| `instance.route_required` | A domain was supplied, but there is no own single-target Project Route. |
| `route.domain_invalid` | The requested domain is invalid. |
| `route.domain_conflict` | Another Route owns the normalized domain, or it is a reserved domain. |
| `route.domain_change_conflict` | A different domain replacement is already in progress. |
| `instance.source_profile_missing` | Domain convergence lacks the recorded source profile needed for URL synchronization. |
| `env.owner_changed` | Route targets or environment ownership changed while acquiring the operation owner. |
| `route.reconciliation_required` | An incompatible Route or placement reconciliation is in progress. |
| `route.domain_change_failed` | Route projection or URL synchronization failed; inspect Route failure details and retry the same request. |

Authentication, access and missing-record errors, and more specific Route projection errors retain the shared API error contract. A preflight refusal changes nothing. Infrastructure failure during convergence follows Route rollback before cutover and forward recovery after cutover; it is not a promise of atomic rollback across the Node and Gateway.

## orbit instance:register

Adopt the current Git checkout or worktree as a managed Instance of an existing Project. Run it on the app-dev Node that holds the source.

```bash theme={"dark"}
orbit instance:register [options]
```

| Option | Default | Meaning |
| - | - | - |
| `--path=PATH` | the current directory | Existing Git checkout or worktree. |
| `--include-worktrees` | off | Adopt the checkout and every linked worktree as one preflighted set. |
| `--project=ID` | resolved from the origin | Existing numeric Project ID. |
| `--name=NAME` | inferred | Non-default Instance name. |
| `--root=PATH` | the Project root | Relative web-root override for this Instance. |
| `--domain=HOST` | generated | Explicit Route domain for the primary source. |
| `--yes` | off | Confirm transfer of the source into Orbit ownership without prompting. |
| `--setup` | off | Run the Project setup steps after adoption. A failed step leaves the Instance and the checkout in place. |

The CLI refuses a directory outside Git and an origin with credentials before it sends a request. The Gateway finds the Project by repository identity, checks the source on the caller's Node, moves it into its managed path, and provisions it as `instance:create` does. See [Register an existing checkout](/docs/domains/applications#register-an-existing-checkout).

Registration never creates a Project. When no Project owns the repository, it fails with `instance.project_missing`. Run [`project:create`](/docs/cli/project#orbit-projectcreate) first.

In a terminal, the CLI asks for default-No consent that names the source. JSON and noninteractive calls need `--yes`. Cancellation leaves the source unchanged.

```bash theme={"dark"}
cd ~/apps/acme
orbit instance:register
orbit instance:register --path=/srv/orbit/apps/acme/main --include-worktrees --yes --json
```

## orbit instance:list

List Instances with their Project, Node, status, Route domain, `vite_port`, and `removal` progress. JSON also includes `annotator_port` and `annotator_url`; both are null when no annotator port is assigned, and the URL is null without a Route. JSON includes the [assigned SSR port](/docs/reference/assigned-ssr-ports) as `ssr_port`, which is null when none is assigned.

```bash theme={"dark"}
orbit instance:list [--json]
```

## orbit instance:show

Show one Instance. When the `annotator` Process has an assigned port, human output includes `Annotator port` and `Annotator URL`. The URL uses the Instance's Route, for example `https://commander.test/__orbit/annotator`; without a Route, the display is an em dash. JSON keeps the `annotator_port` and `annotator_url` fields even when they are null. See [Annotator Process](/docs/reference/agentation#annotator-process). Human output shows the [assigned SSR port](/docs/reference/assigned-ssr-ports) as `SSR port` beside `Vite port`, and JSON has `ssr_port`. Both are empty when no SSR port is assigned.

Production output includes the recorded user, home, selected branch, and deploy steps in phase and placement order.

Human output lists the Instance's Routes with their domain, web root, and status. JSON has them under `routes`; `route` stays the Instance's own Route. See [Serve several web roots](/docs/reference/routes#serve-several-web-roots).

```bash theme={"dark"}
orbit instance:show <instance> [--json]
```

| Argument | Required | Meaning |
| - | - | - |
| `instance` | yes | Numeric Instance ID. |

## orbit instance:logs

Return the end of the Instance's application log, `storage/logs/laravel.log` or the newest `laravel-*.log`, or follow new lines as they are written. Stored environment values and credential-shaped data are redacted. [Instance logs](/docs/reference/instance-logs) describes the file and the redaction.

```bash theme={"dark"}
orbit instance:logs <instance> [--lines=COUNT] [--follow] [--json]
```

| Argument | Required | Meaning |
| - | - | - |
| `instance` | yes | Numeric Instance ID. |

| Option | Default | Meaning |
| - | - | - |
| `--lines=COUNT` | `100` | Number of lines, from 1 through 1,000. With `--follow`, the number of earlier lines to print first. |
| `--follow` | off | Keep printing new lines until Ctrl-C. |

`--follow` works as it does for [`process:logs`](/docs/cli/process#orbit-processlogs): the CLI opens a [live log stream](/docs/reference/live-logs), and it polls the one-shot read every 5 seconds when the Gateway cannot open one. A production Instance log is always read over SSH: the CLI prints `Following over SSH; polling every 5 seconds.` and polls from the start. The JSON output has the same shapes, with reason `ssh_only` in the notice. Without `--follow`, `--json` returns `{ id, name, lines, logs, request_id }`.

```bash theme={"dark"}
orbit instance:logs 12 --lines=50
orbit instance:logs 12 --follow
```

## orbit instance:destroy

Remove an Instance with its Route, Processes, Schedules, and runtime. A development removal runs the teardown steps first and deletes the checkout. See [Instance removal](/docs/reference/instance-removal).

```bash theme={"dark"}
orbit instance:destroy <instance> [--yes] [--force] [--json]
```

| Argument | Required | Meaning |
| - | - | - |
| `instance` | yes | Numeric Instance ID. |

| Option | Meaning |
| - | - |
| `--yes` | Confirm removal without prompting. Required for JSON and noninteractive calls. |
| `--force` | Delete dirty or unpublished development source after identity checks pass, and accept a checkout together with its registered linked worktrees. |

Interactive removal defaults to No. `--force` does not supply consent.

Normal removal refuses dirty source, a `HEAD` that no origin branch or tag contains, and a checkout with registered linked worktrees. `--force` waives only those three refusals. The source identity checks apply in both modes.

```bash theme={"dark"}
orbit instance:destroy 12
orbit instance:destroy 12 --force
```

<Warning>
  Production removal keeps `releases/`, `.env`, `database.sqlite`, and the local PHP-FPM tuning. Repeat the same command to resume an interrupted removal. A failed teardown step keeps the Instance, and the next `instance:destroy` runs the teardown list again.
</Warning>

## orbit instance:setup

Run the Project setup steps for one development Instance. The command runs every step from the start of the list. A failed step leaves the Instance in place.

```bash theme={"dark"}
orbit instance:setup <instance> [--json]
```

| Argument | Required | Meaning |
| - | - | - |
| `instance` | yes | Numeric Instance ID. |

```bash theme={"dark"}
orbit instance:setup 12
```

## orbit instance:setup-step:create

Record one named setup step on a Project. The step is a command string. Orbit stores the row and does not write a file into a checkout.

```bash theme={"dark"}
orbit instance:setup-step:create <name> --project=<id> --command=<command> [--timeout=<seconds>] [--before=<name>|--after=<name>] [--rebalance=<name>=<seconds>]... [--json]
```

| Argument | Required | Meaning |
| - | - | - |
| `name` | yes | Step name, unique within the Project setup list. |

| Option | Default | Meaning |
| - | - | - |
| `--project=ID` | required | Numeric Project ID. |
| `--command=COMMAND` | required | Shell command Orbit runs from the instance directory. |
| `--timeout=SECONDS` | 240 | Timeout from 1 through 540 seconds. The whole list may total at most 540 seconds. |
| `--before=NAME` | none | Insert before this step. Exclusive with `--after`. |
| `--after=NAME` | none | Insert after this step. Exclusive with `--before`. |
| `--rebalance=NAME=SECONDS` | none | Set another step's timeout in the same write. Repeat for each step. Use it to [make room in a full list](/docs/reference/instance-setup#make-room-in-a-full-list). |

```bash theme={"dark"}
orbit instance:setup-step:create install-php --project=4 --command='composer install --no-interaction'
```

[Instance setup and teardown](/docs/reference/instance-setup) owns the field limits, order, and execution contract. List, update, and destroy use the same Project selector and step name.

## orbit instance:setup-step:list

List a Project's setup steps in order.

```bash theme={"dark"}
orbit instance:setup-step:list --project=<id> [--json]
```

## orbit instance:setup-step:update

Change the command, timeout, or position of one setup step. `--rebalance=NAME=SECONDS` sets other steps' timeouts in the same write, as for create.

```bash theme={"dark"}
orbit instance:setup-step:update <name> --project=<id> [--command=<command>] [--timeout=<seconds>] [--before=<name>|--after=<name>] [--rebalance=<name>=<seconds>]... [--json]
```

## orbit instance:setup-step:destroy

Remove one setup step. Interactive confirmation defaults to No. JSON and noninteractive calls require `--yes`.

```bash theme={"dark"}
orbit instance:setup-step:destroy <name> --project=<id> [--yes] [--json]
```

## orbit instance:teardown-step:create

Record one named teardown step on a Project. The arguments match `instance:setup-step:create`.

```bash theme={"dark"}
orbit instance:teardown-step:create <name> --project=<id> --command=<command> [--timeout=<seconds>] [--before=<name>|--after=<name>] [--rebalance=<name>=<seconds>]... [--json]
```

```bash theme={"dark"}
orbit instance:teardown-step:create drop-sqlite --project=4 --command='rm -f database/database.sqlite'
```

## orbit instance:teardown-step:list

List a Project's teardown steps in order.

```bash theme={"dark"}
orbit instance:teardown-step:list --project=<id> [--json]
```

## orbit instance:teardown-step:update

Change the command, timeout, or position of one teardown step.

```bash theme={"dark"}
orbit instance:teardown-step:update <name> --project=<id> [--command=<command>] [--timeout=<seconds>] [--before=<name>|--after=<name>] [--rebalance=<name>=<seconds>]... [--json]
```

## orbit instance:teardown-step:destroy

Remove one teardown step. Interactive confirmation defaults to No. JSON and noninteractive calls require `--yes`.

```bash theme={"dark"}
orbit instance:teardown-step:destroy <name> --project=<id> [--yes] [--json]
```

## orbit instance:clone

Clone a candidate into a prepared production Instance. The candidate supplies source, stored environment values, and an optional SQLite snapshot. The Project supplies production Process and Schedule definitions.

```bash theme={"dark"}
orbit instance:clone <candidate> <node> <name> --preview-name=NAME [options]
```

| Argument | Required | Meaning |
| - | - | - |
| `candidate` | yes | Numeric candidate Instance ID. |
| `node` | yes | Numeric destination Node ID with the active `app-prod` role. |
| `name` | yes | Target production Instance name. |

| Option | Default | Meaning |
| - | - | - |
| `--preview-name=NAME` | required | Preview name that the Gateway combines with the destination Node TLD. |
| `--branch=BRANCH` | the candidate branch | Target branch that must exist in the Project repository. |
| `--sqlite-source-path=PATH` | none | Absolute path to one SQLite database on the candidate to seed `database.sqlite`. |

Give the production Node a TLD with `node:add --tld` first: `shop.com` on a Node with TLD `prod.orbit` becomes the preview `shop.com.prod.orbit`. The candidate must be clean, and its commit must be in the Project repository.

```bash theme={"dark"}
orbit node:add production production.example --role=app-prod --tld=prod.orbit
orbit instance:clone 12 9 primary --preview-name=shop.com --sqlite-source-path=/srv/orbit/apps/acme/default/database/database.sqlite
```

Cloning ends with an active Instance and no release. Update its environment, record deploy steps, then run `instance:deploy`. See [Instance cloning](/docs/reference/instance-cloning#next-steps).

## orbit instance:update

Change the deployment branch of a production Instance. The Gateway stores the branch and does not change deploy steps or start a deployment.

The human result shows the accepted deployment branch and the currently selected source branch. JSON returns the existing Instance response; its `selected_branch` describes the source, not the newly stored deployment setting.

```bash theme={"dark"}
orbit instance:update <instance> --branch=BRANCH [--json]
```

| Argument | Required | Meaning |
| - | - | - |
| `instance` | yes | Numeric Instance ID. |

| Option | Meaning |
| - | - |
| `--branch=BRANCH` | Deployment branch. A later Project default change does not replace it. |

The Gateway refuses a development Instance with a bounded conflict before it stores a branch.

## orbit instance:deploy-step:create

Record one named deploy step on a production Instance. The Gateway stores it at the end of its phase unless you place it.

```bash theme={"dark"}
orbit instance:deploy-step:create <instance> <name> --command=COMMAND [options]
```

| Argument | Required | Meaning |
| - | - | - |
| `instance` | yes | Numeric Instance ID. |
| `name` | yes | Step name: 1 through 63 lowercase letters, digits, or hyphens, unique within the Instance. |

| Option | Default | Meaning |
| - | - | - |
| `--command=COMMAND` | required | Command the Gateway runs as the production user from the fresh release. |
| `--phase=PHASE` | `before_activation` | `before_activation` or `after_activation`. |
| `--timeout=SECONDS` | `300` | Timeout from 1 through 900 seconds. |
| `--before=NAME` | none | Place before this step in the same phase. Exclusive with `--after`. |
| `--after=NAME` | none | Place after this step in the same phase. Exclusive with `--before`. |

```bash theme={"dark"}
orbit instance:deploy-step:create 15 install --command="composer install --no-dev --optimize-autoloader"
orbit instance:deploy-step:create 15 migrate --command="php artisan migrate --force" --after=install
orbit instance:deploy-step:create 15 restart-queue --command="php artisan queue:restart" --phase=after_activation
```

The Gateway refuses a duplicate name, a placement that names an unknown step or a step in another phase, a thirty-third step, a timeout over 900 seconds, or a step-timeout sum over 3,600 seconds.

## orbit instance:deploy-step:list

List deploy steps in phase and placement order. `--json` returns the steps and the `request_id` as one object.

```bash theme={"dark"}
orbit instance:deploy-step:list <instance> [--json]
```

## orbit instance:deploy-step:update

Change one named deploy step. Options you omit stay unchanged.

```bash theme={"dark"}
orbit instance:deploy-step:update <instance> <name> [options]
```

| Argument | Required | Meaning |
| - | - | - |
| `instance` | yes | Numeric Instance ID. |
| `name` | yes | Existing step name. |

| Option | Meaning |
| - | - |
| `--command=COMMAND` | New command. |
| `--phase=PHASE` | `before_activation` or `after_activation`. |
| `--timeout=SECONDS` | Timeout from 1 through 900 seconds. |
| `--before=NAME` | Place before this step in the same phase. Exclusive with `--after`. |
| `--after=NAME` | Place after this step in the same phase. Exclusive with `--before`. |

```bash theme={"dark"}
orbit instance:deploy-step:update 15 migrate --timeout=600
```

## orbit instance:deploy-step:destroy

Remove one named deploy step. Remaining steps keep their relative order. Confirm the named target at a default-No prompt, or pass `--yes`. JSON and noninteractive calls require `--yes`.

```bash theme={"dark"}
orbit instance:deploy-step:destroy <instance> <name> [--yes] [--json]
```

## orbit instance:deploy

Deploy a production Instance or an app-dev `default` Instance. For production, the Gateway creates a fresh release, fetches the configured branch, synchronizes stored environment values, runs the `before_activation` steps, atomically replaces `current`, refreshes the PHP runtime cache, and runs the `after_activation` steps. For a development default, it fetches the Project's default branch, checks out its newest commit in the default's checkout, and runs the Project's development deploy steps there. It refuses a checkout with uncommitted changes to tracked files. A failed required step leaves the new commit checked out, and the next scheduled tick retries. A best-effort failure reports a warning and the deployment continues. See [Instance releases](/docs/reference/deployments#development-defaults).

```bash theme={"dark"}
orbit instance:deploy <instance> [--json]
```

| Argument | Required | Meaning |
| - | - | - |
| `instance` | yes | Numeric Instance ID. |

Human output shows a progress tree. The deploy phases the Gateway always sends appear up front; named deploy steps and the PHP cache refresh phase reveal only when their phase starts. Glyphs and color show waiting, running, success, failure, and not-reached states, and active indicators alternate while work is in progress. Standard output and standard error from application commands appear labeled and escaped, and print above the tree without redrawing it, while their step runs.

On failure the tree marks the last reached step as failed, with the error code shown under it, even when the Gateway's failed boundary has no step of its own (an activation or cache-refresh failure during a rollback, for example). Every later step shows orange with a dim "Not reached." label under it, and the footer turns red. The final lines add the failed boundary, the error code, the selected release when available, and the request ID. `--json` writes the same events as NDJSON, one event per line, without prompts or prose.

Pressing Ctrl-C closes the connection at once, including during a step with no output yet: the CLI does not wait for the Gateway to finish that step first. The tree marks the current step failed and shows a red "Operation interrupted." footer; JSON mode ends the stream with no result line. Either way the CLI submits no second request.

| Event type | Fields |
| - | - |
| `phase` | `phase` is `source_preparation`, `environment_sync`, `before_activation`, `activation`, `php_refresh`, `after_activation`, or `rollback`. `step_name` is present only for a named step. |
| `output` | `stream` is `stdout` or `stderr`. `data_base64` carries at most 16 KiB of decoded bytes. |
| `result` | `status` is `succeeded` or `failed`, with nullable `failed_step`, `error_code`, and `selected_release`. This is the final line. |

Every event carries `type`, a monotonically increasing `sequence`, and the `request_id`. A failed `result` stays a `result` event; the CLI uses the one-line error envelope only when the Gateway refuses the command before the stream opens or when the stream is malformed or truncated.

| Stream outcome | Exit status |
| - | - |
| The final event is a succeeded result. | `0` |
| The final event is a failed result. | Nonzero. The command names the failed boundary and the selected release when the result includes one. |
| The stream is malformed, truncated, or ends without a result. | Nonzero. The CLI never infers success from earlier events. |
| You press Ctrl-C. | Nonzero. The CLI closes its connection and submits no second request. |

```bash theme={"dark"}
orbit instance:deploy 15
orbit instance:deploy 15 --json > deploy.ndjson
```

A failure during release fetch, environment synchronization, or a `before_activation` step leaves the prior `current` selected. A failure during the PHP cache refresh or an `after_activation` step leaves the fresh release selected. Deployment, rollback, deploy-step changes, environment changes, and removal share one operation owner per Instance, so a competing request waits or returns a busy refusal.

<Note>
  Only `default` can be deployed on an app-dev Node. Other development Instances still return `deployment_config.unavailable`. Releases, rollback, and per-Instance deploy-step operations remain production-only; `instance:release:list` shows none for a development default.
</Note>

## orbit instance:release:list

List retained release names and the current selection. A production home keeps at most 3 releases, as [Retained releases](/docs/reference/deployments#retained-releases) describes. See [`instance:deployment:list`](#orbit-instancedeploymentlist) for the recorded run history behind those releases.

```bash theme={"dark"}
orbit instance:release:list <instance> [--json]
```

## orbit instance:rollback

Select one retained release through `current`. A successful deployment keeps the previous selection and one other release, so these are the rollback targets. Rollback does not fetch Git, synchronize environment values, run deploy steps, or change database files.

```bash theme={"dark"}
orbit instance:rollback <instance> --release=NAME [--json]
```

| Argument | Required | Meaning |
| - | - | - |
| `instance` | yes | Numeric Instance ID. |

| Option | Meaning |
| - | - |
| `--release=NAME` | Retained release name from `instance:release:list`. |

The command streams the same `phase`, `output`, and `result` events as `instance:deploy`, with the `rollback` phase, and uses the same exit status table.

```bash theme={"dark"}
orbit instance:release:list 15
orbit instance:rollback 15 --release=20260914T101500Z
```

<Warning>
  Orbit selects the older code only. You own any data or application recovery that the switch needs.
</Warning>

## orbit instance:deployment:list

List the deployment history the Gateway recorded for a production Instance, newest first. The Gateway writes one row when `instance:deploy` or `instance:rollback` starts and fills it in when the run finishes, and keeps the last 50 rows per Instance.

```bash theme={"dark"}
orbit instance:deployment:list <instance> [--json]
```

| Argument | Required | Meaning |
| - | - | - |
| `instance` | yes | Numeric Instance ID. |

The table shows Started, Release, Branch, Commit, By, Duration, and Status. `By` is the calling Node's name, since the Gateway authorizes every command as a Node. A row still running when read shows `running` and an empty Finished, Duration, and Release until the run completes.

```bash theme={"dark"}
orbit instance:deployment:list 15
```

## orbit instance:deployment:show

Show one recorded deployment: a detail tree of its identity and outcome, then the phases and steps it went through as a table, then its log.

```bash theme={"dark"}
orbit instance:deployment:show <deployment> [--json]
```

| Argument | Required | Meaning |
| - | - | - |
| `deployment` | yes | Numeric deployment ID from `instance:deployment:list`. |

The detail tree shows the Instance ID, release, branch, commit, started and finished times, duration, status, failed step, error code, selected release, and who triggered it. The phases table repeats the `phase` and `step_name` values the run streamed. The log reproduces the run's standard output and standard error lines in order.

```bash theme={"dark"}
orbit instance:deployment:show 42
```

## orbit instance:database:add

Add a registered Database connection on an Instance and write prefixed keys into its stored environment configuration.

```bash theme={"dark"}
orbit instance:database:add <slug> --instance=SELECTOR [--prefix=PREFIX] [--json]
```

| Argument | Required | Meaning |
| - | - | - |
| `slug` | yes | Database connection slug from `database:list`. |

| Option | Default | Meaning |
| - | - | - |
| `--instance=SELECTOR` | required | Positive Instance ID or exact Route domain. |
| `--prefix=PREFIX` | `DB` | Uppercase key prefix that starts with a letter, at most 32 characters. |

For mysql and pgsql the Gateway writes `DB_CONNECTION`, `DB_HOST`, `DB_PORT`, `DB_DATABASE`, `DB_USERNAME`, and `DB_PASSWORD`. For sqlite it writes `DB_CONNECTION=sqlite` and `DB_DATABASE` as the absolute path, plus username and password only when stored. The Gateway writes the connection's stored host and port, also when the Instance runs on the connection's Node.

```bash theme={"dark"}
orbit instance:database:add app --instance=12
orbit instance:database:add reporting --instance=shop.example.test --prefix=REPORTING
```

Add changes stored configuration only. Run `orbit env:sync --instance=SELECTOR` to install it in the workload `.env`.

## orbit instance:database:remove

Remove a Database connection from an Instance and clear the prefixed stored keys. Other stored keys stay in place.

```bash theme={"dark"}
orbit instance:database:remove <slug> --instance=SELECTOR [--prefix=PREFIX] [--force] [--json]
```

| Option | Default | Meaning |
| - | - | - |
| `--instance=SELECTOR` | required | Positive Instance ID or exact Route domain. |
| `--prefix=PREFIX` | `DB` | Prefix of the attachment to remove. |
| `--force` | off | Confirm removal without prompting. Interactive confirmation defaults to No. A JSON or non-interactive call without `--force` returns `database.confirmation_required`. Interactive decline, Ctrl-C, and EOF cancel with `input.cancelled`. |

```bash theme={"dark"}
orbit instance:database:remove app --instance=12 --force
```

An unknown attachment returns `database.attachment_missing`.

## orbit instance:analytics:enable

Publish the tracking hosts that send an Instance's visits to the analytics role.

```bash theme={"dark"}
orbit instance:analytics:enable <instance> [--host=HOST]... [--json]
```

| Argument | Required | Meaning |
| - | - | - |
| `instance` | yes | Numeric Instance ID. |

| Option | Default | Meaning |
| - | - | - |
| `--host=HOST` | `analytics.<instance domain>` | A tracking host. Repeat it for more, up to ten. |

```bash theme={"dark"}
orbit instance:analytics:enable 12
orbit instance:analytics:enable 12 --host=stats.example.com --host=analytics.shop.example.com
```

The command sets the exact host set: the Gateway publishes each named host that is missing and removes each tracking host of the Instance that you did not name. Naming the hosts that already exist changes nothing. Each host is a Route that answers only `/js/*` and `/api/event`, served wherever the Instance's own domain is served; the [Analytics role](/docs/reference/analytics#publish-a-tracking-host) page owns that contract.

Human output lists each host with its Route and status, the DNS record to create for it, and the script tag to add to the Project. JSON returns `instance_id`, `enabled`, `domain`, `dashboard_url`, `hosts`, and `snippet`. You still create the site in Plausible yourself.

| Error code | Meaning |
| - | - |
| `analytics.role_missing` | No Node has an active analytics role. |
| `analytics.domain_required` | The Instance does not serve a domain yet. |
| `analytics.host_taken` | Another Route already uses a named host. |
| `validation.failed` | A host is not a lowercase DNS name, is reserved, is repeated, or more than ten hosts were named. |

## orbit instance:analytics:show

Show the tracking hosts of an Instance.

```bash theme={"dark"}
orbit instance:analytics:show <instance> [--json]
```

The output has the same shape as [`instance:analytics:enable`](#orbit-instanceanalyticsenable). An Instance without tracking hosts reports tracking as disabled, with no hosts and no script tag.

## orbit instance:analytics:disable

Remove every tracking host of an Instance.

```bash theme={"dark"}
orbit instance:analytics:disable <instance> [--yes] [--json]
```

| Option | Default | Meaning |
| - | - | - |
| `--yes` | off | Confirm without prompting. Interactive confirmation defaults to No. A JSON or non-interactive call without `--yes` returns `input.confirmation_required`. |

Plausible stops receiving visits for the Instance as soon as the hosts are gone. The data already in Plausible stays. Running the command again for an Instance without hosts succeeds and changes nothing.

## orbit instance:transfer

Move an active development Instance to another `app-dev` Node. Both Nodes must belong to active Clusters. The transfer stops the source, copies it into an independent checkout, moves or replaces its Route, and deletes the old placement. See [Instance transfer](/docs/reference/instance-transfer).

```bash theme={"dark"}
orbit instance:transfer <instance> <node> [--name=NAME] [--sqlite-source-path=PATH] [--force] [--json]
```

Use these options to select the destination and confirm downtime.

| Option | Meaning |
| - | - |
| `--name=NAME` | Optional destination name. |
| `--sqlite-source-path=PATH` | Optional SQLite database to copy from the source. |
| `--force` | Confirm downtime and deletion of the old placement. |
| `--json` | Return machine-readable output without prompts. Requires `--force` for consent. |

Without `--force`, an interactive call asks for default-No consent naming the source, destination and effect. JSON and noninteractive calls without `--force` return `instance.confirmation_required` before mutation.

## orbit instance:dependencies:scan

Read the root manifests and lockfiles of an Instance and record its package inventory. The Gateway changes no file.

```bash theme={"dark"}
orbit instance:dependencies:scan [--project=DOMAIN | --all] [--json]
orbit instance:dependencies:scan --project=commander.test
```

| Option | Meaning |
| - | - |
| none | Scan the registered Instance whose checkout or production home holds the current directory. |
| `--project=DOMAIN` | Scan the one Instance behind this full Route domain. It takes precedence over the directory. |
| `--all` | Scan every Instance that `instance:list` returns, one by one. Combining it with `--project` returns `dependencies.target_conflict`. |

The exit status is zero only when every scanned ecosystem succeeds. See [Scan](/docs/reference/instance-dependencies#scan) for the output and errors.

## orbit instance:dependencies:update

Update the Composer and JavaScript packages of one development Instance within their declared constraints, then scan it again. A production Instance returns `dependencies.production_update_forbidden`.

```bash theme={"dark"}
orbit instance:dependencies:update [--project=DOMAIN] [--json]
```

| Option | Meaning |
| - | - |
| `--project=DOMAIN` | Update the Instance behind this full Route domain instead of the one in the current directory. |
| `--all` | Refused before any request. Updates run on one Instance at a time. |
| `--latest` | Refused before any request. Updates stay within the declared constraints. |

See [Update a development Instance](/docs/reference/instance-dependencies#update-a-development-instance) for the steps it runs.

## Related

* [`project`](/docs/cli/project) owns the repository and source defaults that an Instance inherits.
* [`route`](/docs/cli/route) shows and changes the domain of an Instance.
* [`env`](/docs/cli/env) imports, updates, and synchronizes the stored environment that deployments render.
* [`process`](/docs/cli/process) and [`schedule`](/docs/cli/schedule) run services and timers on an Instance.
* [`database`](/docs/cli/database) registers the connections that `instance:database:add` attaches.
* [`analytics`](/docs/cli/analytics) pins the Plausible version that the tracking hosts send visits to.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.