Forges
Responsibility
The forge publishes code and represents pull requests.
- The kernel owns the forge. Pushes, PRs, comments, merge and merge happen in deterministic code.
- Agents only commit locally. They never push or see forge credentials.
- Publication is exact. The branch head read back from the forge must equal the intended SHA.
Shipped adapters
GitHub
The default, selected explicitly in this complete configuration:
forge = "github"
[tickets]
source = "file"
readyState = "ready"
Export a token for the dispatcher:
export GITHUB_TOKEN='<push-capable repository token>'
bun ab init --validate
Credential precedence:
GITHUB_TOKEN, if nonblankGH_TOKEN, if nonblank- local
gh auth tokenlogin, checkout-mode local workspaces only
Origin mode and Vercel Sandbox need an exported token. Never forward kernel credentials to guests; private cloning uses a separate read-only identity.
| Permission | Used for |
|---|---|
| Contents: write | publishing branches |
| Pull requests: write | opening and updating PRs |
| Metadata, Administration: read | readiness checks |
A classic token on a private repository needs the repo scope instead. Validation doesn't guarantee a merge: branch protection, required checks, merge settings and permissions can still defer merge.
Local git
forge = "local-git"
[tickets]
source = "file"
readyState = "ready"
Needs only Git and a writable repository.
- Pull requests are JSON records under private
refs/autobuild/refs, linking to local branch refs. - Publication confirms the local branch; nothing is uploaded.
- Merge makes a head-guarded squash commit with compare-and-swap ref updates, waiting while the checked-out destination has unsafe local changes.
It can't serve remote sandboxes; use GitHub there.
Writing your own
Writing a plugin covers the module, packaging and capability contract. For a forge:
- Register a
ForgePluginFactoryinforges. - Expose a
ForgeContractFactory. - Run the shared harness unchanged before dispatching:
bun ab plugin test forge acme
Then select it:
plugins = ["./autobuild-plugin.ts"]
forge = "acme"
[tickets]
source = "file"
readyState = "ready"
An adapter must provide:
- idempotent PR creation
- exact-SHA publication confirmation, never inferred from ancestry or a push response
- guarded merge and comments
- every capability it advertises
Reconciliation needs the optional Forge.rewrite group: immutable exact-SHA archives, branch snapshots and head-guarded replacement. Report lease mismatches separately and preserve unknown work. Without it, reconciliation fails with an actionable refusal, never an ordinary push.
Classify failures with ForgeFailure (API 1.8):
{ kind: 'rate-limited', resetAt } // resetAt: a valid ISO timestamp
{ kind: 'transient', retry: 'retryable' } // retryable transport failures
Ordinary policy or permission refusals stay deferrals.
Optional observeRequests observers count every wire request, including failures and pagination, attributed to a build when known, excluding skipped calls and credential discovery; no observer means "unknown", not zero. Keep tokens out of failures and telemetry.