Skip to content
This text was generated by an LLM (how cgwalters uses LLMs). cgwalters has not reviewed it yet.

Setup

From installing the binary to a deployment that dispatches agent jobs from a board. Bring a deployment up one lane at a time, with writes and scheduling off until their previews and prerequisites are checked: a working offline rehearsal does not establish a scheduled real-agent and review loop. The steps below use GitHub; see forges for Forgejo and GitLab.

Install

agent-board needs Rust supporting edition 2024. There are no prebuilt releases, and it is not installable with gh extension install.

Terminal window
cargo install --locked --git https://github.com/cgwalters-forge/agent-board agent-board

The binary is also built as gh-agent-board. Output follows gh: --json, --jq and gh's exit codes. Live HTTPS requests use the platform trust store through rustls-platform-verifier, not bundled Mozilla roots, so install a sandbox egress proxy's or corporate CA certificate in the system trust store; certificate and hostname verification stay on.

Try it offline

The sample board is in the repository, so clone it (git clone https://github.com/cgwalters-forge/agent-board) and, from its root, with no token:

Terminal window
agent-board item list --snapshot fixtures/board.json
agent-board reconcile plan --snapshot fixtures/board.json --emit
agent-board project view --snapshot fixtures/board.json --json project,coverage

All three should exit 0 without GH_TOKEN or GITHUB_TOKEN. The fixture is sample data: listing it proves the CLI works, the plan is a proposal rather than a write, and coverage describes which facts the snapshot contains. It does not prove live token access, dispatch, inference, review or container isolation. The offline CLI test runs these commands, so this starting point stays reproducible. Every command and flag is in the CLI reference.

Connect one lane

A deployment is configuration on a caller repository's protected default branch plus workflow callers, each of which builds agent-board at a pinned, reviewed revision and runs one subcommand. No agent-board code is copied into the caller or resynced from another deployment. Two steps below still copy workflow files from elsewhere, the dispatch caller (step 2) and the review caller (step 4); each says so.

  1. Choose the identities. A target repository, a trusted caller repository that holds the dispatch workflow, its bounds, agent-board's configuration and the callers, and an existing organization Project v2. Each is a separate identity; none is provisioned for you by an existing deployment.

  2. Prove model-free dispatch first. This step still copies a workflow: the caller needs its own dispatch workflow, which calls a reusable agentic-job workflow (directly, or through an organization wrapper), with its bounds and the profile of each kind beside it. Follow agentic-job's ten-minute scripted trial: copy its dispatch workflow and bounds into the caller, pin the reusable workflow to a reviewed commit, set exact repos and keep bases = ["main"]. Commit to the protected default branch, allow the actions, then dispatch kind=research against an existing issue. Implement runs also need the apply environment and its token. Bounds protect documentation too: list the intended documentation files in unprotected_files rather than unprotecting the repository. The workflow must take the inputs and set the run title agent-board expects (dispatch).

  3. Provision inference and network before selecting a real agent. Follow agentic-job's Switch to a real agent and broker admission, matching admission to the identity that calls the broker.

  4. Install review independently. This step also still copies a workflow: each reviewed repository needs its own review caller and its bounds and task files. Follow agentic-job's review Another repository and Configuration; actions#129 plans one organization-wide review workflow instead. Choose merge policy separately: an agent verdict is not human authorization.

  5. Provision and read the board before writes. Pre-create the Status options Triage, Backlog, Todo, In Progress, Draft, In Review, Blocked, Needs human, Done and Cancelled, and the Priority single-select with P0, P1 and P2 (durable model; Status is derived by the pass, see architecture). project init creates only missing Turn, Run and Result fields, with the operator's token, and never edits existing fields or options; project init --snapshot FILE instead prints copyable gh project field-create commands on stderr without running them. For asks, provision the question and needs-human labels and an assignable operator. Start with snapshot create and reconcile plan previews. Live writes need a token with organization Projects read and write and repository Issues write, with organization approval and the token owner's access to the project; workflow permissions and GITHUB_TOKEN do not grant organization Projects writes. The live template shows a protected staging test.

  6. Preview a plan, then wire scheduling deliberately. Use job-plan dispatch, starting with dispatch ISSUE --dry-run; apply needs a writer's user token and records the plan before dispatching. Write the callers' configuration on the caller's protected default branch: owner and project, exact repository lists, the dispatch caller and the identities, never from dispatcher-set inputs. Every option ships off; pull request follow-up and the pass configuration list them. Add the callers one at a time, each previewing before it applies. Audit dispatch and fix bounds and pools before enabling a scheduled applier, and never run two appliers against one board.

Operator-only work, which no agent and no guide can do: authorize the network identity and its ACLs, admit the specific repository and workflow identities and finite budgets at the broker, keep model credentials only at the broker, and provision the protected apply, reconcile and live-test secrets with effective Projects access.

Pinned callers

Each caller is a scheduled or dispatched workflow in the caller repository. It checks out the caller's default branch for its configuration, builds agent-board at a full commit reviewed in the caller repository (never a branch, since the binary then runs with a write token; the build step itself gets no token), and runs one subcommand, for example:

Terminal window
[[ $AGENT_BOARD_REV =~ ^[0-9a-f]{40}$ ]]
cargo install --locked --root "$RUNNER_TEMP/agent-board" \
--git https://github.com/cgwalters-forge/agent-board --rev "$AGENT_BOARD_REV" agent-board
"$RUNNER_TEMP/agent-board/bin/agent-board" pass --config CONFIG

Moving a caller to a newer agent-board is a reviewed edit of its pinned revision. Configuration is read only from files on the default branch; a caller may add a value from a repository variable, such as the broker's address, before passing the file on. The caller workflows themselves are written per deployment: copying another deployment's means replacing its names, secrets and defaults, and resyncing the steps around each subcommand by hand.

Example caller, not a requirement: cgwalters-forge/tracker at bb8363a. The paths and file names are that deployment's. tracker#890 plans to move the deployment to cgwalters-forge/infra, so the caller repository may change.

  • poll.yml, every ten minutes: agent-board pass --config .github/pass.json (pass) with --max-dispatch, --max-writes and --max-status-changes caps; a scheduled pass adds --apply only once a repository variable enables it.
  • release-train.yml, hourly: agent-board release-train --config .github/release-train/config.json (release train), off until a repository variable enables it.
  • supervisor.yml, on its own crons, by dispatch and on the operator's comments on its requests issue, with this deployment's defaults for the operator and that issue: agent-board supervise due, health, repeat, trigger, compose, preview and execute (supervisor), reading .github/poll/agent-board.json, .github/supervisor/config.json, .github/usage/config.json and .github/agentic-job/pools.json; its agent job runs the dispatch wrapper with .github/agentic-job/supervisor.toml.
  • session.yml, by dispatch: agent-board supervise session, reading .github/poll/agent-board.json, .github/supervisor/config.json, .github/agentic-job/session.json, .github/agentic-job/profiles/session.md and .github/agentic-job/pools.json; its agent job runs the dispatch wrapper with .github/agentic-job/dispatch.toml and hosted.toml.
  • broker-probe.yml, every 15 minutes: agent-board broker probe --config .github/broker/config.json --apply (broker probe), with the broker's address added, off until a repository variable enables it.

Two parts of that caller are still copies rather than configuration: dispatch.yml, which calls cgwalters-forge/actions' cgwalters-agentic-job.yml wrapper, with its bounds and profiles under .github/agentic-job (step 2), and review.yml with workflow/review.* (step 4). Its callers also build through a just build-agent-board recipe in tracker's own Justfile, which runs the check and cargo install above (taking the source from agent-board.json); a deployment does not need that recipe.

Repeat a staging trial

With the prerequisites satisfied, use a disposable staging repository and project selected by the trusted configuration; do not reuse a production board or enable a scheduled applier. Use at most three small, independent issues: one research task and two harmless documentation tasks. Add them with item add previews before applying each addition. For each, have an accepted writer post a plan, inspect dispatch --dry-run, then dispatch it once. Stop at the first failed prerequisite; do not work around bounds, widen token permissions blindly, or replace an ambiguous dispatch record to force a retry. Keep batching and scheduled dispatch off so each result can be attributed to its plan.

Inspect the dispatch record and the linked run, then preview the matching Run/Result update with run record before applying it. Verify any pull request and exact-head review separately: neither a successful dispatch nor a recorded run proves the task succeeded.

Report the date, workflow revision, non-secret configuration names, issue, plan, run and pull request links, exact commands and exit statuses, expected versus actual results, and every guess or workaround. Mark unattempted steps unverified, and remove only scratch objects the trial created.

Scheduled reconciliation

This repository's reconcile.yml is a staging example of applying reconcile plan repairs from CI; the pass's Status stage (pass) replaces it at cutover, so a deployment does not copy it: once its pass caller runs, that derives Status. Every ten minutes on main it reads a staging board with a read-only token, writes reconcile plan --emit proposals as an artifact, and hands them to agentic-job's independent check and apply, bounded by reconcile.toml to Status updates on one project and issue closes in one repository. The board comes from the repository variables RECONCILE_OWNER, RECONCILE_PROJECT and RECONCILE_REPO; until they and the read token are set, each run skips with a notice. Apply is skipped when nothing is proposed, and it does not reread the board, so an issue reopened between snapshot and apply can still be set Done.

It needs two environments:

  • staging-project-read holds STAGING_PROJECT_READ_TOKEN, with organization Projects Read and repository Issues Read on the staging repository (plus GitHub's required Metadata read), and no write credential. Set its deployment branches and tags to Selected branches and tags, with only a branch rule for main and no tag rules. Do not use "Protected branches only", which can admit other protected branches.
  • staging-project-apply, limited to main the same way, holds SAFE_OUTPUTS_PAT with organization Projects read and write and Issues write on the bounds' repository.

Remove any repository or organization secret of the same names accessible to this repository, so a branch workflow cannot bypass an environment by omitting environment; revoke and reissue a token that was ever a repository secret. Keep changes to these environments restricted to trusted administrators.