Vibes DIY
Vibes DIY / Docs
creator docs · pattern

The CI lane with a device cert

The problem: some work can't run in a vibe's backend — codegen, heavy builds, anything needing a real container. You want CI to participate in your app's workflow without scattering API tokens through GitHub secrets.

The pattern: enroll a dedicated device for your account, hand its certificate to the runner, and let it speak the same CLI you do.

Enroll the device

vibes-diy login enrolls the current machine with a device certificate — that's the credential the CLI uses everywhere. For CI, enroll once locally, then export the keybag item it wrote (the device's private key + signed cert, not just an id) into the runner's environment:

shnpx vibes-diy login          # browser flow; enrolls this device
# The enrollment lands in ~/.fireproof/keybag/<id>.json. Copy that file's
# contents into a CI secret — base64 avoids JSON quoting trouble:
base64 -w0 ~/.fireproof/keybag/<id>.json   # -> secret BUILDER_DEVICE_ID
yaml# .github/workflows/your-lane.yaml
env:
  VIBES_DEVICE_ID: ${{ secrets.BUILDER_DEVICE_ID }}

VIBES_DEVICE_ID accepts the keybag JSON raw or base64-encoded (the full file or its bare { deviceId, cert } item), and an interactive login already on the machine always wins over it. With it set, every CLI command runs headless as your account — no browser, no prompt:

shnpx vibes-diy db query --vibe you/your-hub --db requests   # pick up work
npx vibes-diy db put   --vibe you/your-hub --db requests '…' # report back
npx vibes-diy generate "the requested app" --handle yourbot --app-slug m-abc123

Why a cert and not a token

The device cert is a builder identity, not a capability grab-bag. It authenticates as your account, so it passes exactly the gates your access.js already defines — there's no second permission system to design, and revoking it is deleting the device. Meanwhile the dangerous credentials (social tokens, API keys) stay in the vibe's write-only vault: the two lanes coordinate entirely through status documents and never share a secret. If the runner is compromised, the attacker gets a revocable builder cert — not your Bluesky password.

In production

The platform's mention-builds pipeline is this exact split: mention-builds.yaml runs on a cron, and scripts/mention-builds.mjs drives the public CLI — the same one you just installed — to pick up pending-build docs, generate each requested app, verify it actually serves, and write the result back. (It stores the keybag under its own secret name, MENTION_BUILDER_DEVICE_ID, and exports it as VIBES_DEVICE_ID at runtime — the env var name is what the CLI reads; the secret name is yours to choose.) The workflow self-skips until its secrets exist, so the lane is dark by default.

Anything that can run a shell can join your app's workflow this way: a laptop cron, a Raspberry Pi, another CI system. And when the "script" is an AI agent, skip the shell parsing entirely — npx vibes-diy mcp exposes the same list/get/put/query/delete surface as an MCP server any agent can mount.