DOCSImages and the registry
DOCS

Images and the registry

Every workspace has its own private namespace in the isolance container registry, registry.caas.sh/<tenant-id>/. Push an image there with Docker, then run it in a sandbox or an MCP server. Only your workspace's API keys, and your workspace's own sandboxes, can pull it.

This guide covers logging in, naming, building and pushing, running an image by its digest, listing tags, pricing and deleting images. The CLI examples assume you've installed and configured caas (see The CLI).

Log in to the registry

The registry takes the same API keys as the API. Docker logs in with your workspace's tenant ID as the username and an API key as the password.

Create an API key

API keys are created only in the console:

  1. Sign in to the console and open Settings.

  2. Under Workspace, copy the Tenant ID.

  3. Under API keys, enter a Key name, such as docker on my laptop, and choose Create key.

  4. Copy the key. It starts with ck_, and the console shows it only once.

Owners and operators can create keys; viewers can't. A new key can push and pull images.

Log in with Docker

shell
export CAAS_TENANT=<tenant-id>
export CAAS_API_KEY=<api-key>

echo "$CAAS_API_KEY" | docker login registry.caas.sh --username "$CAAS_TENANT" --password-stdin

Log in with the CLI

If you've saved your tenant ID and key with caas configure, log Docker in with them:

shell
caas registry login

It runs docker login registry.caas.sh with your tenant ID as the username and your saved key as the password.

What a key can do

AccessNeedsLets the key
registry:readAny key from the consolePull images and list tags
registry:writeAny key from the console, while its creator is an owner or operatorPush and delete images, and pull them

A key only ever reaches its own workspace's namespace. If the member who created a key becomes a viewer, the key can still pull but no longer push. A revoked key stops working within a minute. See The API for scopes and roles.

Name your images

An image in your registry is named registry.caas.sh/<tenant-id>/<name>:<tag>, for example registry.caas.sh/<tenant-id>/agent:1.2.0.

  • <tenant-id> is your workspace's Tenant ID. You can only push to and pull from your own.

  • <name> is one to four parts separated by /, such as agent or tools/python. Each part is lowercase letters and digits, which ., _, __ or hyphens may join, as in my-agent or node_24.tools. <tenant-id>/<name> is at most 255 characters.

  • <tag> is up to 128 letters, digits, _, . and -, and doesn't start with . or -.

Build and push an image

Sandboxes run linux/amd64 images. Build for that platform, even on an Arm Mac, then push:

shell
docker build --platform linux/amd64 -t registry.caas.sh/$CAAS_TENANT/agent:1.2.0 .
docker push registry.caas.sh/$CAAS_TENANT/agent:1.2.0

docker push ends with the image's digest:

1.2.0: digest: sha256:4f1c…e9a2 size: 1784

A multi-platform image works too, as long as it includes linux/amd64.

To look up a tag's digest later, ask the registry for its manifest's headers:

shell
curl -sI -u "$CAAS_TENANT:$CAAS_API_KEY" \
  https://registry.caas.sh/v2/$CAAS_TENANT/agent/manifests/1.2.0 | grep -i docker-content-digest

To pull an image to your own machine, log in, then use docker pull as usual:

shell
docker pull registry.caas.sh/$CAAS_TENANT/agent:1.2.0

What the image needs

  • /bin/sh, base64, tar and gzip. isolance runs your commands, moves files and takes snapshots inside the image's container, with these tools.

  • Layers under about 100 MB. docker push uploads each layer in one request, and a layer over about 100 MB can exceed the registry's upload limit. Split large installs across several RUN instructions to keep each layer smaller.

Run your image

Sandboxes and MCP servers run an image pinned to its digest, registry.caas.sh/<tenant-id>/<name>@sha256:…, so what runs is exactly the image you pushed, even if you push the tag again later. The CLI looks tags up for you; the console and the API take the digest. To copy one, open Registry in the console, then the repository: each image shows its reference, shortened, with a copy icon for the whole reference.

Before anything is created, isolance checks that the digest exists in your namespace.

