Manifest (meta)
Every workflow exports a meta literal. Boardwalk derives the workflow's manifest from it at deploy time without executing your code, so meta must be a pure literal: no computed values, no inlined imports. The schema is strict: an unknown field is a validation error (boardwalk check catches it before deploy), so it can never silently drift.
export const meta = {
slug: "morning-digest",
title: "Morning Digest",
description: "Summarize open issues every weekday at 9am.",
triggers: [{ kind: "cron", expr: "0 9 * * 1-5", timezone: "America/New_York" }],
permissions: { secrets: [{ name: "GITHUB_TOKEN" }] },
budget: { max_usd: 1 },
};Fields
| Field | Required | What it declares |
|---|---|---|
slug | yes | The workflow's identity: lowercase letters, digits, and hyphens, stable across versions. |
title | no | A human-readable display label for the dashboard. |
description | no | One line for the dashboard and your teammates. |
triggers | yes | At least one trigger: manual, cron, or webhook. See Triggers. |
env | no | Environment variables for the run. Values are plaintext or a whole-value secret reference, ${{ secrets.NAME }}. |
input_schema | no | JSON Schema validating the trigger payload. |
output_schema | no | JSON Schema validating the value passed to output(). |
workspace | no | { persist: true }(or a list of directories) keeps the run's working directory between runs; omitted, it's scratch. |
budget | no | Caps that fail the run when breached (never silent truncation). See below. |
concurrency | no | How many runs of this workflow may run at once. Default: unlimited. See below. |
runs_on | no | The machine. Default boardwalk/linux. See Runners. |
notifications | no | Email or webhook on completion, failure, cancelled, or budget_exceeded. |
permissions | no | What a run may do: its API token scope, OIDC, artifacts, and the secret allowlist. See below. |
callable_by | no | Who may invoke this workflow (e.g. other workflows in the org). Default: anyone in the org. |
egress | no | Outbound network policy on hosted runners: none, trusted, full, or a custom host allowlist. |
container | no | A custom OCI image to run the workflow's tools inside (hosted). |
runs_on
Almost every workflow uses the default, boardwalk/linux: a Linux machine with Node, Python, git, and common CLIs preinstalled. For more CPU and memory, ask for a larger machine:
runs_on: "boardwalk/linux-large",
// or, equivalently, with an explicit size:
runs_on: { label: "boardwalk/linux", size: "large" },budget
Any cap that's exceeded ends the run with a budget error. All three are optional:
budget: {
max_usd: 5, // stop if the run's inference cost passes $5
max_tokens: 2_000_000, // ...or this many tokens
max_duration_seconds: 3600, // ...or this long
},concurrency
By default runs overlap freely. Serialize them when a workflow mutates shared state, either globally or per key (so one user, repo, or tenant runs one at a time):
concurrency: { mode: "serial" },
// or keyed:
concurrency: { mode: "serial_by_key", key: "repo" },permissions
A run executes with a least-privilege token. permissions raises or lowers what it can do, modeled on GitHub Actions:
permissions: {
contents: "read", // the run's API token: "read" (default), "write", or "none"
artifacts: "write", // read/write/none for run artifacts
id_token: "write", // mint an OIDC token (for cloud federation)
secrets: [{ name: "GITHUB_TOKEN" }], // allowlist of names the program may secrets.get()
},permissions.secrets is the allowlist of secret names the program may secrets.get(): see Secrets. The injected token is always ceilinged below admin, so a workflow can never escalate past member-level access to your org.