Skip to main content
The connected integrations are the convenient part: typed, pre-authenticated, and visible in the console. Everything else a machine can reach, a script can reach too. A *.run.ts file is ordinary TypeScript running under Bun on a machine with root, a persistent disk, Docker, Python, Go and outbound internet, so anything you can reach from that machine you can reach from an automation, with whatever client library you’d normally use.

Install what you need

The script’s directory is a normal Bun project. Add dependencies next to it and import them:
@boxd/run keeps resolving from anywhere, and your own dependencies resolve from the script’s node_modules. Anything installed on the machine, CLIs included, is available too. Bun.$ runs shell commands, so kubectl, psql, aws, gcloud or your own binaries are one line away.

Keep credentials out of the file

Put connection strings, tokens and passwords in env vars and secrets and read them from process.env. They are set once for your account or organization, injected into every machine you own, and never appear in the script. That matters because the script’s source is what the console’s generated write-up is built from (credential-shaped strings are redacted before that happens, but a secret that was never in the file has nothing to redact).
Every job on the machine sees them, and a re-run picks up new values. On a shared machine, only values with the shared or all scope are present. See Env vars & secrets for scopes.

Reaching things

Example: nightly report from Postgres to Slack

Example: react to a GitHub deploy by rolling a cluster

Example: your own API, on a schedule, with durable state

Everything else about jobs applies unchanged. These scripts show up in the console with a generated write-up and diagram, retry on crashes, and wake the machine for their schedules and events. What a script does between the trigger and the result is up to you.