Secrets

Secrets and environment variables are the entire credential story: there are no per-service connect flows to manage. Declare a name, fetch it in code, and the engine worries about where the value lives.

Declare, then get

export const meta = {
  slug: "morning-digest",
  title: "Morning Digest",
  triggers: [{ kind: "cron", expr: "0 9 * * 1-5" }],
  permissions: { secrets: [{ name: "GITHUB_TOKEN" }] },
};

const token = await secrets.get("GITHUB_TOKEN");

The declaration is an allowlist: secrets.get() on an undeclared name fails, and so does a run whose declared secret is missing, with an error that says exactly what to set. Fail-closed, both ways.

Where secrets resolve from

  • boardwalk dev: your project's .env file (override with --env). Nothing leaves your machine.
  • Boardwalk:the org's secrets vault, managed in the dashboard (Settings → Secrets). Values are encrypted at rest and released to a run only for the names its manifest declares.
  • Self-hosted:the server's environment. Your hardware, your values.

The program code is identical in all three.

The redaction guarantee

Secret values live only in your deterministic code; they are redacted from everything the model sees: prompts, tool arguments, tool results, the transcript. Fetch with the token, then hand the model the data, never the credential. Because the model can't see a secret, prompt injection can't exfiltrate one.

Secrets in env vars

env: {
  NPM_TOKEN: "${{ secrets.NPM_TOKEN }}",
},

When a subprocess needs a credential (a CLI you shell out to, for instance), meta.env may reference a declared secret. The reference must be the whole value, exactly as above; partial interpolation inside a longer string is not supported.