# Status

**Spinbox is experimental: APIs change and data may be lost.** What is built and what proves it is on [Status](https://spin-stack.github.io/website/reference/status.md); what Spinbox does not do is on [Limitations](https://spin-stack.github.io/website/overview/limitations.md).

> What Spinbox does today with what proves each, what is partly there, what is not built, and its limits, each row held to the code.

<!-- Generated by tools/refgen from spin:internal/features/features.go. Edit the source, not this file. -->

Every row of this page is a line of `internal/features` in spin, and a test there resolves its proof against the tree: a procedure the control plane serves, a command the CLI has, or a test the end-to-end lane runs on real machines. A row that says **built** names one; a row that says **not built** is an item of [`docs/ROADMAP.md`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/docs/ROADMAP.md). The page is written by `task reference` from `spin features` at spin `8eee32b9d`, and cannot say a feature the binary does not.

## Built

### Workspaces

| Feature | Proof |
|---|---|
| A machine per workspace: KVM, its own kernel, root, a persistent disk, SSH | [`TestAWorkspaceBootsARealGuest`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/vm_test.go#L169), an end-to-end test |
| Create, start, stop and delete | [`WorkspaceService/CreateWorkspace`](https://spin-stack.github.io/website/reference/api/workspaceservice.md) |
| A trash: a deleted workspace stays whole, for its owner to undelete, until its days are up | [`TestAWorkspaceWhoseDaysInTheTrashAreUpIsErasedFromItsHost`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/background_test.go#L363), an end-to-end test |
| Idle suspend, with a question before it that a keep answers | [`TestAWorkspaceIsAskedBeforeItsSuspensionAndAKeepAnswersIt`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/background_test.go#L107), an end-to-end test |
| A workspace that ran as long as the installation allows is suspended | [`TestAWorkspaceThatRanForAsLongAsAllowedIsSuspended`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/background_test.go#L69), an end-to-end test |
| A process inside holds its workspace awake while it lives | [`TestAProcessHoldsItsWorkspaceAwakeWhileItLives`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/background_test.go#L190), an end-to-end test |
| Suspend with the processes where they are; a start resumes them | [`TestAWorkspaceNobodyUsesIsSuspendedAndAStartResumesIt`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/background_test.go#L35), an end-to-end test |
| Cores and memory lent while the host has them, and taken back | [`TestABusyWorkspaceIsLentCoresAndGivesThemBack`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/background_test.go#L326), an end-to-end test |
| A grant of cores and memory of its own, for a while | [`TestAGrantWhoseTimeIsUpIsGivenBackToTheMachine`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/background_test.go#L287), an end-to-end test |
| Move a running workspace to another host, its processes as they are | [`TestHostsAMoveTakesARunningWorkspaceToAnotherHost`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/hosts_flows_test.go#L65), an end-to-end test |
| Clone a workspace: its disk, team, project, size, policies and environment, in one | [`TestACloneHoldsWhatItsSourceWroteAndItsShape`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/clone_test.go#L62), an end-to-end test |
| Recover a workspace whose host is gone, at a cost its owner accepts | [`TestHostsAWorkspaceWhoseHostIsGoneIsRecoveredOnAnother`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/hosts_flows_test.go#L99), an end-to-end test |
| A workspace outlives its runner | [`TestAWorkspaceOutlivesItsRunner`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/vm_test.go#L214), an end-to-end test |
| Quarantine, by an administrator | [`WorkspaceService/QuarantineWorkspace`](https://spin-stack.github.io/website/reference/api/workspaceservice.md) |
| Why a workspace is not behaving: status, console, history | [`spin workspace status`](https://spin-stack.github.io/website/reference/cli/workspace.md) |
| The owner's shell, environment, editor settings, Taskfile and dotfiles reach the guest | [`TestAWorkspacesOwnEnvironmentIsInItsOwnersLoginShell`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/env_test.go#L20), an end-to-end test |
| Reset a disk to what it was created from | [`spin workspace reset`](https://spin-stack.github.io/website/reference/cli/workspace.md) |
| Claude Code and Codex on every workspace's PATH, at the versions the release pins, with their own defaults | [`TestTheAgentCLIsAreOnPathWithThePinnedVersions`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/agentclis_test.go#L20), an end-to-end test |

### Teams and projects

| Feature | Proof |
|---|---|
| Open a repository, branch, commit or pull request from its URL, in the dashboard (/launch) and from the terminal | [`spin open --no-connect`](https://spin-stack.github.io/website/reference/cli/open.md) |
| A workspace opened at a commit or a pull request, checked out as pr-&lt;n> | [`TestAProjectsWorkspaceOpensAtTheCommitItWasAskedFor`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/project_test.go#L70), an end-to-end test |
| Teams, with owner, admin and member | [`spin team member role`](https://spin-stack.github.io/website/reference/cli/team.md) |
| A team's own identity providers | [`TeamService/CreateIdentityProvider`](https://spin-stack.github.io/website/reference/api/teamservice.md) |
| A team's forge app: private repositories cloned and pushed with nothing on the disk | [`spin team forge set`](https://spin-stack.github.io/website/reference/cli/team.md) |
| A team's own network policies, where the installation allows them | [`spin team policy set`](https://spin-stack.github.io/website/reference/cli/team.md) |
| Projects: a repository and the shape of the workspace that opens it | [`TestAProjectsWorkspaceHasItsRepositoryCheckedOutAtTheRef`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/project_test.go#L25), an end-to-end test |
| Prebuilds of a project's refs, as the floor of the workspaces that open them | [`TestAProjectOpensAsItsPrebuildMadeIt`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/prebuild_test.go#L29), an end-to-end test |
| A team's workspaces run on the installation's hosts | [`TestATeamsWorkspaceRunsOnTheInstallationsHost`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/team_test.go#L20), an end-to-end test |

### Snapshots

| Feature | Proof |
|---|---|
| Snapshots of a running workspace's disk | [`WorkspaceService/CreateSnapshot`](https://spin-stack.github.io/website/reference/api/workspaceservice.md) |
| Snapshots with memory, resumed with their processes | [`TestARunningWorkspaceResumesFromASnapshotsMemory`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/restore_test.go#L121), an end-to-end test |
| Restore a workspace to a snapshot | [`TestARestoredWorkspaceBootsOnTheSnapshotItWasRestoredTo`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/restore_test.go#L32), an end-to-end test |
| A diff of the files that changed between two snapshots | [`TestADiffOfTwoSnapshotsIsWhatChangedBetweenThem`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/diff_test.go#L28), an end-to-end test |
| Share a snapshot with a person or make it public, and create a workspace from it | [`TestACloneOfASnapshotRegistersAsItself`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/clone_test.go#L19), an end-to-end test |
| What looks like a credential is found before a share, and the share refused unless acknowledged | [`ShareService/ShareSnapshot`](https://spin-stack.github.io/website/reference/api/shareservice.md) |
| A long chain is compacted while the workspace runs | [`TestADiskSnapshottedPastTheThresholdIsCompactedWhileItRuns`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/compaction_test.go#L19), an end-to-end test |

### Network

| Feature | Proof |
|---|---|
| Egress is closed by default; policies, by tag, name what a workspace may reach | [`TestAnOwnerMayOnlyChooseAPolicyTheInstallationDeclares`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/retag_test.go#L68), an end-to-end test |
| A policy changed reaches the host that runs the workspace | [`TestChangingAWorkspacesPoliciesReachesTheHostThatRunsIt`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/retag_test.go#L22), an end-to-end test |
| Brokered names: the host's proxy stands in and adds what the workspace never holds - a team secret, a forge token, its identity, a cloud role | [`spin team secret set`](https://spin-stack.github.io/website/reference/cli/team.md) |
| A workspace trusts the egress root only by its owner's word | [`TestAGuestTrustsTheEgressRootOnlyByItsOwnersWord`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/egress_root_test.go#L20), an end-to-end test |
| What a workspace reached, what it looked up and what it was refused | [`spin workspace egress`](https://spin-stack.github.io/website/reference/cli/workspace.md) |
| Each request to a brokered name as the proxy read it, served or refused and why; and whether each injection's secret is the team's to give | [`TestABrokeredRequestIsSeenAsTheProxyReadIt`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/brokered_test.go#L28), an end-to-end test |
| The egress proxy is a process of its own, holding no key of the host's, started again by the runner when it ends | [`TestTheEgressProxyIsAProcessOfItsOwnThatTheRunnerStartsAgain`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/egress_process_test.go#L21), an end-to-end test |
| A brokered rule names whose it is, the agent's or the person's: one policy says what each may reach and with what | [`TestABrokeredNameForTheAgentIsTheAgentsAlone`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/brokered_test.go#L72), an end-to-end test |
| A WebSocket to a brokered name: its handshake under the rule's headers and scope, then bytes each way | [`TestAWebSocketToABrokeredNameIsCarriedAfterItsHandshake`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/brokered_test.go#L99), an end-to-end test |
| HTTP/2 to a brokered name, the proxy's ALPN the real host's: a rule's headers set stream by stream, gRPC's trailers both ways | [`TestHTTP2ToABrokeredNameIsTheRealHosts`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/brokered_test.go#L125), an end-to-end test |
| Watch where a workspace connects, into its logs | [`spin workspace watch`](https://spin-stack.github.io/website/reference/cli/workspace.md) |
| An agent the supervisor starts is marked, and reaches only brokered names | [`TestARealWorkspaceMarksTheAgentItsSupervisorStarts`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/seal_test.go#L21), an end-to-end test |
| Published ports at https://{port}-{workspace}.{domain}: private, whitelisted or public | [`spin port expose`](https://spin-stack.github.io/website/reference/cli/port.md) |

### Access

| Feature | Proof |
|---|---|
| Sign in with GitHub or an OIDC provider | [`AuthService/StartLogin`](https://spin-stack.github.io/website/reference/api/authservice.md) |
| Device login for a terminal | [`AuthService/StartDeviceLogin`](https://spin-stack.github.io/website/reference/api/authservice.md) |
| API keys for scripts and agents | [`spin api-key create`](https://spin-stack.github.io/website/reference/cli/api-key.md) |
| SSH keys, and plain ssh to spin.&lt;workspace> | [`spin ssh-config`](https://spin-stack.github.io/website/reference/cli/ssh-config.md) |
| Who logs in to a workspace is what its owner signed | [`TestOnlyThePeopleTheAccessNamesLogInToAWorkspace`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/login_test.go#L247), an end-to-end test |
| Guests of a workspace, invited by its owner | [`spin workspace guests`](https://spin-stack.github.io/website/reference/cli/workspace.md) |
| A workspace's identity, signed by its host, for the audiences its owner allows | [`TestAWorkspacesIdentityIsTheHostsSignatureOfWhatItsOwnerSigned`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/identity_test.go#L56), an end-to-end test |
| VS Code over SSH, with the server the installation publishes and nothing downloaded | [`TestAVSCodeServerOfAnotherCommitIsHandedToTheRunningMachine`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/vscodehotplug_test.go#L22), an end-to-end test |
| Run a command in a workspace, copy files to and from it | [`spin exec`](https://spin-stack.github.io/website/reference/cli/exec.md) |

### Administration

| Feature | Proof |
|---|---|
| Installation settings seeded from a file; a change in the file is a proposal to apply or dismiss | [`AdminService/DecideConfigChange`](https://spin-stack.github.io/website/reference/api/adminservice.md) |
| Resource presets | [`AdminService/CreateResourcePreset`](https://spin-stack.github.io/website/reference/api/adminservice.md) |
| Registration: open, by allowlist, or closed | [`AdminService/SetRegistrationMode`](https://spin-stack.github.io/website/reference/api/adminservice.md) |
| An audit log | [`AdminService/ListAuditLog`](https://spin-stack.github.io/website/reference/api/adminservice.md) |
| The control plane's jobs, and running one now | [`spin admin jobs`](https://spin-stack.github.io/website/reference/cli/admin.md) |
| The month's bill, its forecast, and what each workspace cost | [`spin admin costs`](https://spin-stack.github.io/website/reference/cli/admin.md) |
| The store: every volume, whose it is, and taking out what nothing needs | [`spin admin storage list`](https://spin-stack.github.io/website/reference/cli/admin.md) |
| Re-key a workspace's disk | [`spin admin volume rekey`](https://spin-stack.github.io/website/reference/cli/admin.md) |
| Runners: registration tokens, drain, activate, revoke, and a policy per host | [`spin admin runner drain`](https://spin-stack.github.io/website/reference/cli/admin.md) |
| Runners start when a workspace waits for one and stop when nothing runs | [`HostService/GetFleet`](https://spin-stack.github.io/website/reference/api/hostservice.md) |
| A host that reboots brings its workspaces back | [`TestAHostRebootBringsItsWorkspacesBack`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/restart_test.go#L38), an end-to-end test |
| A cloud's reclaim warning empties the host before the machine goes | [`TestACloudsReclaimWarningEmptiesTheHostBeforeAnySignal`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/preemption_test.go#L26), an end-to-end test |
| A writeback bound per host, measured on that host before it is taken | [`TestCustomWritebackValuesAreMeasuredOnTheRunner`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/writeback_test.go#L18), an end-to-end test |
| What is running where: the control plane, each runner and its machine | [`spin admin versions`](https://spin-stack.github.io/website/reference/cli/admin.md) |

### Observability

| Feature | Proof |
|---|---|
| Platform logs, workspace logs and traces, searched in the product | [`LogService/SearchPlatformLogs`](https://spin-stack.github.io/website/reference/api/logservice.md) |
| Metrics, with Grafana on the control plane | [`AdminService/GetMonitoring`](https://spin-stack.github.io/website/reference/api/adminservice.md) |
| A workspace's journal and console are collected only with its owner's consent | [`spin workspace logs-consent`](https://spin-stack.github.io/website/reference/cli/workspace.md) |

### Platform

| Feature | Proof |
|---|---|
| A smoke test of what an installation's API promises, with a workspace of its own | [`spin smoke`](https://spin-stack.github.io/website/reference/cli/smoke.md) |
| A host serves only the releases it carries | [`TestAMachineAdoptedWithoutItsReleasesIsSuspendedWithItsDisk`](https://github.com/spin-stack/spin/blob/8eee32b9ddc8d535b3300d0da3927a30b33f22c4/internal/e2e/suspend_test.go#L118), an end-to-end test |

## Partly there

Nothing today.

## Not built

Each is an item of `docs/ROADMAP.md`, with the command that checks it.

- **What a workspace grew to is asked for and never recorded** (Workspaces)
- **Placement cannot be told which kind of host a workspace belongs on** (Workspaces)
- **A workspace whose host never comes back is moved only when little would be lost** (Administration)
- **Nothing that needs a kernel runs in CI** (Platform)
- **`spin/v1` is still ignored by the breaking-change gate** (Platform)

## Limits

Not planned: a limit of the platform or of where it runs today. [Limitations](https://spin-stack.github.io/website/overview/limitations.md) says what each means.

- **AWS only** (Platform): The Terraform module is the one supported install; nothing else is packaged or tested.
- **x86-64 only** (Platform): Runners are x86-64 machines with nested virtualization.
- **The CLI runs on Linux x86-64 and macOS Apple silicon** (Platform)
- **One region, one control plane** (Platform): A machine that fails is replaced in minutes, not seconds.
- **No GPUs** (Workspaces): There is no way to ask for a runner of a particular kind.
- **Linux guests only** (Workspaces): Booted with the kernel spin provides.
- **No IPv6 inside a workspace** (Network)
- **TCP only for published ports** (Network)
- **A diff does not see everything** (Snapshots): A file is hashed only when its size, inode or times changed; extended attributes are not compared.
- **A memory snapshot resumes only on the same machine** (Snapshots): The same QEMU, guest kernel and guest init; a disk restore has no such limit.
- **Disk chains have a limit** (Snapshots): At the limit the top layer grows instead, so less of the recent work is in the bucket.
- **Work since the last upload can be lost** (Snapshots): A runner uploads writes in layers, on the RPO, on snapshot and on stop; what it had not uploaded goes with it.
- **No multi-factor authentication of Spinbox's own** (Access): Sign in through a provider that enforces it.
- **No invitations** (Access): A person signs in once before they can be added to a team.
- **Team roles are fixed** (Access): Owner, admin and member.
- **Nothing pages anyone** (Observability): Metrics, logs and traces stay inside the installation; there are no alerts.
- **An update is one way** (Administration): A release older than the one that last started the database refuses to start on it.
