Search docs

Search the Beamd documentation

Embed in your app

Bundle the beamd binary into a host app, drive it with a dedicated config, and reconcile tunnels on startup.

This is for building Beamd into a host app — for example an AI task manager that exposes each agent's dev server for remote review. You bundle the binary, point it at your edge with a dedicated config, and manage the bring-up / tear-down lifecycle yourself.

Mental model

  • One edge runs on a public box and owns a domain.
  • Your app machine runs the client: beamd open <port> -d hands a tunnel to a background agent that holds it and returns immediately.
  • Your app is the source of truth for what should be exposed. The agent doesn't persist registrations across reboots — on startup, re-open what you want (cheap and idempotent).

1. Bundle the binary

Add Beamd as a dependency — npm installs only the host-platform binary (~4 MB):

npm i @beamd/cli

Spawn it via the package bin (node_modules/.bin/beamd) or require.resolve("@beamd/cli/bin/beamd.cjs"). Everything below is just beamd <args>.

2. Configure with --config

Pass a dedicated config file to every command. It bypasses Beamd's account store entirely, so your app keeps its own {server, token} out of the user's $HOME and never collides with their interactive beamd accounts. The token is a workspace API key (hosted) or an operator-issued token (self-host):

# my-app-beamd.yaml — referenced via --config my-app-beamd.yaml
server: tunnel.example.com:443
token: <workspace API key>
agent_socket: /path/to/your-app/beamd-agent.sock   # pin a dedicated socket
# insecure_skip_verify: true   # ONLY for a self-signed dev edge

Pin a dedicated agent_socket. The agent is keyed by its socket path. Without one, your app shares the default socket with the user's own beamd, and an agent already running there keeps serving its original credentials even after you change server / token. A per-app socket isolates you — and if you rotate creds, run beamd reload --config <path> to restart the agent with them.

3. Bring a tunnel up (detached + JSON)

beamd open 3000 --as my-app -d --json
# { "url": "https://my-app.<base>", "name": "my-app", "port": 3000, "slug": "", "baseDomain": "<base>" }

-d detaches; --json prints exactly one object. Parse url, embed or open it — and always trust url rather than assembling the host (it's correct whether the edge is flat or namespaced).

4. Tear down

beamd close my-app --json    # { "name": "my-app", "removed": true|false }

Idempotent: exit 0 whether or not it existed. Never spawns an agent.

5. Reconcile on startup

After a reboot the agent isn't running and holds nothing. Reconcile against your own desired state:

beamd status --json   # { "agentRunning": bool, "server": ..., "slug": ..., "scope": ..., "healthy": bool }
beamd list --json     # [ { "name", "url", "port", "healthy" }, … ]

For anything you want exposed that isn't listed, beamd open … -d again (the first detached open spawns the agent automatically).

Two constraints to design around

  • Names are one label. --as <name> must be a single RFC 1123 label — encode structure with hyphens, not dots (proj-ab12-api, not a.b). See Naming.
  • There's a tunnel cap. The edge caps concurrent tunnels per token (max_tunnels_per_token, default 25). If you expose many short-lived previews, close the ones you no longer need.

For the raw socket contract under these commands, see Agent local API.