# agent Always-on credentials refresher, hosted by the single binary as `drm agent`. ```text apps/agent/ agentcmd/ the command body, imported by apps/cli internal/ poller, durable queue, device pool, worker, ws client agent.yaml config ``` ## What it does 1. Polls streamd (`GET /api/streams`) 2. When an **enabled** stream is down/errored or missing `mpd`/`key`, enqueues a job in a durable SQLite queue under `data_dir` 3. Claims a free ADB device that **already has** the app installed — it never installs 4. Runs a phone capture through the stream's app module 5. `POST /api/streams/:id/credentials` 6. Force-stops the app and clears the device proxy so the phone is free It never runs a downloader. Claims are kept alive by a websocket heartbeat, so they expire by themselves if the agent dies. ## Run ```bash # terminal 1 — control plane ./bin/drm serve --bind 127.0.0.1:8083 --data .cache/streamd --token SECRET # terminal 2 — agent export STREAMD_TOKEN=SECRET ./bin/drm agent run --config apps/agent/agent.yaml ``` ```bash ./bin/drm agent status ./bin/drm agent devices ./bin/drm agent enqueue --stream tg4-ioi --reason manual ./bin/drm agent cancel --job 3 ``` App modules are compiled into the binary, so there is no `modules_dir` to set. The agent drives whichever module a stream names and contains no provider logic. ## Config `agent.yaml` — `streamd_url`, `token` (or `STREAMD_TOKEN`), `poll_interval_sec`, `workers`, `max_attempts`, `capture_wait_sec`, `devices` (empty = any authorised device), `wvd`, `user_agent`, `agent_id`, `data_dir`. `wvd` must be set or key fetches fail. ## Build ```bash go -C apps/cli build -o ../../bin/drm . # cross-compile GOOS=darwin GOARCH=arm64 go -C apps/cli build -o ../../bin/drm . ``` **Full guide: [docs/streamd.md](../../docs/streamd.md)**