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:
Sign in to the console and open Settings.
Under Workspace, copy the Tenant ID.
Under API keys, enter a Key name, such as
docker on my laptop, and choose Create key.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
export CAAS_TENANT=<tenant-id>
export CAAS_API_KEY=<api-key>
echo "$CAAS_API_KEY" | docker login registry.caas.sh --username "$CAAS_TENANT" --password-stdinLog in with the CLI
If you've saved your tenant ID and key with caas configure, log Docker in with them:
caas registry loginIt 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
| Access | Needs | Lets the key |
|---|---|---|
registry:read | Any key from the console | Pull images and list tags |
registry:write | Any key from the console, while its creator is an owner or operator | Push 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 asagentortools/python. Each part is lowercase letters and digits, which.,_,__or hyphens may join, as inmy-agentornode_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:
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.0docker push ends with the image's digest:
1.2.0: digest: sha256:4f1c…e9a2 size: 1784A 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:
curl -sI -u "$CAAS_TENANT:$CAAS_API_KEY" \
https://registry.caas.sh/v2/$CAAS_TENANT/agent/manifests/1.2.0 | grep -i docker-content-digestTo pull an image to your own machine, log in, then use docker pull as usual:
docker pull registry.caas.sh/$CAAS_TENANT/agent:1.2.0What the image needs
/bin/sh,base64,tarandgzip. isolance runs your commands, moves files and takes snapshots inside the image's container, with these tools.Layers under about 100 MB.
docker pushuploads each layer in one request, and a layer over about 100 MB can exceed the registry's upload limit. Split large installs across severalRUNinstructions 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:
Open Sandboxes and choose New sandbox.
Under 1. Choose an image, pick Your image.
In Image, enter the digest reference,
registry.caas.sh/<tenant-id>/agent@sha256:….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.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:
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:
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.shfor 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.shdoesn'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:
curl -s -u "$CAAS_TENANT:$CAAS_API_KEY" \
https://registry.caas.sh/v2/$CAAS_TENANT/agent/tags/list{ "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:
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
| Meter | Price | What counts |
|---|---|---|
| Registry storage | On the pricing page | Everything stored in your namespace: manifests, configs and layers, measured every hour |
| Registry pulls | On the pricing page | Each 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 lists | On the pricing page | Each 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:
# 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
curl -X DELETE -u "$CAAS_TENANT:$CAAS_API_KEY" \
https://registry.caas.sh/v2/$CAAS_TENANT/agent/manifests/1.1.0This removes only the tag. The image stays, under its digest and any other tags.
Delete an image
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:
Before you delete the image, read its manifest and note the
config.digestand eachlayers[].digest. If it's an index (a multi-platform image), it lists other manifests undermanifests: read each of those too, and delete them along with the index.shellcurl -s -u "$CAAS_TENANT:$CAAS_API_KEY" \ https://registry.caas.sh/v2/$CAAS_TENANT/agent/manifests/sha256:<digest>Delete the image, as above.
Delete each layer and config that no other image in your namespace uses:
shellcurl -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 see | What to do |
|---|---|
docker login fails with unauthorized | Use 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 refused | Push 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 upload | Keep each layer under about 100 MB. |
429 with TOOMANYREQUESTS | One 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 CLI | Push the tag first, or check its spelling. |
image digest not found in registry.caas.sh | The digest is wrong, or the image was deleted. Copy it again from docker push. |
image must belong to this tenant | The reference names another workspace's namespace. Push the image to yours. |
sandboxes on your own image need size M or larger | Pick M or larger, or a custom size with at least 4 GiB and 8 GB. |