---
title: "Environments & the kill switch"
description: "Isolate staging from production at the key, and stop an environment with one switch."
---

An **environment** is an isolated space for your resources. A new workspace starts with one protected environment of kind `production`, named Production, with the slug `production`. A plan allows a total number of environments of any kind: 3 during Early Beta Access, 1 on the standard Free plan, 2 on Production, 3 on Growth, and unlimited on Enterprise. You choose each environment's kind (`production`, `staging` or `development`) and can change it later in the console or through the API.

## A key is its environment

Every API key belongs to **exactly one environment** and resolves it on authentication. A key cannot read or write another environment's data, because the environment is bound to the credential itself. This is logical isolation: rows in shared storage, filtered by an enforced column. It is not dedicated storage or compute.

```typescript
import { Client } from '@anlyonhq/sdk';

// This key was minted against `staging`. The actions it invokes, the
// approvals it requests and the runs it records are staging data, and it
// cannot reach production data.
const client = new Client({ apiKey: process.env.ANLYON_STAGING_KEY! });
```

Isolation holds across the resources an agent works with: actions, secrets, invocations, approvals, events, agents, and their runs and spans. It also holds across the earlier namespaces. URL groups, flow-control keys and execution logs were the exceptions until September 2026. They are scoped now, execution logs through the message or schedule they belong to. The same name (a topic, an action) can exist in `staging` and `production` as two distinct resources. Resolving a `staging` name does not return the `production` one.

The secret that signs outbound deliveries is per workspace. A signed delivery names its environment inside the signature, so a verifier configured with the expected environment rejects a staging delivery presented as a production one. What is shared is the key material, so rotating it rotates for every environment in the workspace at once. Action invocations carry no Anlyon delivery signature. A notification webhook carries no `Anlyon-Signature`. It carries `X-Anlyon-Signature: sha256=<hex>` when a webhook secret is set, and nothing otherwise.

**Where names are unique**

Event topics, actions and secrets are unique **per environment**, so staging and production can share names without colliding. Billing counters are deliberately workspace-level.

## The kill switch

When an agent misbehaves (a runaway loop, a bad deploy, a prompt-injection scare), halt the whole environment, with a reason recorded. From the dashboard (**Environments → Halt**), or from a runbook:

```typescript
import { Client } from '@anlyonhq/sdk';

// An operator key holding `environments:halt`, not your agent's key.
const operator = new Client({ apiKey: process.env.ANLYON_OPERATOR_KEY! });

await operator.environment.halt({ reason: 'runaway refund loop' });

// ...and when the incident is over:
await operator.environment.resume();
```

The API halts **the calling key's own environment** and needs the `environments:halt` scope, which is not granted by default. A staging key can halt staging and cannot reach production, for the same reason it cannot read production.

The contract, in one sentence: **halting stops the agent acting and stops anything leaving, while continuing to accept data so nothing in flight is lost, and leaving your controls working.** It stops new dispatch after the halt check. A request an external server already accepted is not recalled.

Stopped:

- **Action invocations are blocked** and recorded on the row. That includes approval-gated resumes, so an *already-approved* call still will not run.
- **A replay of a governed effect is refused.** Reconcile, notes and resolve stay available.
- **In the earlier namespaces**, message deliveries defer without consuming a retry attempt, workflow runs park, and writes to memory, files, sessions and semantic cache return `409`.

Still working:

- **Publishing still queues.** An event you send is accepted and held. Delivery is what defers.
- **Approvals can still be decided**, including denying the ones that piled up.
- **Every read still answers**, so an agent can drain what it already has without starting anything new.
- **Resume works**, obviously. The switch never disables its own undo.

When you resume, deferred work is released and picks up where it left off.

**It cannot silently un-halt**

The halt flag lives in Redis for the hot path, but the database is the source of truth. Redis holds an explicit, versioned copy of each environment's state. A missing copy (after a flush, a failover or an eviction) is answered from the database and rebuilt, and an older copy does not overwrite a newer one. So a Redis flush or eviction does not resume a halted environment, and a resume is not undone by a stale re-sync. If neither layer can be read at all, the check reports **halted**: an outage is when you are most likely to be reaching for the switch, so being wrong in that direction is the only safe way to be wrong.

## Protected production

Environment protection and controlled promotion are included during Early Beta Access, and on the Production, Growth and Enterprise plans. The default Production environment of a new workspace is protected. Promotion into a protected environment requires an explicit `confirmProtected` acknowledgement. You can mark an environment protected, or remove protection, from the dashboard. An environment you add is unprotected until you protect it. Isolation and the halt switch are included on every plan.

## What to reach for

### Preparing for a plan downgrade

Use **Environments → Manage** to change an environment's kind without moving or
deleting its resources, or to make it the workspace default. Remove protection
before reclassifying a protected environment. Kind limits are checked when saving.

Owners can delete an **empty** environment after halting it, removing protection,
and choosing another default. Type its exact slug to confirm. The server refuses
deletion while resources or retained history reference it. Remove resources using
their normal controls and let retained history expire. Deletion never cascades
customer data or removes stored objects implicitly.

After requesting a downgrade, new seats, actions, and environments must fit the
target plan immediately. Current paid usage allowances continue until the billing
boundary. **Billing → Keep current plan** withdraws the requested change.

- Create separate keys per environment. Do not let a build use a production key for tests.
- Put the kill switch behind an on-call runbook, with an operator key holding `environments:halt`. It stops new dispatch without a redeploy.
- See [Immutable versions & rollback](/trust-control/promotion) for moving configuration between environments safely.
