# Forge cloud compute

Forge cloud compute gives Forge a server to run agents and tests on while the Forge window stays on the person's Mac. The API under `https://api.aitronos.com/v1/forge/compute` lists where a server can run and at what price, connects an organization's own cloud accounts, and creates, parks, resumes, deletes and revokes servers. Everything that has to happen on the Mac — the SSH client key, installing Forge's runtime on the server, pairing and the tunnel — is done by the client; this API records each step.

Every endpoint is plain JSON request and response. Progress is **polled**, never streamed.

## Access

- Every endpoint requires the `use_forge` capability in the acting organization, except the three spend-limit endpoints for people who manage billing (below).
- Connecting or disconnecting a cloud account, changing the organization's compute settings, deleting a leftover resource, listing every member's servers (`?scope=org`) and acting on a server someone else created require `manage_forge` (which includes `use_forge`).
- Changing the organization's spend limits for Aitronos servers, listing every member's limits and setting one member's limit require `manage_billing` (the capability every spending limit is changed with) instead of `use_forge`. Reading the limits and setting your own needs only `use_forge`; your own limit needs a signed-in person.
- A server is visible to the person who created it and to members with `manage_forge`. Anyone else is told it does not exist (`404 FORGE_COMPUTE_HOST_NOT_FOUND`).
- Forge cloud compute is switched on per organization. While it is off, the catalog lists no offerings, and options, connecting an account, creating, resuming and the setup reports (progress, host key, ready, activity) are refused with `403 FORGE_COMPUTE_DISABLED`. Reads, park, delete, revoke, disconnecting an account and deleting a leftover resource keep working, so switching the feature off never strands a server that costs money.


## Which organization pays

Forge is not tied to one organization; a person may rent servers in any organization they belong to.

- **Choosing.** [List billing organizations](/docs/api-reference/forge-compute/list-billing-organizations) lists every organization the person is an active member of, which ones servers can be billed to (`selectable`, with a `reason` to show when not) and which one to preselect (`default_organization_id`). [Choose the default billing organization](/docs/api-reference/forge-compute/choose-billing-organization) saves the preselection. Show the choice as **Bill to** on every rental.
- **Creating.** [Create a server](/docs/api-reference/forge-compute/create-host) names the organization in `organization_id`. The server is billed to that organization alone, for its whole life: every hour, every resume and its parked copy. The backend never infers it.
- **Finding a server again.** Every server carries `organization` (`{id, name}`). [List your servers in every organization](/docs/api-reference/forge-compute/list-my-hosts) lists the person's own servers across all of their organizations.
- **Acting on a server.** Every other endpoint acts in the caller's current organization unless the request names another one with the `organization_id` query parameter or the `X-Organization-Id` header. Send the server's `organization.id` with every request about it. Naming an organization you are not an active member of is refused with `403 ORGANIZATION_ACCESS_DENIED`; capabilities are checked in the named organization.


## Project groups

A project group is a folder of projects in the Forge sidebar, and it can carry the organization that pays for the Forge spend made inside its projects: rented servers and the [git impact assessment](/assets/assess-git-impact.a7bae1761a3dd82a227de8c76df41608e7e238562f3d2f420b7b3eccb4ee1234.23c4b6e8.md). Forge registers each group, keyed by its own id, with [Register or update a project group](/docs/api-reference/forge-compute/put-project-group), lists them with [List project groups](/docs/api-reference/forge-compute/list-project-groups) and removes one with [Delete a project group](/docs/api-reference/forge-compute/delete-project-group); the API is under `https://api.aitronos.com/v1/forge/project-groups`. A group bills to its own organization, else to its nearest registered ancestor's (`inherited`), else to none; register every group, also those without an organization, so the groups inside them can inherit through them. A server rented inside a group sends `project_group_id` and must be [created](/docs/api-reference/forge-compute/create-host) in the group's organization (`422 FORGE_PROJECT_GROUP_ORGANIZATION_MISMATCH` otherwise); it carries the group in `project_group` and stays billed to the organization it was rented in. Spend inside a group whose organization can no longer be billed is refused with `403 FORGE_PROJECT_GROUP_ORGANIZATION_UNAVAILABLE`, never billed somewhere else. The organization's [usage report](/assets/get-usage-detail-report.45870ea5b94806d0570403fa53ae031e4b48417dddf0f27bd3aa2fc29b7ba55c.49b960d1.md) shows its Forge spend per group in `by_forge_project_group`.

## Two kinds of server

