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. Each one is set once with a scope (private, shared or all), injected into the machines in that scope, and never appears in the script. That matters because the console’s generated write-up is built from the script’s source. 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. For scopes, see Env vars and secrets.

Reaching things

Example: nightly report from Postgres to Slack

nightly-report.run.ts

Example: react to a GitHub deploy by rolling a cluster

rollout.run.ts

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

invoice-sync.run.ts
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.