# Products and environments

Products are what you test, environments are where they run, and a deployment joins one product to one environment.

A workspace describes the software it tests and where that software runs with three objects.
Products and environments do not depend on each other; only a deployment joins them. Test runs
target a deployment, and the secrets vault keeps each deployment's values.

| Object      | Meaning                                                                                                                          |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Product     | A piece of software the workspace tests, such as the `storefront` website or a public API                                        |
| Environment | A place products run, such as `staging` or `production`, shared by every product                                                 |
| Deployment  | One product running in one environment: where it answers (`baseUrl`), its Fixture API (`fixtureUrl`) and which build (`version`) |

## Products

- `slug`: 2–48 lowercase letters, digits or hyphens, with no hyphen at the start or end and not a
  reserved Windows folder name such as `con`. Unique in the workspace.
- `name`: 1–100 characters, unique in the workspace ignoring case.
- `type`: `website`, `api`, `cli`, `mobile_app`, `desktop_app` or `agent`. A product becomes a
  website or API product only once each of its deployments has a base URL.
- `description`: optional, up to 200 characters.
- `repository`: optional, the source repository as `owner/name`, such as `acme/storefront`.
  Messages about a project's tickets go to clanker sessions working in the repositories of the
  products the project changes.

## Environments

- `slug` and `name`: the same rules as a product, with names up to 80 characters.
- `class`: `production` or `non-production`, chosen at creation and never changed. Production means
  real customer data, or the live system customers use. To treat a place as the other class, create
  a new environment.
- `description`: optional, up to 200 characters. `emoji`: optional, shown beside the name.

