| 1 | # `codewhale-cloud-agent` — Daytona Computer snapshot |
| 2 | |
| 3 | This directory is the product-owned definition of the Daytona snapshot that a |
| 4 | Cloud Agent acquires as its Computer (PRODUCT_PRD §4.5). The Codewhale Engine |
| 5 | is the sole runtime inside the Computer and is installed as a commit- and |
| 6 | digest-pinned Linux binary; nothing else in the image runs agent logic. |
| 7 | |
| 8 | ## What the image is |
| 9 | |
| 10 | - Base: `debian:bookworm-slim` (linux/amd64 — Daytona builds amd64 only). |
| 11 | - Engine: released `codewhale-linux-x64` from GitHub release `v0.9.11`, |
| 12 | fetched by exact URL and verified against the release checksum before |
| 13 | install: |
| 14 | - commit `96d13a0bc3f40280ea3865280ad5ccf0e2845e6f` (tag `v0.9.11`) |
| 15 | - sha256 `c02969556e51e138afa3fe9c97a1359878cd3d1986b1ce1f5fa96c93c6909416` |
| 16 | - static musl build (no glibc floor), installed at `/usr/local/bin/codewhale` |
| 17 | with a `codew` symlink; the build fails if `codewhale --version` does not |
| 18 | print `codewhale 0.9.11 (96d13a0bc3f4)`. |
| 19 | - Toolchain for agent work: git, curl, CA roots, ripgrep, procps, python3 |
| 20 | (+pip, venv), build-essential, pkg-config, jq, unzip, xz-utils, less, |
| 21 | Node.js 22 (NodeSource). No sudo. |
| 22 | - User: non-root `agent` (uid/gid 1000), `HOME=/home/agent`, |
| 23 | `CODEWHALE_HOME=/home/agent/.codewhale`. `/work` and `/workspace` exist and |
| 24 | are owned by `agent`. |
| 25 | - Entrypoint: `sleep infinity` (Daytona injects its own toolbox daemon). |
| 26 | - No provider credentials are baked in. Provider credentials must not be |
| 27 | supplied at sandbox create time. |
| 28 | Daytona create-time environment is server-visible, so a provider secret |
| 29 | must never appear in `daytona create -e …` or an SDK `envVars` payload. |
| 30 | |
| 31 | The pins are recorded as OCI labels (`org.opencontainers.image.revision`, |
| 32 | `net.codewhale.binary.sha256`, ...) so a running Computer can be audited |
| 33 | against the release it claims to run. |
| 34 | |
| 35 | ## Dispatcher wiring and acceptance limits |
| 36 | |
| 37 | The image definition lives only in this directory. The launcher in |
| 38 | `crates/tui/src/cloud_dispatch.rs` selects `codewhale-cloud-agent` (or |
| 39 | `CODEWHALE_DISPATCH_SNAPSHOT`), sends the account machine token in |
| 40 | `CODEWHALE_API_KEY`, applies job labels, and uses the Daytona toolbox to clone |
| 41 | and execute commands. `crates/tui/src/dispatch_runner.rs` drives that lifecycle. |
| 42 | See the [dispatch guide](../../../docs/DAYTONA_CLOUD_DISPATCH.md) for the |
| 43 | command surface. |
| 44 | |
| 45 | This describes source wiring. The image remains pinned to the Engine version |
| 46 | listed above, and this repository does not establish a server-side |
| 47 | account-token-to-provider-credential resolution path. A snapshot build or |
| 48 | manual `codewhale exec` is evidence for that specific operation; it does not |
| 49 | qualify account entitlement, provider credential custody, dispatcher execution, |
| 50 | metering or customer use. The historical manual image receipt below is not |
| 51 | acceptance of the current dispatcher. |
| 52 | |
| 53 | ## Provider credentials inside the Computer |
| 54 | |
| 55 | > **Credential exposure note (verified 2026-08-30).** Daytona persists |
| 56 | > `daytona create -e KEY=VALUE` / SDK `envVars` server-side and returns the |
| 57 | > environment through its API (`GET /sandbox/{id}`). Create-time environment is |
| 58 | > therefore server-visible. Provider secrets must be injected only after the |
| 59 | > Computer is created, through a post-create execution channel from stdin |
| 60 | > (never argv and never create-time environment), then removed at teardown. |
| 61 | > This image and the current dispatcher do not implement that bridge. |
| 62 | > |
| 63 | > `api_key_env` accepts the **name of an environment variable**, not a file |
| 64 | > path or file contents. Do not point it at a `0600` secret file. If a future |
| 65 | > product-owned bridge uses a temporary file, it must separately and explicitly |
| 66 | > map the stdin-delivered secret into the engine process without placing the |
| 67 | > secret in Daytona create-time environment. |
| 68 | > |
| 69 | > The #5712 `CODEWHALE_API_KEY` account/machine-token caveat remains: it is not |
| 70 | > an inference-provider credential and current cloud dispatch does not resolve |
| 71 | > it server-side into one. A machine token alone cannot make this image run a |
| 72 | > provider-backed Engine turn. |
| 73 | |
| 74 | The following are configuration references for a future supported post-create |
| 75 | bridge, not current dispatcher wiring and not permission to use create-time |
| 76 | environment: |
| 77 | |
| 78 | | Provider (config name) | Env var | Example model identifiers | |
| 79 | |----------------------------|----------------------------------------|------------------------------| |
| 80 | | `modelstudio-token-plan` | `MODELSTUDIO_API_KEY` (or `DASHSCOPE_API_KEY`) | `qwen3.8-flash`, `deepseek-v4-pro` | |
| 81 | | `deepseek` | `DEEPSEEK_API_KEY` | `deepseek-v4-pro` | |
| 82 | |
| 83 | `CODEWHALE_PROVIDER` / `CODEWHALE_MODEL` select an Engine route when the Engine |
| 84 | is launched; they do not make the current dispatcher launch this snapshot or |
| 85 | deliver a provider credential. |
| 86 | |
| 87 | ## Build |
| 88 | |
| 89 | `daytona snapshot create` (CLI v0.205.x) has no `--build-arg`, so every pin is |
| 90 | inline in the Dockerfile. Resources are set at snapshot creation and are the |
| 91 | plan maximum: |
| 92 | |
| 93 | ```sh |
| 94 | cd computer/snapshots/cloud-agent |
| 95 | daytona snapshot create codewhale-cloud-agent -f Dockerfile --cpu 4 --memory 8 --disk 10 |
| 96 | ``` |
| 97 | |
| 98 | To roll the engine forward: bump `CODEWHALE_VERSION`, `CODEWHALE_COMMIT`, |
| 99 | `CODEWHALE_ASSET_URL`, `CODEWHALE_ASSET_SHA256`, the `grep -qx` version |
| 100 | assertion, and the OCI labels together, then rebuild under a new snapshot |
| 101 | name (snapshots are immutable once active). |
| 102 | |
| 103 | ## Probe a Computer (manual image evidence only) |
| 104 | |
| 105 | ```sh |
| 106 | daytona create --snapshot codewhale-cloud-agent \ |
| 107 | -l owner=cw-integrator -l lane=cloud-agent-e2e --ttl 30 --auto-delete 0 --name cw-probe |
| 108 | daytona exec cw-probe -- sh -c 'id -u; codewhale --version; git --version; node --version; df -h /; sha256sum /usr/local/bin/codewhale' |
| 109 | daytona delete cw-probe |
| 110 | ``` |
| 111 | |
| 112 | The sha256 printed by the probe must equal the pinned |
| 113 | `c02969556e51e138afa3fe9c97a1359878cd3d1986b1ce1f5fa96c93c6909416`. This is |
| 114 | not product-dispatch or launch acceptance evidence. |
| 115 | |
| 116 | ## Image build and manual probe receipt (2026-08-30; not launch proof) |
| 117 | |
| 118 | Built with the command above; snapshot id `b9275f82-0ead-4855-9707-21859aa186b4`, |
| 119 | state ACTIVE, 0.70 GB, cpu 4 / memory 8 / disk 10. Probe sandbox |
| 120 | (`daytona create --snapshot codewhale-cloud-agent`, labels |
| 121 | `owner=cw-integrator,lane=cloud-agent-e2e`, ttl 30, auto-delete 0) reported: |
| 122 | |
| 123 | ``` |
| 124 | uid=1000 user=agent HOME=/home/agent CODEWHALE_HOME=/home/agent/.codewhale PWD=/work |
| 125 | codewhale 0.9.11 (96d13a0bc3f4) |
| 126 | git version 2.39.5 |
| 127 | v22.23.2 (node) |
| 128 | Python 3.11.2 |
| 129 | ripgrep 13.0.0 |
| 130 | overlay 10G used 24K avail 10G (/ , /work, /workspace) |
| 131 | cpu.max 400000 100000 ; memory.max 8589934592 |
| 132 | c02969556e51e138afa3fe9c97a1359878cd3d1986b1ce1f5fa96c93c6909416 /usr/local/bin/codewhale |
| 133 | /workspace writable ; /work writable |
| 134 | ``` |
| 135 | |
| 136 | This shows only that the Daytona toolbox executed the listed manual commands |
| 137 | as the image `USER` (uid 1000) with the image `ENV` honored. It does not prove |
| 138 | current product dispatcher wiring, provider-secret custody, Engine execution, |
| 139 | or any launch acceptance condition. |
| 140 |