Sizes

A sandbox or MCP server on your own image needs size M (1/2 vCPU, 4 GiB of memory, 8 GB of disk) or larger, or a custom size with at least 4 GiB of memory and 8 GB of disk. XS and S are refused with sandboxes on your own image need size M or larger. See Sizes.

In a sandbox

A sandbox runs its command at every start, in place of the image's entrypoint and command; without a command, the image's own entrypoint and command run, and an image without any runs nothing until you send it commands. These, and every command you run in the sandbox, run in the image's container, where the sandbox's working directory, /workspace, is mounted.

In the console:

  1. Open Sandboxes and choose New sandbox.

  2. Under 1. Choose an image, pick Your image.

  3. In Image, enter the digest reference, registry.caas.sh/<tenant-id>/agent@sha256:….

  4. Optionally, in Command, enter what the sandbox runs at every start, such as node agent.js. Leave it empty to run the image's own entrypoint and command.

  5. Under 2. Configure, pick size M or larger, and choose Create sandbox.

With the CLI, --image takes a tag or a digest. caas run creates a sandbox without a command, so the image's own entrypoint and command, if it has any, run at its start; then it runs node agent.js in the sandbox once and prints its output. To make node agent.js the sandbox's command, pass --command:

shell
caas run --image agent:1.2.0 -- node agent.js
caas run --image agent@sha256:<digest> --size l -- node agent.js
caas sandboxes create --image agent:1.2.0 --command "node agent.js"

You can write the image as NAME[:TAG] or NAME@sha256:DIGEST, optionally under registry.caas.sh/ or registry.caas.sh/<tenant-id>/. Without a tag, the CLI uses latest. It looks the tag up in the registry, which needs registry:read, and creates the sandbox with the digest. Images from other registries or other workspaces are refused with push the image to registry.caas.sh/<tenant-id>/NAME first.

With the API, put the digest reference in image:

shell
curl https://api.caas.sh/v1/sandboxes \
  -H "Authorization: Bearer $CAAS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "image": "registry.caas.sh/<tenant-id>/agent@sha256:<digest>",
    "command": ["node", "agent.js"],
    "size": "m"
  }'

The API doesn't take tags. A reference in another workspace's namespace gets 400 with image must belong to this tenant, and a digest the registry doesn't hold gets 400 with image digest not found in registry.caas.sh. Without command, the image's own entrypoint and command run. Sandboxes covers the other fields.

In an MCP server

caas mcp create --image server:1.2.3 --http 3000 creates an MCP server from your image, serving MCP over HTTP on port 3000. Without --command, the image's own entrypoint and command start the server. MCP servers covers servers on your own image.

Private pulls

Your images never need to be public, and your sandboxes never need your API key to pull them:

  • When a sandbox or an MCP server starts on your image, isolance pulls it from registry.caas.sh for you, with a short-lived credential that can only pull that image. You don't log in from inside the sandbox.

  • A sandbox can always reach registry.caas.sh. You don't add it to the sandbox's allowed outbound hosts.

  • Traffic between your sandboxes and registry.caas.sh doesn't bill as egress. Pulls count only as registry pulls (see Pricing).

  • Nobody outside your workspace can pull your images: the registry serves a key only its own workspace's namespace, and refuses requests without a key.

List tags

The registry answers the standard tags list for one image name:

shell
curl -s -u "$CAAS_TENANT:$CAAS_API_KEY" \
  https://registry.caas.sh/v2/$CAAS_TENANT/agent/tags/list
json
{ "name": "<tenant-id>/agent", "tags": ["1.1.0", "1.2.0", "latest"] }

It returns up to 50 tags at a time; add ?n=100 for more. When there are more, the response's Link header holds the URL of the next page. Each request bills as one list.

Docker's catalog (/v2/_catalog) is refused. To see every image name in your workspace, open Registry in the console, or ask the API with a key that has registry:read; these reads don't bill as lists:

shell
curl -s https://api.caas.sh/v1/images -H "Authorization: Bearer $CAAS_API_KEY"