The class decides the vault's rules: only admins and owners write production secrets, and only a
vault key reads them back. See [Secrets vault and CLI](https://docs.clankership.com/get-started/concepts/secrets-vault.md).

## Deployments

- One per product and environment pair, addressed as `{product}/{environment}`, such as
  `storefront/staging`.
- `baseUrl`: an `http://` or `https://` URL without a username, password or `#fragment`. A trailing
  slash is dropped. Required for website and API products.
- `fixtureUrl`: optional, the deployment's Fixture API, which test runs call to create test data
  and delete it when they finish. It follows the same URL rules as `baseUrl`. See
  [Test runs](https://docs.clankership.com/get-started/concepts/test-runs.md#test-data).
- `version`: optional free text up to 100 characters, such as a git SHA or a tag. The server sets
  `versionUpdatedAt` whenever it changes.
- `active`: false while its product or its environment is archived.

Responses carry IDs as well as slugs. IDs never change; renaming a slug keeps deployments, secrets
and vault key grants, and the old slug stops working.

## Archive, restore and remove

Products and environments are archived, never deleted. Archiving one:

- hides it from lists unless you ask for archived objects with `archived=include` or
  `archived=only`;
- makes it read-only: changing it, or creating, changing or removing one of its deployments, fails
  with `409` and says to restore it first;
- keeps its slug and name reserved, so it can always be restored;
- makes its deployments inactive, so vault pulls for them are refused.

Restoring reverses all of this. Repeating an archive or a restore returns the object unchanged.

Removing a deployment deletes it, but its secret values stay: deploying the same pair again brings
them back.

## Who can change them

| Action                                              | Viewer | Member | Admin, owner |
| --------------------------------------------------- | ------ | ------ | ------------ |
| List and get products, environments and deployments | yes    | yes    | yes          |
| Create, change, archive and restore                 | no     | yes    | yes          |
| Create, change and remove deployments               | no     | yes    | yes          |

## API

Paths are relative to `https://api.clankership.com/v1/workspaces/{slug}`. Creating returns `201`,
removing a deployment returns `204`, and every other call returns `200` with the object. `PATCH`
changes only the fields you send, and `null` clears an optional field.

| Operation           | Request                                        | Reference                                      |
| ------------------- | ---------------------------------------------- | ---------------------------------------------- |
| List products       | `GET /products?archived=include`               | [List products](https://docs.clankership.com/api/products/list.md)            |
| Create a product    | `POST /products`                               | [Create a product](https://docs.clankership.com/api/products/create.md)       |
| Change a product    | `PATCH /products/{product}`                    | [Update a product](https://docs.clankership.com/api/products/update.md)       |
| Archive, restore    | `POST /products/{product}/archive`, `/restore` | [Archive a product](https://docs.clankership.com/api/products/archive.md)     |
| Environments        | The same under `/environments`                 | [Environments](https://docs.clankership.com/api/environments.md)              |
| List deployments    | `GET /deployments?product=storefront`          | [List deployments](https://docs.clankership.com/api/deployments/list.md)      |
| Create a deployment | `POST /deployments`                            | [Create a deployment](https://docs.clankership.com/api/deployments/create.md) |
| Change a deployment | `PATCH /deployments/{product}/{environment}`   | [Update a deployment](https://docs.clankership.com/api/deployments/update.md) |
| Remove a deployment | `DELETE /deployments/{product}/{environment}`  | [Delete a deployment](https://docs.clankership.com/api/deployments/delete.md) |

```bash
curl https://api.clankership.com/v1/workspaces/acme/deployments \
  -H "Authorization: Bearer $CLANKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "product": "storefront", "environment": "production", "baseUrl": "https://shop.acme.dev" }'
```

## CLI

Every command prints the API's JSON, uses the workspace `clanker link` recorded (or `--workspace`),
and exits 2 when it is used wrongly or the request is refused. An empty value clears a field.

```bash
clanker environment create production --name Production --class production
clanker product create storefront --name Storefront --type website --repository acme/storefront
clanker deployment create storefront production --base-url https://shop.acme.dev \
  --fixture-url https://shop.acme.dev/fixtures
clanker deployment update storefront production --deployed-version "$GIT_SHA"
clanker product list --archived only
clanker product archive storefront
clanker product restore storefront
```

The flag is `--deployed-version` because `--version` prints the CLI's own version.

## Clankers

Clankers use [list_products](https://docs.clankership.com/mcp/tools/list_products.md),
[create_deployment](https://docs.clankership.com/mcp/tools/create_deployment.md), [update_deployment](https://docs.clankership.com/mcp/tools/update_deployment.md)
and the other catalog tools, or their `/clanker/v1` twins. Archiving and removing are marked
destructive, so clients ask before they run them.

## Errors

| Rule                        | Status | Example message                                                                          |
| --------------------------- | ------ | ---------------------------------------------------------------------------------------- |
| Slug or name taken          | `409`  | A product named Storefront already exists.                                               |
| Taken by an archived object | `409`  | An archived product already uses the slug storefront. Restore it or choose another slug. |
| Pair already deployed       | `409`  | Storefront is already deployed to Staging.                                               |
| Archived object             | `409`  | Storefront is archived. Restore it before changing it or its deployments.                |
| Not found                   | `404`  | No product with the slug storefront.                                                     |
| Role too low                | `403`  | You do not have permission to manage products, environments or deployments.              |
| Bad slug, class or base URL | `400`  | The message names the rule, such as the slug format or a missing base URL.               |

<!-- surfaces -->

## On every surface

Generated from Clanker Ship's surface registry. A dash means the surface leaves the operation out.

| Operation                          | Website          | API                                                                                         | MCP                                                     | CLI                                                       |
| ---------------------------------- | ---------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------- | --------------------------------------------------------- |
| List products                      | Products         | [GET /v1/workspaces/{slug}/products](https://docs.clankership.com/api/products/list.md)                                    | [`list_products`](https://docs.clankership.com/mcp/tools/list_products.md)             | [`clanker product list`](https://docs.clankership.com/cli/product/list.md)               |
| Read a product                     | Product page     | [GET /v1/workspaces/{slug}/products/{product}](https://docs.clankership.com/api/products/get.md)                           | [`get_product`](https://docs.clankership.com/mcp/tools/get_product.md)                 | [`clanker product get`](https://docs.clankership.com/cli/product/get.md)                 |
| Create a product                   | Products         | [POST /v1/workspaces/{slug}/products](https://docs.clankership.com/api/products/create.md)                                 | [`create_product`](https://docs.clankership.com/mcp/tools/create_product.md)           | [`clanker product create`](https://docs.clankership.com/cli/product/create.md)           |
| Change a product                   | Products         | [PATCH /v1/workspaces/{slug}/products/{product}](https://docs.clankership.com/api/products/update.md)                      | [`update_product`](https://docs.clankership.com/mcp/tools/update_product.md)           | [`clanker product update`](https://docs.clankership.com/cli/product/update.md)           |
| Archive a product                  | Products         | [POST /v1/workspaces/{slug}/products/{product}/archive](https://docs.clankership.com/api/products/archive.md)              | [`archive_product`](https://docs.clankership.com/mcp/tools/archive_product.md)         | [`clanker product archive`](https://docs.clankership.com/cli/product/archive.md)         |
| Restore a product                  | Products         | [POST /v1/workspaces/{slug}/products/{product}/restore](https://docs.clankership.com/api/products/restore.md)              | [`restore_product`](https://docs.clankership.com/mcp/tools/restore_product.md)         | [`clanker product restore`](https://docs.clankership.com/cli/product/restore.md)         |
| List environments                  | Environments     | [GET /v1/workspaces/{slug}/environments](https://docs.clankership.com/api/environments/list.md)                            | [`list_environments`](https://docs.clankership.com/mcp/tools/list_environments.md)     | [`clanker environment list`](https://docs.clankership.com/cli/environment/list.md)       |
| Read a environment                 | Environment page | [GET /v1/workspaces/{slug}/environments/{environment}](https://docs.clankership.com/api/environments/get.md)               | [`get_environment`](https://docs.clankership.com/mcp/tools/get_environment.md)         | [`clanker environment get`](https://docs.clankership.com/cli/environment/get.md)         |
| Create a environment               | Environments     | [POST /v1/workspaces/{slug}/environments](https://docs.clankership.com/api/environments/create.md)                         | [`create_environment`](https://docs.clankership.com/mcp/tools/create_environment.md)   | [`clanker environment create`](https://docs.clankership.com/cli/environment/create.md)   |
| Change a environment               | Environments     | [PATCH /v1/workspaces/{slug}/environments/{environment}](https://docs.clankership.com/api/environments/update.md)          | [`update_environment`](https://docs.clankership.com/mcp/tools/update_environment.md)   | [`clanker environment update`](https://docs.clankership.com/cli/environment/update.md)   |
| Archive a environment              | Environments     | [POST /v1/workspaces/{slug}/environments/{environment}/archive](https://docs.clankership.com/api/environments/archive.md)  | [`archive_environment`](https://docs.clankership.com/mcp/tools/archive_environment.md) | [`clanker environment archive`](https://docs.clankership.com/cli/environment/archive.md) |
| Restore a environment              | Environments     | [POST /v1/workspaces/{slug}/environments/{environment}/restore](https://docs.clankership.com/api/environments/restore.md)  | [`restore_environment`](https://docs.clankership.com/mcp/tools/restore_environment.md) | [`clanker environment restore`](https://docs.clankership.com/cli/environment/restore.md) |
| List deployments                   | Product page     | [GET /v1/workspaces/{slug}/deployments](https://docs.clankership.com/api/deployments/list.md)                              | [`list_deployments`](https://docs.clankership.com/mcp/tools/list_deployments.md)       | [`clanker deployment list`](https://docs.clankership.com/cli/deployment/list.md)         |
| Read a deployment                  | Product page     | [GET /v1/workspaces/{slug}/deployments/{product}/{environment}](https://docs.clankership.com/api/deployments/get.md)       | [`get_deployment`](https://docs.clankership.com/mcp/tools/get_deployment.md)           | [`clanker deployment get`](https://docs.clankership.com/cli/deployment/get.md)           |
| Deploy a product to an environment | Product page     | [POST /v1/workspaces/{slug}/deployments](https://docs.clankership.com/api/deployments/create.md)                           | [`create_deployment`](https://docs.clankership.com/mcp/tools/create_deployment.md)     | [`clanker deployment create`](https://docs.clankership.com/cli/deployment/create.md)     |
| Change a deployment                | Product page     | [PATCH /v1/workspaces/{slug}/deployments/{product}/{environment}](https://docs.clankership.com/api/deployments/update.md)  | [`update_deployment`](https://docs.clankership.com/mcp/tools/update_deployment.md)     | [`clanker deployment update`](https://docs.clankership.com/cli/deployment/update.md)     |
| Remove a deployment                | Product page     | [DELETE /v1/workspaces/{slug}/deployments/{product}/{environment}](https://docs.clankership.com/api/deployments/delete.md) | [`remove_deployment`](https://docs.clankership.com/mcp/tools/remove_deployment.md)     | [`clanker deployment remove`](https://docs.clankership.com/cli/deployment/remove.md)     |

<!-- /surfaces -->