| Offering | `kind` | Who runs and bills it |
|  --- | --- | --- |
| `aitronos` — **Aitronos servers** | `managed` | Aitronos runs the server and charges your organization per started hour, in CHF, as **Forge cloud compute** on its usage. |
| `hetzner`, `digitalocean`, `vultr`, `scaleway`, `exoscale`, `linode`, `upcloud` | `byo` | The server runs in your organization's own account at that provider. The provider bills your organization directly; Aitronos meters nothing. |


Labels, order, help text and the connect form of each offering come from [List compute offerings](/docs/api-reference/forge-compute/list-offerings); a client should render what it receives rather than hard-code it.

## Billing of Aitronos servers

- **Per started hour.** Every started hour a server exists is charged once, from the moment the server is confirmed to exist until it is confirmed gone. An hour a server is parked and resumed in is charged once.
- **At the quoted price.** The hourly price the person confirmed when creating (or resuming) the server is frozen on the server as `price` and is exactly what is charged. Each charge is recorded in CHF, already priced, in the organization's usage under **Forge cloud compute**; it is not converted from synapses or neurons.
- **CHF, excluding VAT.** Prices already include your organization's individual agreement, if any. The list rates are published in the `forge_compute` section of [Get pricing sheet](/assets/get-pricing.a1f4a5c69505ff07d8f94ed9588348eade862458c82c1d34e23b1c589add5713.4236153a.md).
- **Monthly cap per server.** One server is never charged more than its size's `monthly_cap` in a calendar month.
- **Parked servers** are billed for their stored copy per GB-month (`parked_storage.per_gb_month`), accrued hourly, instead of the hourly price.
- **Spending limits.** Creating or resuming is refused with `402 FORGE_COMPUTE_SPEND_LIMIT_REACHED` when the organization's spending limit cannot absorb one more hour. At 90% of the limit every running Aitronos server carries a `notice`; at 100% running servers are parked (the default) or keep running, as set in the organization's [compute settings](/docs/api-reference/forge-compute/get-settings).
- **Spend limits on Aitronos servers.** On top of the spending limit, an organization can set its own monthly limit for Aitronos servers and a default monthly limit per person, someone who manages billing can set a different limit for one person, and each person can hold themselves to a lower one. [Get spend limits](/docs/api-reference/forge-compute/get-limits) returns them with this month's spend and every label and sentence to show; change them with [Change the organization's limits](/docs/api-reference/forge-compute/update-organization-limits), [Set a member's limit](/docs/api-reference/forge-compute/update-member-limit) (see [List member limits](/docs/api-reference/forge-compute/list-member-limits)) and [Set your own limit](/docs/api-reference/forge-compute/update-my-limit). A person's spend is the spend of the servers they own. Creating or resuming past one is refused with `402 FORGE_COMPUTE_SPEND_LIMIT_REACHED` (`details.reason` `org_compute_limit_reached` or `member_limit_reached`, checked against the server owner's limit); at 90% of a person's limit their running servers carry the `notice` `member_limit_90`, and at 100% they are parked (`member_limit_parked`) or keep running (`member_limit_100`). Limits work while Forge cloud compute is switched off.
- **Capacity.** Aitronos servers share a platform-wide capacity. When it is reached, creating or resuming an Aitronos server is refused with `503 FORGE_COMPUTE_PLATFORM_CAPACITY_REACHED` ("Aitronos servers are at capacity right now. Try again later."), the catalog shows Aitronos servers as `blocked` with that sentence, and running Aitronos servers may be parked; their work is kept and they can be resumed once capacity is back. Servers on your own cloud accounts are never affected.


Servers in your own account (`byo`) are never charged by Aitronos. Their prices are the provider's own, in the provider's currency, read with your connected account.

## Server lifecycle

| State | Driven by | Meaning |
|  --- | --- | --- |
| `creating` | backend | The record exists; the server is being created. |
| `booting` | backend | The server exists and is starting. |
| `awaiting_client` | client | The server is running and waits for the client to connect. |
| `securing` | client | The client is replacing the bootstrap host key. |
| `installing` | client | The client is installing Forge on the server. |
| `pairing` | client | The client is pairing with the server. |
| `ready` | — | Usable. |
| `parking` | backend | The server is being saved, then stopped. |
| `parked` | — | Saved and not running. |
| `resuming` | backend | The server is being started again from its saved copy. |
| `deleting` | backend | Everything created for the server is being removed. |
| `deleted` | — | Nothing is left. Listed for seven days. |
| `revoking` | backend | Emergency stop: the server and its key are being removed now. |
| `revoked` | — | Server and key are gone; the record keeps the reason. |
| `failed_billing` | — | Something went wrong and a server may still exist. Delete it to stop charges. |
| `failed_clean` | — | The server could not be created and nothing is running. `failure` says why. |


Every server response carries `state_label` (a sentence to show), `transient` (`true` while the server is between states) and `actions` (what the caller may request now, already filtered by what the offering supports). Backend-driven states end on their own: poll until the state changes. Client-driven states (`awaiting_client` to `pairing`) end when the client reports its next step, so a client must act on them rather than wait.

### Creating and setting up a server

1. **Choose.** Pick the organization to bill from [List billing organizations](/docs/api-reference/forge-compute/list-billing-organizations), then [list compute offerings](/docs/api-reference/forge-compute/list-offerings) in it, then [get the offering's options](/docs/api-reference/forge-compute/get-offering-options) and show the person the price of the location and size they pick.
2. **Create.** [Create a server](/docs/api-reference/forge-compute/create-host) with a client-chosen `id`, the chosen `organization_id`, the person's SSH public key and the `quote` they confirmed. The answer is `202` with the server in `creating`, carrying `ssh_user` (always `forge`) and `ssh_port`. `bootstrap_host_key_pub` is still `null` in that answer: the bootstrap host key (K0) to trust on the first connection appears on the server record once the backend has generated it, at the latest by `awaiting_client`. Only public keys are ever stored or returned; the bootstrap key is not a secret handed out once, it is shown on every read until the host key is reported.
3. **Poll.** [Get the server](/docs/api-reference/forge-compute/get-host) about every two seconds until it reaches `awaiting_client`. It moves `creating` → `booting` → `awaiting_client` and gains `ipv4`/`ipv6`. A server that could not be created ends in `failed_clean` with `failure.code` (for example `FORGE_COMPUTE_CAPACITY_UNAVAILABLE` with `failure.details.alternatives`).
4. **Connect on K0.** At `awaiting_client`, connect as `ssh_user` with the person's key, pinning `bootstrap_host_key_pub`.
5. **Secure.** [Report](/docs/api-reference/forge-compute/report-progress) `securing`. On the server, wait for `/var/lib/forge/bootstrap.done`, read the staged key K1 from `/etc/ssh/forge_next_ed25519_key.pub` and pin it, then `touch /var/lib/forge/host-key/commit` so the server swaps K1 in. Reconnect pinned to K1 and [report the host key](/docs/api-reference/forge-compute/report-host-key). From then on `host_key_pub` is the key to trust and `bootstrap_host_key_pub` is `null`.
6. **Install and pair.** Report `installing`, then `pairing`, as the client reaches them.
7. **Ready.** [Mark the server ready](/docs/api-reference/forge-compute/report-ready). This is refused with `409 FORGE_COMPUTE_INVALID_STATE` until the host key was reported.
8. **In use.** [Report activity](/docs/api-reference/forge-compute/report-activity) at most once every five minutes while the server is used. It drives the idle reminder and, if the organization turned it on, automatic parking.


Setup steps only move forward: repeating the current step changes nothing, and an earlier step is refused.

### Park, resume, delete, revoke

- **[Park](/docs/api-reference/forge-compute/park-host)** saves the server (a snapshot where the offering's `capabilities.park` is `snapshot`, or the stopped server itself where it is `poweroff`), then stops it: `ready` → `parking` → `parked`. Hourly charges stop; the stored copy is billed per GB-month. Offerings whose `capabilities.park` is `false` cannot park, and their servers never list `park` in `actions`. Aitronos servers are parked automatically after 1 hour without activity (adjustable to 1 to 168 hours in the [compute settings](/docs/api-reference/forge-compute/get-settings), never off), and an Aitronos server left parked for 30 days is deleted (its owner is notified 3 days before; see `parked_expires_at`).
- **[Resume](/docs/api-reference/forge-compute/resume-host)** starts a parked server again from its saved copy at a newly confirmed quote: `parked` → `resuming` → `awaiting_client`. The server keeps its host key K1, so the client skips `securing`, reports `installing` and `pairing`, and marks it ready. The saved copy is removed once it is ready.
- **[Delete](/docs/api-reference/forge-compute/delete-host)** removes the server and everything created for it: `deleting` → `deleted`. The record stays and is listed for seven days.
- **[Revoke](/docs/api-reference/forge-compute/revoke-host)** is the emergency stop for a server or key that may be compromised: the server and its SSH key are removed at once (`revoking` → `revoked`) and the record keeps the reason. Delete it afterwards to remove what is left. A parked server has no running server to revoke; delete it instead.


Every action answers `202` with the server in its new state, and asking again for a state that is already current returns the server again rather than an error. Park, delete and revoke work while Forge cloud compute is switched off; resume does not, because it starts charges again.

### A server's history

Three reads describe what a server has done, for a detail page: [Get a server's daily cost and uptime](/docs/api-reference/forge-compute/get-host-usage) (what it was billed per day, from the same ledger as the usage page, and how long it ran), [List a server's running intervals](/docs/api-reference/forge-compute/list-host-intervals) (each period it ran and why it stopped) and [List a server's event history](/docs/api-reference/forge-compute/list-host-events) (every move through the lifecycle, with a sentence to show). The first two take a period of at most 93 days and default to the current month.

## Errors

Every refusal uses the standard error envelope. `error.message` is a sentence written to be shown to the person as is; branch on `error.code`. A server that fails after the request was accepted carries the same code in `failure.code`.


```json
{
  "success": false,
  "error": {
    "code": "FORGE_COMPUTE_INVALID_STATE",
    "message": "This server cannot do that in its current state. Wait for it to finish and try again.",
    "system_message": "Action 'park' is not allowed while the host is 'creating'",
    "type": "client_error",
    "status": 409,
    "details": {"state": "creating", "action": "park"},
    "trace_id": "3f1c9a52-7d4e-4b8a-9c21-6e0d5f7a8b34",
    "timestamp": "2026-09-28T09:00:00Z"
  }
}
```

## Related Resources

- [List billing organizations](/docs/api-reference/forge-compute/list-billing-organizations)
- [Choose the default billing organization](/docs/api-reference/forge-compute/choose-billing-organization)
- [List project groups](/docs/api-reference/forge-compute/list-project-groups)
- [Register or update a project group](/docs/api-reference/forge-compute/put-project-group)
- [Delete a project group](/docs/api-reference/forge-compute/delete-project-group)
- [List compute offerings](/docs/api-reference/forge-compute/list-offerings)
- [Get offering options](/docs/api-reference/forge-compute/get-offering-options)
- [Resolve a free size](/docs/api-reference/forge-compute/resolve-offering-size)
- [List connected accounts](/docs/api-reference/forge-compute/list-credentials)
- [Connect a cloud account](/docs/api-reference/forge-compute/put-credential)
- [Disconnect a cloud account](/docs/api-reference/forge-compute/delete-credential)
- [Create a server](/docs/api-reference/forge-compute/create-host)
- [List servers](/docs/api-reference/forge-compute/list-hosts)
- [List your servers in every organization](/docs/api-reference/forge-compute/list-my-hosts)
- [Get a server](/docs/api-reference/forge-compute/get-host)
- [Get a server's daily cost and uptime](/docs/api-reference/forge-compute/get-host-usage)
- [List a server's running intervals](/docs/api-reference/forge-compute/list-host-intervals)
- [List a server's event history](/docs/api-reference/forge-compute/list-host-events)
- [Report a setup step](/docs/api-reference/forge-compute/report-progress)
- [Report the server's host key](/docs/api-reference/forge-compute/report-host-key)
- [Mark a server ready](/docs/api-reference/forge-compute/report-ready)
- [Report activity](/docs/api-reference/forge-compute/report-activity)
- [Park a server](/docs/api-reference/forge-compute/park-host)
- [Resume a server](/docs/api-reference/forge-compute/resume-host)
- [Delete a server](/docs/api-reference/forge-compute/delete-host)
- [Revoke a server](/docs/api-reference/forge-compute/revoke-host)
- [Get compute settings](/docs/api-reference/forge-compute/get-settings)
- [Update compute settings](/docs/api-reference/forge-compute/update-settings)
- [Get spend limits](/docs/api-reference/forge-compute/get-limits)
- [Change the organization's limits](/docs/api-reference/forge-compute/update-organization-limits)
- [Set your own limit](/docs/api-reference/forge-compute/update-my-limit)
- [List member limits](/docs/api-reference/forge-compute/list-member-limits)
- [Set a member's limit](/docs/api-reference/forge-compute/update-member-limit)
- [Delete a leftover resource](/docs/api-reference/forge-compute/delete-orphan)
- [Get pricing sheet](/assets/get-pricing.a1f4a5c69505ff07d8f94ed9588348eade862458c82c1d34e23b1c589add5713.4236153a.md)