It answers each repository with its tag and image counts, the bytes it stores and when it was last pushed. GET /v1/images/<name> lists one repository's images, newest first, each with its digest, tags, platforms, size and when it was pushed.

Pricing

MeterPriceWhat counts
Registry storageOn the pricing pageEverything stored in your namespace: manifests, configs and layers, measured every hour
Registry pullsOn the pricing pageEach image manifest fetched, by Docker or by your sandboxes. A multi-platform image counts two: its index and the platform's manifest. HEAD requests and layer downloads are free.
Registry listsOn the pricing pageEach tags listing

A GB is 1,000,000,000 bytes, and a month is 30 days. A sandbox on your own image pulls it each time it starts, and each of those pulls bills to your workspace. Registry usage draws from the workspace's balance like everything else; see Billing and usage.

Delete images

The simplest way is Registry in the console: open the repository, then choose Delete tag or Delete image from the image's ••• menu. The console asks first and says which of your sandboxes and MCP servers run it. Deleting an image there also frees the storage its layers used, unless another image still uses them.

The API does the same with a key that has registry:write:

shell
# Remove one tag; the image stays under its digest and any other tags.
curl -X DELETE https://api.caas.sh/v1/images/agent:1.1.0 -H "Authorization: Bearer $CAAS_API_KEY"
# Remove the image, every tag naming it, and the layers no other image uses.
curl -X DELETE https://api.caas.sh/v1/images/agent@sha256:<digest> -H "Authorization: Bearer $CAAS_API_KEY"

A sandbox pulls its image every time it starts. Don't delete an image that a sandbox still uses.

The registry's own Docker DELETE requests work too, as below, but they leave the layers behind.

Delete a tag

shell
curl -X DELETE -u "$CAAS_TENANT:$CAAS_API_KEY" \
  https://registry.caas.sh/v2/$CAAS_TENANT/agent/manifests/1.1.0

This removes only the tag. The image stays, under its digest and any other tags.

Delete an image

shell
curl -X DELETE -u "$CAAS_TENANT:$CAAS_API_KEY" \
  https://registry.caas.sh/v2/$CAAS_TENANT/agent/manifests/sha256:<digest>

This removes the image's manifest and every tag that points to it.

Free the storage it used

Deleting a manifest doesn't delete its layers, which keep counting toward registry storage. To free them:

  1. Before you delete the image, read its manifest and note the config.digest and each layers[].digest. If it's an index (a multi-platform image), it lists other manifests under manifests: read each of those too, and delete them along with the index.

    shell
    curl -s -u "$CAAS_TENANT:$CAAS_API_KEY" \
      https://registry.caas.sh/v2/$CAAS_TENANT/agent/manifests/sha256:<digest>
  2. Delete the image, as above.

  3. Delete each layer and config that no other image in your namespace uses:

    shell
    curl -X DELETE -u "$CAAS_TENANT:$CAAS_API_KEY" \
      https://registry.caas.sh/v2/$CAAS_TENANT/agent/blobs/sha256:<layer-digest>

Docker can share a layer between image names when it pushes, so an image under another name may use it too. Deleting a layer that another image still uses breaks that image.

Troubleshooting

What you seeWhat to do
docker login fails with unauthorizedUse your Tenant ID as the username and an API key from the same workspace as the password. Check that the key isn't revoked.
docker push is refusedPush to registry.caas.sh/<tenant-id>/… with your own Tenant ID, with a key whose creator is still an owner or operator.
A large layer fails to uploadKeep each layer under about 100 MB.
429 with TOOMANYREQUESTSOne address or one key sent more than about 1,200 requests in a minute. Wait a minute, then retry.
image tag not found from the CLIPush the tag first, or check its spelling.
image digest not found in registry.caas.shThe digest is wrong, or the image was deleted. Copy it again from docker push.
image must belong to this tenantThe reference names another workspace's namespace. Push the image to yours.
sandboxes on your own image need size M or largerPick M or larger, or a custom size with at least 4 GiB and 8 GB.