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.
cargo install --locked --git https://github.com/cgwalters-forge/agent-board agent-boardThe 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:
agent-board item list --snapshot fixtures/board.jsonagent-board reconcile plan --snapshot fixtures/board.json --emitagent-board project view --snapshot fixtures/board.json --json project,coverageAll 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.
-
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.
-
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
reposand keepbases = ["main"]. Commit to the protected default branch, allow the actions, then dispatchkind=researchagainst an existing issue. Implement runs also need the apply environment and its token. Bounds protect documentation too: list the intended documentation files inunprotected_filesrather than unprotecting the repository. The workflow must take the inputs and set the run title agent-board expects (dispatch). -
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.
-
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.
-
Provision and read the board before writes. Pre-create the Status options
Triage,Backlog,Todo,In Progress,Draft,In Review,Blocked,Needs human,DoneandCancelled, and the Priority single-select withP0,P1andP2(durable model; Status is derived by the pass, see architecture).project initcreates only missing Turn, Run and Result fields, with the operator's token, and never edits existing fields or options;project init --snapshot FILEinstead prints copyablegh project field-createcommands on stderr without running them. For asks, provision thequestionandneeds-humanlabels and an assignable operator. Start withsnapshot createandreconcile planpreviews. 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; workflowpermissionsandGITHUB_TOKENdo not grant organization Projects writes. The live template shows a protected staging test. -
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:
[[ $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 CONFIGMoving 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-writesand--max-status-changescaps; a scheduled pass adds--applyonly 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 supervisedue,health,repeat,trigger,compose,previewandexecute(supervisor), reading.github/poll/agent-board.json,.github/supervisor/config.json,.github/usage/config.jsonand.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.mdand.github/agentic-job/pools.json; its agent job runs the dispatch wrapper with.github/agentic-job/dispatch.tomlandhosted.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.ymlwrapper, with its bounds and profiles under.github/agentic-job(step 2), andreview.ymlwithworkflow/review.*(step 4). Its callers also build through ajust build-agent-boardrecipe in tracker's own Justfile, which runs the check andcargo installabove (taking the source fromagent-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-readholdsSTAGING_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 formainand no tag rules. Do not use "Protected branches only", which can admit other protected branches.staging-project-apply, limited to main the same way, holdsSAFE_OUTPUTS_PATwith 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.