@cameronpak/box
Full Box Public API v1 client: lifecycle, prompts, files, commands, snapshots, environments, webhooks, desktop, hosting, and account.
- Other
- box
- ascii
- sandbox
- vm
- code-execution
- Version
- 1.0.0
- License
- MIT
- Published
- August 21, 2026
- Pinned commit
47e14cf- Rating
- No ratings yet
- Forks
- 2
- Adaptation effort
- —
README
@cameronpak/box
Full client for the Box Public API v1 at https://ascii.dev/api/box/v1.
Intent
This package exists so agents can run and build code in a Box cloud sandbox from Kody, without hand-writing fetch calls each time.
Success means:
- Create a box, wait for it to be ready, and run shell commands in it.
- Write source files into the box and build or test them.
- Read results back out.
- Stop, resume, or fork a box to control cost and reuse state.
- Cover every documented Box Public API v1 endpoint as a named export.
Prompting Codex or Claude Code inside the box is included, but it is secondary. Command execution is the primary surface.
Auth
Every call sends the user secret boxApiKey as a bearer token. The host
ascii.dev must be approved in the Kody account security UI.
PATCH /account/data-retention is the documented exception: it requires an
interactive Box session and refuses API keys (403 session_required). The
update-data-retention export still exists and will return that error for a
normal service key.
Error handling
Every export returns a Result:
type Result<T> = { ok: true; data: T } | { ok: false; error: BoxError }BoxError carries code, message, status, and requestId when the API
supplies one. No export throws on an API error.
Secrets
Treat Box API keys, returned desktop/VNC URLs, hosted _token URLs, webhook
signing secrets, and snapshot download signedUrl values as secrets. Do not
log or persist them unredacted.
Usage
import { createBox, waitForBox, runCommand, stopBox } from 'kody:@cameronpak/box'
const created = await createBox({ ttlSeconds: 3600 })
if (!created.ok) throw new Error(created.error.message)
const boxId = created.data.box.id
await waitForBox({ boxId })
const result = await runCommand({ boxId, command: 'node --version' })
await stopBox({ boxId })Exports
Account
get-me—GET /meget-limits—GET /limitsget-data-retention—GET /account/data-retentionupdate-data-retention—PATCH /account/data-retention(session required)get-deletion-operation—GET /deletion-operations/{operationId}list-repos—GET /reposselect-repo—POST /reposlist-api-keys—GET /api-keysget-secrets—GET /secretsupdate-secrets—POST /secrets(full replacement)
Webhooks
list-webhooks—GET /webhookscreate-webhook—POST /webhooksget-webhook—GET /webhooks/{webhookId}update-webhook—PATCH /webhooks/{webhookId}delete-webhook—DELETE /webhooks/{webhookId}rotate-webhook-secret—POST /webhooks/{webhookId}/rotate
Environments
list-environments—GET /environmentscreate-environment—POST /environmentsupdate-environment—PUT /environments/{environmentId}delete-environment—DELETE /environments/{environmentId}upgrade-environment—POST /environments/{environmentId}/upgradeset-environment-var—PUT /environments/{environmentId}/vars/{key}delete-environment-var—DELETE /environments/{environmentId}/vars/{key}set-environment-secret-file—PUT /environments/{environmentId}/secret-filesdelete-environment-secret-file—DELETE /environments/{environmentId}/secret-filesadd-environment-repo—POST /environments/{environmentId}/reposdelete-environment-repo—DELETE /environments/{environmentId}/repos/{repositoryId}
Boxes
list-boxes—GET /boxescreate-box—POST /boxesget-box—GET /boxes/{boxId}update-box—PATCH /boxes/{boxId}delete-box—DELETE /boxes/{boxId}(X-Ascii-Confirm-Delete, 202)stop-box—POST /boxes/{boxId}/stopresume-box—POST /boxes/{boxId}/resumefork-box—POST /boxes/{boxId}/forkwait-for-box— poll helper aroundget-box
Agent / I/O
prompt-box—POST /boxes/{boxId}/promptget-prompt-run—GET /boxes/{boxId}/prompts/{promptId}list-events—GET /boxes/{boxId}/eventsread-file—GET /boxes/{boxId}/fileswrite-file—PUT /boxes/{boxId}/filesrun-command—POST /boxes/{boxId}/commandsget-command-status—GET /boxes/{boxId}/commands/{processId}run-code— write-file then run-command conveniencedownload-artifact—GET /boxes/{boxId}/artifactsinterrupt-box—POST /boxes/{boxId}/interruptget-desktop-url—POST /boxes/{boxId}/desktopconfigure-ssh-key—POST /boxes/{boxId}/sshkeyhost-port—POST /boxes/{boxId}/host
Snapshots
list-snapshots—GET /snapshotslist-box-snapshots—GET /boxes/{boxId}/snapshotsget-latest-box-snapshot—GET /boxes/{boxId}/snapshots/latestget-snapshot-tree—GET /snapshots/{snapshotId}/treeget-snapshot-file—GET /snapshots/{snapshotId}/filesget-snapshot-download—GET /snapshots/{snapshotId}/downloaddelete-snapshot—DELETE /snapshots/{snapshotId}(X-Ascii-Confirm-Delete, 202)list-named-snapshots—GET /named-snapshotssave-named-snapshot—POST /named-snapshotsget-named-snapshot—GET /named-snapshots/{name}delete-named-snapshot—DELETE /named-snapshots/{name}
Limits worth knowing
runCommandacceptstimeoutSecondsfrom 1 to 600. The API rejects values outside that range. Usedetached: trueplusgetCommandStatusfor longer work.- Kody's
executehas a hard timeout near 90 seconds. Long builds belong in a workflow, or in a prompt run observed throughlistEvents. promptBoxneeds Codex or Claude Code credentials configured in the Box dashboard. Without them the API returnsprovider_not_configured.idleandrunningreflect prompt work only. A box staysidlewhile your own command runs.- Binary downloads (
download-artifact,get-snapshot-file) are returned as base64BinaryPayloadobjects. - Permanent delete cannot be canceled. Poll
get-deletion-operationuntilcompleted.
Report this listing
Log in to report this listing.