the universal sandbox runtime for agents and humans. pocketenv.io
sandbox openclaw agent claude-code vercel-sandbox deno-sandbox cloudflare-sandbox atproto sprites daytona
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

Revamp CLI README and rename sshkey command

Bump CLI version to 0.2.0, add eventsource/ws/libsodium-wrappers and
update bun.lock. Remove unused Profile import and adjust command name
from "sshkey" to "sshkeys" in the CLI entrypoint.

+347 -18
+323 -7
apps/cli/README.md
··· 1 1 # Pocketenv CLI 2 2 3 - To install dependencies: 3 + [![npm version](https://img.shields.io/npm/v/@pocketenv/cli?color=green)](https://www.npmjs.com/package/@pocketenv/cli) 4 + [![discord](https://img.shields.io/discord/1270021300240252979?label=discord&logo=discord&color=5865F2)](https://discord.gg/9ada4pFUFS) 5 + [![License: MPL-2.0](https://img.shields.io/badge/License-MPL_2.0-blue.svg)](https://opensource.org/licenses/MPL-2.0) 6 + 7 + The official CLI for [Pocketenv](https://pocketenv.io) — create, manage, and connect to isolated sandboxes from your terminal. Powered by AT Protocol for open, portable, and vendor-agnostic sandbox definitions. 8 + 9 + > [!NOTE] 10 + > **Still in development** 11 + > 12 + > This project is in early development. Expect breaking changes and rapid iteration. 13 + 14 + ## Installation 15 + 16 + ```sh 17 + npm install -g @pocketenv/cli 18 + ``` 19 + 20 + ```sh 21 + pnpm add -g @pocketenv/cli 22 + ``` 23 + 24 + ```sh 25 + bun add -g @pocketenv/cli 26 + ``` 27 + 28 + Verify the installation: 29 + 30 + ```sh 31 + pocketenv --version 32 + ``` 33 + 34 + ## Quick Start 35 + 36 + ```sh 37 + # 1. Log in with your AT Proto account (e.g. Bluesky) 38 + pocketenv login <handle>.bsky.social 39 + 40 + # 2. Create a sandbox 41 + pocketenv create 42 + 43 + # 3. Start it 44 + pocketenv start <sandbox-name> 45 + 46 + # 4. Open an interactive shell inside it 47 + pocketenv console <sandbox-name> 48 + ``` 49 + 50 + ## Authentication 51 + 52 + Pocketenv uses [AT Protocol](https://atproto.com) for authentication. You need an AT Proto account (e.g. a [Bluesky](https://bsky.app) account) to use the CLI. 53 + 54 + ### Login 55 + 56 + ```sh 57 + pocketenv login <handle> 58 + ``` 59 + 60 + Authenticates with your AT Proto handle. A browser window will open for you to authorize the app. Your session token is saved locally at `~/.pocketenv/token.json`. 61 + 62 + **Example:** 63 + 64 + ```sh 65 + pocketenv login alice.bsky.social 66 + ``` 67 + 68 + ### Whoami 69 + 70 + ```sh 71 + pocketenv whoami 72 + ``` 73 + 74 + Displays the currently logged-in user. 75 + 76 + ### Logout 77 + 78 + ```sh 79 + pocketenv logout 80 + ``` 81 + 82 + Removes your local session token. 83 + 84 + --- 85 + 86 + ## Commands 87 + 88 + ### Sandbox Management 89 + 90 + #### `pocketenv create [name]` 91 + 92 + Create a new sandbox. Aliases: `new` 93 + 94 + | Option | Description | 95 + |-----------------------------|---------------------------------------------| 96 + | `--provider, -p <provider>` | The provider to use (default: `cloudflare`) | 4 97 5 - ```bash 6 - bun install 98 + ```sh 99 + pocketenv create my-sandbox 100 + pocketenv create my-sandbox --provider cloudflare 7 101 ``` 8 102 9 - To run: 103 + Supported providers: `cloudflare`, `daytona`, `deno`, `vercel`, `sprites`. 104 + 105 + --- 106 + 107 + #### `pocketenv ls` 10 108 11 - ```bash 12 - bun run index.ts 109 + List all your sandboxes with their status and creation time. 110 + 111 + ```sh 112 + pocketenv ls 13 113 ``` 14 114 15 - This project was created using `bun init` in bun v1.3.10. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime. 115 + Output example: 116 + 117 + ``` 118 + NAME BASE STATUS CREATED AT 119 + true-punter-0nan openclaw RUNNING 33 minutes ago 120 + ruinous-straw-wz8n nix STOPPED 2 days ago 121 + narrative-shift-j80dx zeroclaw STOPPED 11 days ago 122 + mad-ambulance-k9eu nullclaw STOPPED 11 days ago 123 + revered-amateur-n6rz opencrust STOPPED 11 days ago 124 + high-priced-vac-ek73 picoclaw STOPPED 11 days ago 125 + ``` 126 + 127 + --- 128 + 129 + #### `pocketenv start <sandbox>` 130 + 131 + Start a stopped sandbox. 132 + 133 + ```sh 134 + pocketenv start my-sandbox 135 + ``` 136 + 137 + --- 138 + 139 + #### `pocketenv stop <sandbox>` 140 + 141 + Stop a running sandbox. 142 + 143 + ```sh 144 + pocketenv stop my-sandbox 145 + ``` 146 + 147 + --- 148 + 149 + #### `pocketenv rm <sandbox>` 150 + 151 + Delete a sandbox permanently. Aliases: `delete`, `remove` 152 + 153 + ```sh 154 + pocketenv rm my-sandbox 155 + ``` 156 + 157 + --- 158 + 159 + ### Interactive Shell 160 + 161 + #### `pocketenv console [sandbox]` 162 + 163 + Open an interactive shell inside a running sandbox. Aliases: `shell`, `ssh`, `s` 164 + 165 + ```sh 166 + # Connect to a specific sandbox 167 + pocketenv console my-sandbox 168 + 169 + # Omit the name to auto-connect to the first running sandbox 170 + pocketenv console 171 + ``` 172 + 173 + --- 174 + 175 + ### Environment Variables 176 + 177 + Manage environment variables scoped to a sandbox. 178 + 179 + #### `pocketenv env put <sandbox> <key> <value>` 180 + 181 + Set an environment variable. 182 + 183 + ```sh 184 + pocketenv env put my-sandbox DATABASE_URL postgres://localhost/mydb 185 + ``` 186 + 187 + #### `pocketenv env list <sandbox>` 188 + 189 + List all environment variables for a sandbox. Aliases: `ls` 190 + 191 + ```sh 192 + pocketenv env list my-sandbox 193 + pocketenv env ls my-sandbox 194 + ``` 195 + 196 + #### `pocketenv env delete <sandbox> <key>` 197 + 198 + Remove an environment variable. Aliases: `rm`, `remove` 199 + 200 + ```sh 201 + pocketenv env delete my-sandbox DATABASE_URL 202 + ``` 203 + 204 + --- 205 + 206 + ### Secrets 207 + 208 + Manage encrypted secrets scoped to a sandbox. 209 + 210 + #### `pocketenv secret put <sandbox> <key>` 211 + 212 + Store a secret in a sandbox (value is prompted securely). 213 + 214 + ```sh 215 + pocketenv secret put my-sandbox API_KEY 216 + ``` 217 + 218 + #### `pocketenv secret list <sandbox>` 219 + 220 + List all secret keys stored in a sandbox. Aliases: `ls` 221 + 222 + ```sh 223 + pocketenv secret list my-sandbox 224 + ``` 225 + 226 + #### `pocketenv secret delete <sandbox> <key>` 227 + 228 + Delete a secret from a sandbox. Aliases: `rm`, `remove` 229 + 230 + ```sh 231 + pocketenv secret delete my-sandbox API_KEY 232 + ``` 233 + 234 + --- 235 + 236 + ### SSH Keys 237 + 238 + Manage SSH keys associated with a sandbox. 239 + 240 + #### `pocketenv sshkeys put <sandbox>` 241 + 242 + Upload an SSH key pair to a sandbox. 243 + 244 + | Option | Description | 245 + |-----------------|-----------------------------| 246 + | `--private-key` | Path to the SSH private key | 247 + | `--public-key` | Path to the SSH public key | 248 + 249 + ```sh 250 + pocketenv sshkeys put my-sandbox 251 + ``` 252 + 253 + #### `pocketenv sshkeys get <sandbox>` 254 + 255 + Retrieve the public SSH key from a sandbox. 256 + 257 + ```sh 258 + pocketenv sshkeys get my-sandbox 259 + ``` 260 + 261 + --- 262 + 263 + ### Tailscale 264 + 265 + Manage Tailscale integration for your sandboxes. 266 + 267 + #### `pocketenv tailscale put <sandbox>` 268 + 269 + Store a Tailscale auth key in a sandbox. 270 + 271 + ```sh 272 + pocketenv tailscale put my-sandbox 273 + ``` 274 + 275 + #### `pocketenv tailscale get <sandbox>` 276 + 277 + Retrieve the stored Tailscale auth key (redacted) from a sandbox. 278 + 279 + ```sh 280 + pocketenv tailscale get my-sandbox 281 + ``` 282 + 283 + --- 284 + 285 + ## Environment Variables 286 + 287 + The CLI can be configured via the following environment variables: 288 + 289 + | Variable | Default | Description | 290 + |---------------------|----------------------------|-----------------------------------------------| 291 + | `POCKETENV_TOKEN` | _(none)_ | Override the session token (useful for CI/CD) | 292 + | `POCKETENV_API_URL` | `https://api.pocketenv.io` | Override the API base URL | 293 + | `POCKETENV_CF_URL` | `https://sbx.pocketenv.io` | Override the Cloudflare sandbox URL | 294 + | `POCKETENV_TTY_URL` | `https://api.pocketenv.io` | Override the TTY URL | 295 + 296 + **Example — using a token in CI:** 297 + 298 + ```sh 299 + POCKETENV_TOKEN=<your-token> pocketenv ls 300 + ``` 301 + 302 + --- 303 + 304 + ## Use Cases 305 + 306 + - Run AI agents (Codex, Claude, Gemini, OpenClaw, Copilot ...) safely in isolated environments 307 + - Spin up ephemeral dev sandboxes for quick prototyping 308 + - Share reproducible developer environments via AT Protocol 309 + - Test untrusted or third-party code securely 310 + - Provide sandbox infrastructure as a service 311 + 312 + --- 313 + 314 + ## Documentation 315 + 316 + Full documentation is available at **[docs.pocketenv.io](https://docs.pocketenv.io)**. 317 + 318 + --- 319 + 320 + ## Contributing 321 + 322 + Contributions are welcome! Please read the [Contributing Guidelines](https://github.com/pocketenv-io/pocketenv/blob/main/CONTRIBUTING.md) before submitting a pull request. 323 + 324 + - **Bug reports & feature requests:** [Open an issue](https://github.com/pocketenv-io/pocketenv/issues/new) 325 + - **Community & feedback:** [Join our Discord](https://discord.gg/9ada4pFUFS) 326 + 327 + --- 328 + 329 + ## License 330 + 331 + [Mozilla Public License 2.0](https://github.com/pocketenv-io/pocketenv/blob/main/LICENSE)
+19 -5
apps/cli/bun.lock
··· 15 15 "dayjs": "^1.11.20", 16 16 "effect": "^3.19.19", 17 17 "envalid": "^8.1.1", 18 + "eventsource": "^4.1.0", 18 19 "express": "^5.2.1", 19 - "node-pty": "^1.1.0", 20 + "libsodium-wrappers": "^0.8.2", 20 21 "open": "^11.0.0", 22 + "ws": "^8.19.0", 21 23 "zod": "^4.3.6", 22 24 }, 23 25 "devDependencies": { 24 26 "@types/cors": "^2.8.19", 27 + "@types/eventsource": "^1.1.15", 25 28 "@types/express": "^5.0.6", 29 + "@types/ws": "^8.18.1", 26 30 "pkgroll": "^2.27.0", 27 31 "tsx": "^4.21.0", 28 32 }, ··· 198 202 199 203 "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], 200 204 205 + "@types/eventsource": ["@types/eventsource@1.1.15", "", {}, "sha512-XQmGcbnxUNa06HR3VBVkc9+A2Vpi9ZyLJcdS5dwaQQ/4ZMWFO+5c90FnMUpbtMZwB/FChoYHwuVg8TvkECacTA=="], 206 + 201 207 "@types/express": ["@types/express@5.0.6", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", "@types/serve-static": "^2" } }, "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA=="], 202 208 203 209 "@types/express-serve-static-core": ["@types/express-serve-static-core@5.1.1", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A=="], ··· 215 221 "@types/send": ["@types/send@1.2.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ=="], 216 222 217 223 "@types/serve-static": ["@types/serve-static@2.2.0", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*" } }, "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ=="], 224 + 225 + "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], 218 226 219 227 "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], 220 228 ··· 310 318 311 319 "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], 312 320 321 + "eventsource": ["eventsource@4.1.0", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-2GuF51iuHX6A9xdTccMTsNb7VO0lHZihApxhvQzJB5A03DvHDd2FQepodbMaztPBmBcE/ox7o2gqaxGhYB9LhQ=="], 322 + 323 + "eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="], 324 + 313 325 "express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], 314 326 315 327 "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="], ··· 389 401 "is-reference": ["is-reference@1.2.1", "", { "dependencies": { "@types/estree": "*" } }, "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ=="], 390 402 391 403 "is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="], 404 + 405 + "libsodium": ["libsodium@0.8.2", "", {}, "sha512-TsnGYMoZtpweT+kR+lOv5TVsnJ/9U0FZOsLFzFOMWmxqOAYXjX3fsrPAW+i1LthgDKXJnI9A8dWEanT1tnJKIw=="], 406 + 407 + "libsodium-wrappers": ["libsodium-wrappers@0.8.2", "", { "dependencies": { "libsodium": "^0.8.0" } }, "sha512-VFLmfxkxo+U9q60tjcnSomQBRx2UzlRjKWJqvB4K1pUqsMQg4cu3QXA2nrcsj9A1qRsnJBbi2Ozx1hsiDoCkhw=="], 392 408 393 409 "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], 394 410 ··· 412 428 413 429 "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], 414 430 415 - "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], 416 - 417 - "node-pty": ["node-pty@1.1.0", "", { "dependencies": { "node-addon-api": "^7.1.0" } }, "sha512-20JqtutY6JPXTUnL0ij1uad7Qe1baT46lyolh2sSENDd4sTzKZ4nmAFkeAARDKwmlLjPx6XKRlwRUxwjOy+lUg=="], 418 - 419 431 "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], 420 432 421 433 "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], ··· 515 527 "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], 516 528 517 529 "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], 530 + 531 + "ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], 518 532 519 533 "wsl-utils": ["wsl-utils@0.3.1", "", { "dependencies": { "is-wsl": "^3.1.0", "powershell-utils": "^0.1.0" } }, "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg=="], 520 534
+2 -2
apps/cli/package.json
··· 4 4 "bin": { 5 5 "pocketenv": "dist/index.js" 6 6 }, 7 - "version": "0.1.0", 7 + "version": "0.2.0", 8 8 "type": "module", 9 9 "keywords": [ 10 10 "sandbox", ··· 44 44 "envalid": "^8.1.1", 45 45 "eventsource": "^4.1.0", 46 46 "express": "^5.2.1", 47 - "node-pty": "^1.1.0", 47 + "libsodium-wrappers": "^0.8.2", 48 48 "open": "^11.0.0", 49 49 "ws": "^8.19.0", 50 50 "zod": "^4.3.6"
-1
apps/cli/src/cmd/ssh/cloudflare.ts
··· 5 5 import { client } from "../../client"; 6 6 import { env } from "../../lib/env"; 7 7 import type { Sandbox } from "../../types/sandbox"; 8 - import type { Profile } from "../../types/profile"; 9 8 10 9 // ── Protocol (mirrors @cloudflare/sandbox xterm addon) ─────────────────────── 11 10 //
+3 -3
apps/cli/src/index.ts
··· 150 150 .description("delete an environment variable from the given sandbox") 151 151 .action(deleteEnv); 152 152 153 - const sshkey = program.command("sshkey").description("manage SSH keys"); 153 + const sshkeys = program.command("sshkeys").description("manage SSH keys"); 154 154 155 - sshkey 155 + sshkeys 156 156 .command("put") 157 157 .argument("<sandbox>", "the sandbox to put the SSH key in") 158 158 .option("--private-key", "the path to the SSH private key") ··· 160 160 .description("put an SSH key in the given sandbox") 161 161 .action(putKeys); 162 162 163 - sshkey 163 + sshkeys 164 164 .command("get") 165 165 .argument("<sandbox>", "the sandbox to get the SSH key from") 166 166 .description("get an SSH key (public key only) from the given sandbox")