Runners

Runners execute your steps. Managed runners (Linux/OpenBSD) work out of the box; self-hosted runners put builds and deploys on your own machines — the recommended setup when your targets live behind a firewall, since probes and deploys originate from the runner.

Install

Runners → New runner mints a one-time token and shows the install command for each distribution:

  • Script — self-updating (signed, key-pinned), needs Elixir on the host.
  • Binary — self-contained (no runtime needed), systemd unit included.
  • Docker / Helm — container image, or the Helm chart for Kubernetes with optional KEDA scale-to-zero on queue depth.

Isolation

Build steps run isolated by default — hardened docker on Linux (all capabilities dropped, read-only rootfs), vmm on OpenBSD, bhyve on FreeBSD (jails as a lighter opt-in), Tart VMs on macOS, Windows containers on Windows. Self-hosted runners may opt into bare execution per runner; managed runners never run bare.

SSH access

Deploy steps (and target connectivity probes) SSH from the runner using its own keys — the web tier never holds your machine credentials. Add the runner's public key to each target user's ~/.ssh/authorized_keys.

Register runners over the API

Admins can register, change and revoke runners with an API key (GET/POST /api/v1/runners, PUT/DELETE /api/v1/runners/:id, or the runner_* MCP tools). To keep the token on the runner host, generate it there and register only its SHA-256:

TOKEN=ykd_$(head -c 24 /dev/urandom | base64 | tr '+/' '-_' | tr -d '=')
SHA=$(printf '%s' "$TOKEN" | sha256sum | cut -d' ' -f1)
curl -fsS -X POST https://yakdeploy.com/api/v1/runners \
  -H "authorization: Bearer $YAKD_API_KEY" -H 'content-type: application/json' \
  -d "{\"name\":\"build-2\",\"tags\":[\"docker\"],\"token_sha256\":\"$SHA\"}"

Omit token_sha256 and a token is minted and returned once. Every change is in the audit log; revoking a runner that is running a job needs force=true.

Managed builders

Don't want to run build machines? Set builders: managed (or own_then_managed) on a project or a fleet in yakdeploy.yaml and its per-OS fleet builds run on YakDeploy managed builders: one job per builder, a fresh container (Linux) or VM (OpenBSD) and workspace each time, no outbound network except YakDeploy and allowlisted hosts, and a credential that can only upload that one build and dies with the job. Usage is metered in build-minutes per OS (GET /api/v1/managed-builders/usage) against your monthly budget.

Private SSH through YakTunnel

Hosts that should not accept SSH from the internet can be reached through a YakTunnel connector. Link YakTunnel once (PUT /api/v1/tunnels/integration; the management key is write-only), declare a connector on a target and install it:

curl -fsS -X PUT https://yakdeploy.com/api/v1/targets/42/tunnels \
  -H "authorization: Bearer $YAKD_API_KEY" -H 'content-type: application/json' \
  -d '{"ssh_route":"direct_then_tunnel","tunnels":[{"name":"h1-ssh","target":"127.0.0.1:22","grants":["jobs"]}]}'
curl -fsS -X POST https://yakdeploy.com/api/v1/tunnels/7/install -H "authorization: Bearer $YAKD_API_KEY"

YakDeploy creates a private endpoint on YakTunnel and installs the connector with a runbook (systemd or rc.d; its key is written 0600 and never logged). Steps on a tunnel-routed host then get $YAKD_SSH_PROXY_OPT (an OpenSSH ProxyCommand) and a YakTunnel key that works only for that host and only while the step runs. SSH stays end-to-end: the host key is checked against the same pinned known_hosts entry. Runners need the yaktunnel client. In your own scripts, add ${YAKD_SSH_PROXY_OPT:+"$YAKD_SSH_PROXY_OPT"} to ssh.