# Products and environments

A workspace describes what it tests and where it runs:

- A **product** is a piece of software the workspace tests. Its `type` is
  `website`, `api`, `cli`, `mobile_app`, `desktop_app` or `agent`, and its
  optional `repository`, such as `acme/storefront`, is where its code lives.
- An **environment** is a place products run, such as `localhost`, `qa` or
  `production`. Its `class` is `production` or `non-production`, chosen once.
- A **deployment** is one product running in one environment. It records the
  `baseUrl` where the product answers and the `version` that is running.

Secrets belong to a product and its deployments; see
[Secrets vault and CLI](/guides/secrets-vault.md).

## Rules

- Slugs are 2–48 lowercase letters, digits or hyphens, with no leading or
  trailing hyphen and no reserved Windows folder name. Product names are 1–100
  characters, environment names 1–80. Names are unique ignoring case.
- Website and API products need an `http://` or `https://` `baseUrl` in every
  deployment, without a username, password or `#fragment`.
- An environment's class never changes.
- Archive replaces delete. An archived product or environment is hidden from
  lists, read-only, and its deployments refuse vault pulls. It keeps its slug
  and name, and `restore` brings everything back. Archive and restore can be
  repeated safely.
- Removing a deployment keeps its secret values; deploying the pair again shows
  them again.
- Members, admins and owners make changes; viewers read. Account API keys use
  their role.

## HTTP

Paths are relative to `/v1/workspaces/{slug}`. Writes return the changed object;
create returns 201 and remove returns 204. `PATCH` changes only the fields you
send, and `null` clears an optional field.

| Operation          | Request                                                                 |
| ------------------ | ----------------------------------------------------------------------- |
| List               | `GET /products`, `GET /environments`, `GET /deployments`                |
| Archived objects   | `?archived=include` or `?archived=only` on any list                     |
| Filter deployments | `GET /deployments?product={product}&environment={environment}`          |
| Get                | `GET /products/{product}`, `GET /environments/{environment}`            |
| Create             | `POST /products`, `POST /environments`, `POST /deployments`             |
| Change             | `PATCH /products/{product}`, `PATCH /environments/{environment}`        |
| Archive, restore   | `POST /products/{product}/archive`, `…/restore` (same for environments) |
| One deployment     | `GET`, `PATCH`, `DELETE /deployments/{product}/{environment}`           |

```http
POST /v1/workspaces/acme/deployments
Authorization: Bearer ctk_…

{ "product": "web-app", "environment": "qa", "baseUrl": "https://qa.shop.example" }
```

Record what is running after each deploy:

```http
PATCH /v1/workspaces/acme/deployments/web-app/qa

{ "version": "a1c9e02" }
```

The response carries `versionUpdatedAt`. Full schemas are in
[`/openapi.json`](/openapi.json) as `Product`, `Environment` and `Deployment`.

## CLI

Every command prints the API's JSON, takes `--workspace <slug>` or reads
`clanker.json`, and exits 2 when it is used wrongly or the request is refused.

```sh
clanker environment create qa --name QA --class non-production
clanker product create web-app --name 'Web App' --type website
clanker deployment create web-app qa --base-url https://qa.shop.example
clanker deployment update web-app qa --deployed-version "$GIT_SHA"
clanker product list --archived only
clanker product archive web-app
clanker product restore web-app
```

Pass an empty value to clear a field, such as `--deployed-version ""`.

## Agents

Agents use the MCP tools `list_products`, `create_deployment`, `update_deployment`
and the rest of the catalog tools, or their `/agent/v1` twins, with an agent grant.
See [Agents and MCP](/guides/agents.md).
