Design
1. Scope and durable model
Build a new Rust project, not a homegit migration. agent-board is a typed interface and controller for a forge-hosted work board. Deterministic reconciliation repairs bookkeeping and admits eligible work; short-lived agentic jobs supply triage, prioritization and synthesis. GitHub Projects v2, issues, comments, PRs and Actions remain the records people inspect and edit. There is no application server, private task database, new chat system or credential-bearing coordinator agent. Code push, PR close and upstream promotion belong to separately bounded jobs; merging an approved green head is one of the pass's own writes. Leave homegit v1 untouched, and never give both controllers write ownership of the experimental board.
Start with one new organization project and an explicit issue-write repository allowlist. All issues in a dedicated intake repository are enrolled; other repositories require a configured inclusion label or existing membership. This catches work opened outside the tool without claiming every upstream issue. A separate read allowlist may include upstream repositories. Only public work is in scope initially; do not copy private context into public tracking issues.
Each item has one canonical issue and one project membership, keyed by native identity rather than title. PRs are results, not a second task queue. Read-only upstream issues can be canonical items; work requiring issue writes outside our authority gets a local tracking issue linking upstream. Do not create project draft items, including hidden drafts used as a key-value store.
| Concept | Authoritative forge representation | Meaning / writer |
|---|---|---|
| Item | Issue title/body and native identity; project membership | Acceptance criteria live in the body. Membership defines managed work; enrollment repairs omissions. |
| Epic and children | Issue with an existing epic label; native sub-issue relation | Decomposition is not a dependency or permission. Unclassified work need not have a parent. |
| Status | Project single-select | Derived and written by each pass from live facts; only Todo, Backlog and Priority are a person's choice (architecture). |
| Priority | Project single-select: P0, P1, P2 | P0 blocks current work; P1 active focus; P2 parked. No mirrored priority labels. A read-only Forgejo label board (forges) reads priority/P0..priority/P3; the snapshot also admits P3, so a GitHub P3 option now reads as a value rather than as incomplete. |
| Whose turn | Project single-select Turn: Coordinator, Worker, Operator, External, None | Canonical coordination signal. Native assignees remain human ownership, not a second turn field. |
| Operator ask | The needs-human label on the issue or PR | The one marker that the operator must act; the board's Needs human status derives from it (architecture). |
| Results and blockers | Project text fields Result, Blocked by, Next, News | URL lists are parsed as typed references. Next is explanation, never executable input. |
| Run | Actions run ID plus attempt, workflow identity/ref and URL; Run field; the dispatch record on its issue (dispatch) | Actions determines queued/running/finished, not model prose. Artifacts hold details, not indispensable state. |
Reviewed configuration on the protected default branch holds project identity, repositories, operator identities, field/options schema, enrollment, slot count, spending ceilings and fixed workflow routes. This is policy, not a second live board. The project is authoritative for work intent; issue/PR/run objects are authoritative for facts. Reconciliation explains and repairs disagreement rather than overwriting reality.
Off-forge storage is limited to disposable snapshots, caches, temporary artifacts and within-scan cursors. Losing these must not lose an ask, authorize a run, reset spending or repeat an irreversible operation. Summarize accounting and action receipts onto the forge before artifact expiry. Credentials remain in CI secret storage, never board fields.
2. Agent interface and the Paperclip comparison
Verified source facts
Paperclip is more than a kanban UI. Its commit-pinned core skill describes short heartbeat windows, injected agent/company/run identity, API access, inbox selection, checkout before work and final disposition. The injected context includes PAPERCLIP_AGENT_ID, PAPERCLIP_COMPANY_ID, PAPERCLIP_API_URL and PAPERCLIP_RUN_ID; local adapters supply a short-lived run JWT through PAPERCLIP_API_KEY. The skill uses /api/agents/me and /api/agents/me/inbox-lite. A mention alone does not authorize taking somebody else's assignment. States include backlog, todo, in_progress, in_review, done, blocked and cancelled. Task documents support revision-aware PUT /api/issues/{issueId}/documents/{key}.
Its company-skills reference at the same commit separates the skill catalog/library from agent assignment: installation does not attach a skill to an agent. Names and descriptions support discovery, then the full SKILL.md and supporting references are loaded as needed. Same-company reads and policy-controlled mutation are distinct capabilities; ordinary skill mutation is open unless policy restricts it, while team installation requires agents:create. These are source observations, not results of running Paperclip.
Point-by-point design response
Skills and discovery. Adopt concise descriptions, explicit loading and reference files. Ship board-work, board-coordinate and board-report skills at reviewed commits. Advertise their names/descriptions and paths, preload board-work, and load the other two only for that role. Reject runtime self-installation of privileged instructions: a task comment cannot change the skill revision or policy.
Identity and context. Adopt scoped wake context, not an unbounded board dump for every worker. Replace Paperclip's authenticated application API with a credential-free snapshot. The trusted prepare stage supplies forge-attributed actors and events, item/ancestor/blocker context, policy digest and capabilities. A worker cannot claim operator identity by writing it in JSON.
Task discovery and assignment. Adopt explicit inbox selection and checkout semantics, not opportunistic work stealing based on mentions. The coordinator sees actionable board items; workers receive one admitted item. Paperclip has a checkout endpoint backed by its service. Projects v2 does not offer equivalent atomic checkout: serialize admission through one trusted job and record the claim before launching work. An agent changing Status to In Progress is not a claim.
Lifecycle and reporting. Retain explicit disposition and evidence at the end of a short run. Forge status and result links replace application issue state; ordinary issue/PR comments and linked artifacts replace a second task-document service. A worker reports its own result and proposed disposition, not arbitrary parent completion. Cancelled blockers do not count as successful completion.
Agent-to-agent communication. Preserve task-scoped handoff rather than chat-driven implicit assignment. Use job plans on the issue, native parentage, explicit blockers and attributed result receipts. Load only relevant comment deltas where possible, but retain a complete-record fallback. A quoted comment, mention or copied marker never authorizes downstream action.
Heartbeat and continuation. Adopt short execution windows that act and exit. Every nonterminal item must name a real continuation: admitted run, pending request, operator ask, external dependency or next reconciliation. Prose promising that a watcher will resume work is not a scheduler. Actions run facts and level-triggered scans replace an always-running application coordinator and synthetic heartbeat comments.
Approvals. Paperclip's broader approval/organizational model is useful inspiration, not an API to clone. Initially use forge-attributed operator answers and exact-head PR reviews. A response resolves the question it answers; it does not grant unrelated push/merge/promotion authority. Do not introduce hiring, org charts or a general approval service.
Budgets. Retain explicit run and period limits, reservations and actual usage. Enforce them in the broker/runner and trusted admission job, not through a model's cost estimate. Do not claim semantic parity with Paperclip budget enforcement without testing its implementation; our proposed guarantee is explicit and independent.
Security boundary. Paperclip authenticates agents to an application API. agent-board authenticates the CI job and applier, never gives the model forge credentials, and treats every output as a proposal until independently checked. Agent security is CI security: protect refs, environments, artifacts, dependencies, tokens and dispatch inputs. Prompts are not an access-control mechanism.
Proposed read/write contract
The prepare stage emits board-snapshot/v1: native project/repository/item identities, schema/options, relationships, facts with timestamps and provenance, compact comments plus operator events, slots/budgets/runs, completeness flags and an injected clock. Large bodies are separately bounded files. Missing/redacted data stays unknown. The coordinator receives the normalized board and intake inventory; workers get the relevant subset.
gh agent-board … --snapshot FILE reads offline with no token or network. The binary also runs directly as agent-board, without authenticated gh. There is no arbitrary GraphQL/REST passthrough in an agent job. Missing context produces missing_data rather than guessed state. A later read-only gateway is optional.
Mutation commands with --emit print JSONL safe-output proposals. Local validation helps the agent, but only independent check/apply establishes authority. Workers receive item-scoped capabilities; the coordinator receives the configured project/intake scope. Until a trusted apply receipt exists, the agent says proposed, not updated.
3. Agentic-job bounds and delegated operations
Use agentic-job from the first PR: policy → agent → check → apply on separate machines. Pin workflow, binary, skills and gh-aw handlers to reviewed commits, except that our own workflow and action references follow main or, for agentic-job, a release tag, and the review wrapper is pinned by commit (tracker#544). Only apply receives a narrowly scoped write credential; prepare may use separate read access, but the model receives neither. Disable incidental notification/conclusion writes unless separately bounded. Never inherit all secrets or forward caller-selected bounds paths, runners, environments, output repositories or workflow refs.
Current support differs from the proposal. The inspected workflow documentation, event contract, sample bounds and issue 113 must be read together. The sample enables create_pull_request/add_comment/noop/missing_tool/missing_data. create_issue is also collector/check-tested when allowed, but its apply handler has not been exercised by that workflow; labels and assignees have no bounds yet, and parent/blocked_by are refused. The docs explicitly mark real-agent execution, cross-repository calling, analysis mode and several apply configurations untried. Issue 113 is an integration gap, not evidence that its requested expansion already works.
Proposed exact launch profile
The bounds extension must name a resolved project node ID AND canonical URL, exact issue-write repositories, permissible content identities, field IDs/options and per-type limits. This is a new validation contract, not TOML today's parser already accepts. Retain the existing outer hosts/repos/bases/output/trigger limits. Select analysis/no-patch mode and reject every patch.
Allow at most 20 outputs per run, with these individual maxima:
- update_project: 10. Only this project, issue-backed items in the enrollment scope, and existing fields/options. Permit Priority, Turn, Ask, Result, Blocked by, Next and News; at most eight field changes per output. Text fields max 2 KiB; Next/News max 500 characters. No draft/PR content, field/view creation, project creation/settings changes, item deletion or implicit schema extension. Status and Run are written by the pass alone.
- create_issue: 3. Exact allowlisted repositories; title max 200 characters, body 20–8,000 characters. No agent-supplied labels, assignees, parent, blockers or arbitrary metadata. Disable expiration, auto-close-older and automatic event-parent linking. Creation gets trusted provenance and an idempotency key. Subsequent enrollment failure leaves an issue the census will recover.
- close_issue: 5. Exact allowlisted repository and managed item, verified to be an Issue rather than a PR sharing its number namespace. Permit completed/not_planned only, require current completion/cancellation evidence, and disable optional closing comments or relationship side effects. Already closed is a no-op.
- create_project_status_update: 1. This exact project, max 4,000 characters, no more than once per reporting interval, and only when material change exists. It is a project edit, not permission to comment anywhere.
- noop, missing_tool, missing_data: 1 each, also counted in the total; diagnostic text max 2 KiB.
These are proposed coordinator limits, not gh-aw defaults. Its safe-output reference uses hyphenated configuration names and underscored emitted types. It documents update-project with default max 10, project and cross-repository resolution options. The configured project is not itself an enforcement boundary: the message must explicitly supply the project. Require exact identity before invoking the handler. Disable create_if_missing and reject draft/create_fields/create_view modes; pre-create the schema. The update_project handler is more permissive than this design. Treat skipped/warned field writes as incomplete until a post-read confirms each requested value. Handler success alone is insufficient.
Map enrollment and board-field edits to update_project; new tasks to create_issue; accepted completion to close_issue plus update_project; narrative board reporting to create_project_status_update. Labels and assignees are issue properties, not project custom fields. gh-aw's add_labels/remove_labels/assign_to_user/unassign_from_user/add_comment and sub-issue support do not imply agentic-job bounds for them. None is enabled in the strict board-agent profile. Preserve existing assignment; humans establish native parentage initially. An explicitly approved metadata job may later set fixed labels, two configured assignees and same-owner sub-issue links. Until then missing parentage is visible triage debt, not a invented native relation.
No generic update_issue, create_project, dispatch_workflow, PR mutation, repository dispatch or workflow editing capability is granted to the board agent. No project-deletion safe-output was established by this research. Provisioning/deletion is trusted human/CI work. Controller receipts use a separate tightly scoped trusted profile; they are not extra model permissions. Apply integrations must also suppress handlers' implicit event comments and issue creation side effects that would escape this strict profile.
Until these bounds exist in agentic-job, run the board caller in preview: publish artifacts or a separately authorized review comment, not board mutations. Land the narrow bounds/handler integration as an explicit prerequisite. Never work around it with agent-side gh credentials or a generic custom output that executes arbitrary APIs.
4. Pure rules, judgment and drift repair
reconcile(snapshot, policy, now) -> plan is pure. Plans contain stable action keys, prerequisites, reason codes, evidence references and expected relevant values; the same input yields byte-stable sorted output. A pass applies these deterministic plans itself (architecture); agentic-job's independent check/apply is for agent output, and a model cannot obtain controller-only permissions merely by naming a deterministic rule.
Run the deterministic pass on a cron, with no event wakes. A daily full census enumerates all board items, including terminal/archived items, all intake issues in all states, linked PRs and runs. Paginate every connection, including nested field values/comments/relationships. Do not use search as a complete inventory. A partial or redacted response blocks actions depending on missing facts; 404 is unknown, not proof of completion. Honor rate limits and expose stale coverage. No cursor can permanently exempt an invariant.
The five tracker#405 drift cases become explicit construction/repair contracts. Their Status targets predate derived Status (architecture); where they differ, the pass's stage 5 is what runs.
- Missing status and never-triaged work. Every enrollment plan includes Triage and Turn=Coordinator. Adding a project item and setting fields are separate API steps, so null is temporarily possible; the null rule repairs it on every pass. Triage older than 24 hours generates a health alert, never automatic execution. Agent failure does not turn Triage into Todo.
- Done with an open issue. Accepted completion produces closure and terminal status as resumable actions. Done alone is not permission to close: require designated accepted results or an authenticated completion/cancellation decision. Unsupported Done is returned to an evidence-derived nonterminal state with an alert. Failed closure remains visible; archiving does not hide it.
- Draft whose PR merged. Inspect designated result reality independently of prior status. A merged resolving PR, with no remaining acceptance criteria or required results, produces issue closure and Done even from Draft or Blocked. Closed-unmerged is not success; a closed fork with an open promoted PR stays In Review. Reopened issues return to Triage unless an explicit resume authorization exists.
- Issues opened outside the tool never added. Enumerate the intake repository and configured enrollment selectors, subtract membership by native identity, then add omissions. Already-closed issues get terminal classification, not a new execution. Only explicit, auditable exclusions remain outside the board.
- No full-board recheck. The scheduled census is mandatory and reports coverage/time/counts in the pass output. Monitor failure and stale coverage. Every complete census checks contradictions, vanished runs, orphan asks and invalid schema, including terminal items.
Turn follows facts: active run → Worker; unresolved ask → Operator; a newer authenticated operator reply → Coordinator for interpretation; external review/dependency → External; terminal → None. A reply is consumed by exact comment identity/revision, not unrelated updated_at changes. It is not automatically approval. A cancelled blocker requires replacement or explicit waiver. An epic does not consume a slot because its children are active, nor complete merely because all children closed if parent criteria remain.
The GitHub work queue comparison records the operator's 2026-10-09 choice of option (b): finish the narrow one-slot approval→run→checked result seam toward a somewhat hardened functional PoC, with agentic-job the more important primitive. Multi-worker fairness and general dependency scheduling are out of near-term scope per that decision; the broader scheduling ideas below are not near-term requirements. The operator later asked for batching and overlap checks to stop bot pull requests conflicting (#86, #88): dispatch --batch and --bot are both off by default; see batching and overlap. Scheduled runs are never batched.
Scheduling, capacity and pacing are the pass's. Execution eligibility is independent of editable Status, and missing usage holds new starts. Runner/broker enforce token/request/time limits during execution; later board observation cannot be the hard stop.
The model judges whether an issue is actionable, proposes decomposition/priority/estimates, interprets substantive replies and writes reports. It does not decide whether a PR merged, a run exists, an actor is the operator, a budget fits or a workflow is permitted. Apply revalidates irreversible-action evidence on fresh state. Projects lacks general compare-and-swap: serialize tool writes and re-read before/after, but acknowledge concurrent human UI edits can still race. Invalidate stale plans; never derive irreversible authority solely from a project field transition. The guarantee is repair after API/scheduler recovery, not prevention of all human-induced drift.
What to retain from homegit
Use PR 170's pinned proposal as prior design, not an adopted implementation. Retain operator/coordinator/worker separation, task-in/safe-outputs-out, pure snapshot rules, one writer and neutral forge types. Current bot-reconcile, lib/reconcile.js, workstream skill and coordinator skill provide useful semantics, but use local sweep/heartbeat/cache state and directly privileged operations. Port invariants and table tests, not that process topology.
The new repository replaces workstation installation and migration concerns. Native run history plus durable accounting replaces synthetic heartbeat state. This rollout does not require a v1 cutover or deleting homegit tools. Do not import duplicated priority labels, null-as-triage, prose-parsed action instructions, credentialed local workers or an open-ended coordinator session. Fallback representations for other forges must remain visible forge records, never hidden draft items or a private database.
5. CLI: gh agent-board
Ship binary gh-agent-board, also invokable as agent-board. A conventional gh extension distribution repository must be gh-prefixed: recommend a release-only cgwalters-forge/gh-agent-board repository while source stays here, or rename this repository. Do not claim gh extension install cgwalters-forge/agent-board follows the extension naming convention. Publish platform-specific precompiled releases from trusted CI with checksums and pin installations. No substantial shell installer.
Commands use noun-verb structure, as gh does. The commands that exist, and their flags, are in the CLI reference, generated from the binary. Proposed commands that do not exist yet include item create, item close, run list, run view, request create, request view, and output check/output apply (which exist only as an unsupported error).
Reuse -R/--repo, --owner, --project NUMBER, --hostname, -L/--limit, --state, --title, --body-file -, --web, --json fields and --jq expression. --status means board status, distinct from issue --state. ITEM accepts URL or OWNER/REPO#N; bare numbers require -R. --snapshot is offline; --emit writes proposals, never network mutations. Mutation commands default to preview with an explicit not-applied message. Human --apply goes through the same policy checks; the protected CI applier uses its own profile. An agent cannot gain mutation authority by omitting --emit: it has neither credentials nor an allowed mutation network path.
Human live reads can use gh as authenticated API transport through argv/stdin, not shell interpolation or another credential store. Offline reads never invoke it. Implement --json field selection and --jq with a tested Rust jq engine; defer --template with an explicit unsupported error rather than silently offer something different from gh's Go templates. Human output is concise; diagnostics go to stderr; machine schemas are versioned. Follow gh exit codes: 0 success, 1 failure/invalid invocation, 2 cancelled, 4 authentication required. Structured diagnostics distinguish stale_plan, rate_limited and unsupported_capability. A successful plan that finds drift still exits 0.
The trusted create-issue route fixes the repository from policy; omitted targets must not silently select an unrelated checkout. Project provisioning and deletion reuse existing gh project commands rather than duplicating the whole CLI. References: gh command reference, extensions, exit codes.
6. Day-one live CI and credential-free tests
Every privileged test run creates a disposable organization Project v2 named agent-board-ci-
A bootstrap alternative is a fine-grained PAT with organization Projects read/write and sandbox Issues read/write, subject to owner/token support. User-owned projects need a compatible user credential, typically a classic PAT with project scope and public_repo for public issue writes (repo for private access). Do not assume an organization App installation covers a user's project. Confirm the chosen endpoint/token combination in the first fixture; GitHub Projects API guidance distinguishes project scopes and permissions. The operator configures secrets in CI; no credential value belongs in agent context.
Day-one CI has two lanes. Unprivileged PR CI runs formatting, clippy, unit/fixture/property tests, CLI golden tests and malicious-output cases. A trusted-ref protected dispatch runs a random-project fixture and a scripted agent through agentic-job policy/agent/check/apply. Initially exercise the already-supported comment/preview path and trusted project lifecycle, without claiming board mutation support. After the prerequisite bounds land, the same fixture must apply actual project/issue outputs and verify convergence. Add a real-model smoke only after broker admission exists; it is not the deterministic correctness oracle.
Never run arbitrary fork/PR code with the project token. Candidate code may produce proposals in an unprivileged job; a trusted applier validates them independently. Testing candidate applier code live requires approval of that exact commit, protected environment and isolated owner. Never use pull_request_target to checkout and execute an unreviewed head. Verify source commit, workflow identity and run/attempt for artifacts; do not share writable caches across the agent/validator boundary.
The Rust fixture runner provisions existing fields/options and a few issues in a pre-created sandbox repository. It records returned identities, nonce, run URL and expiry in a cleanup artifact and project description. Test reads, enrollment, fields, asks, accepted closure, terminal reconciliation and no-op replay. Seed all five drift cases, interrupt between enrollment and status, and verify the second complete pass converges. Simulate delayed visibility, rate limits, stale plans, ambiguous dispatch and concurrent edits offline rather than disrupting GitHub.
Negative cases must refuse wrong project URL/node ID, a PR number where an issue is required, unlisted repository, unknown field/option, excess outputs, nested target escape, labels/assignees, broad dispatch refs and copied approval markers before mutation. Keep a forbidden canary project and verify it remains unchanged. Assert exact repository/project isolation, no PR mutations, slot/budget limits, sanitized text and complete pagination. Fixture provisioning/deletion authority is never board-agent authority.
Cleanup runs under always(), deletes only recorded project IDs after owner/name/nonce checks, and closes only marked fixture issues: deleting a project does not delete its issues. A trusted scheduled sweeper enumerates projects in the test owner, verifies prefix PLUS provenance/age, excludes active runs and deletes leftovers older than 24 hours. A prefix alone is not proof of ownership. Cleanup failure fails/reports the run; cancellation can skip cleanup, so the sweeper is mandatory. Retain enough identity in the project itself to recover even if the artifact upload failed.
Offline fixtures cover pagination, redacted/null nodes, permissions, rate limits, schema rename, every status/turn transition, native relationships, request validation and accounting. Data-driven and property tests check deterministic ordering, idempotent convergence and absence of unauthorized actions. Required future commands are cargo fmt --all -- --check, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace, and a separately opt-in live fixture command. No model or credential is required for the first three. None was run for this analysis.
7. Rust boundaries
Current implementation limits
This section covers the board reader and reconciliation. Commands built since
have their own pages: pull request follow-up (poll, status),
dispatch, job plans, epic plans,
the supervisor and operator interaction;
pass combines the first several.
The workspace implements offline snapshots, missing-status and issue/status
terminal-drift rules, GitHub proposal lowering, paginated GitHub
schema/membership/issue/PR reads, live read commands, and a staging fixture that
seeds an issue and text field, reads a snapshot and plans drift before cleanup.
live/board-test.yml supplies the protected staging workflow template, and this
repository's reconcile.yml hands reconcile plan --emit to agentic-job's
independent check and apply for a staging board.
It does not complete step 1's scheduled sweeper.
The reader reads each page of 100 board items with their field values, labels and assignees inline, so a board costs a request per page; only an item with more than a page holds is read again by itself. Label, user, linked-PR and reviewer field values are not GraphQL nodes. The reader fetches their nested connections inline (10 entries in a page, and at most 100 in an item's own read); additional pages or redacted/missing connection data mark the item and snapshot incomplete, blocking reconciliation rather than treating a partial list as complete.
Terminal-drift plans leave Done/open issues for review, never proposing closure
from Status alone, so a person's reopen is not undone. Closed issues get Done
only for COMPLETED, Cancelled for NOT_PLANNED; an unknown reason blocks repair.
Every target status must exist unambiguously in the snapshot schema; a snapshot
marked status_field_absent (a Forgejo label board) gets no Status repairs. Both
the observed status and issue state, plus the closure reason, are captured as
preconditions. The pass's Status stage (pass)
replaces these plans as the board's Status writer. Incomplete
snapshot coverage blocks all repairs; incomplete item fields block that item's
repairs. Closed issues are classified before the missing-status rule, avoiding
an intermediate Triage proposal. No live reads or live terminal repair have
been verified against GitHub. Recorded responses exercise the lifecycle and its
failure cleanup without credentials.
test project --sweep fails before authentication or network access. Editable
project descriptions and completed Actions runs cannot prove who created a
project. Re-enabling sweeping requires an independently authenticated creation
receipt binding the returned project ID, nonce, run ID/attempt and approved
workflow identity; missing proof must leave a project untouched. Immediate cleanup
retains its trust anchor in memory: the ID returned by creation and the locally
generated nonce. Crashes require manual recovery until the trusted receipt store
and protected sweeper are implemented.
The current board-snapshot/v1 reader rejects unknown fields at every nested
record boundary. Status, Priority and Turn must be present, with explicit JSON
null for an observed unset value; omission is a schema error, not null. Evidence
may be omitted and defaults to an empty list. Unknown schema versions are rejected
by validation. This is a deliberately strict input policy, not forward-compatible
field discovery. GitHub issue/project URL grammar belongs to board-forge; core
validates only generic identities and canonical HTTPS project URLs. The GitHub
adapter supplies the default hostname.
Use three crates: board-core for domain types, versioned snapshots/plans, pure rules and budget arithmetic; board-forge for GitHub reads, capability discovery and safe-output lowering; agent-board for CLI, orchestration and the Rust integration-fixture driver. Keep skills, schemas, fixtures and rule tables in normal repository directories. No shell program longer than ten lines. Nontrivial fixture logic belongs in Rust; a small standard-library Node wrapper may call pinned gh-aw handlers without duplicating their sanitization.
Core types include ItemRef, ChangeRef, RunRef, Actor, BoardField, Evidence, Snapshot, Intent, Precondition and Capability, not GraphQL IDs or handler JSON fields. A read Forge trait exposes board schema/membership, repository issue inventory, issue/thread/relationship facts, PR state/reviews and runs, each with completeness/freshness. A separate OutputBackend lowers typed intentions to the bounded write protocol or returns unsupported capability; it does not grant a model a mutation client. Native identity includes host.
GitHub uses GraphQL for Projects and REST where appropriate for issues/comments/relationships and Actions. Discover field/option IDs; adding membership and setting fields are separate steps. The sub-issues API is a native relationship surface, but API availability is not safe-output permission. Cross-repository parentage requires platform and policy checks.
Dependencies: serde/serde_json, clap, toml, thiserror/anyhow, url, time, ureq with TLS, reqwest with rustls (ring) and the platform verifier, tokio (a current-thread runtime, its semaphore and timer), a SHA-256 implementation, and a jq-compatible Rust engine for --jq. Use assert_cmd, HTTP fixtures and proptest for testing. The GitHub board snapshot is async on reqwest; every other forge request is still synchronous on ureq, and moves in later slices (architecture). There is no SQL service.
Portability is capability negotiation, not spelling substitutions. GitLab boards are generally lists over issues/labels, with assignments, notes, links and pipelines; some epic/board features vary by tier. A GitLab project is a repository, not GitHub Projects v2. Forgejo's API is versioned REST/OpenAPI; board, hierarchy and Actions coverage must be checked against the target server version. Do not assume custom fields, token scopes or approval semantics match. A future adapter can use visible labels/comments for missing fields, but must report unsupported guarantees instead of weakening them. Prove second-forge read normalization first; replacement write appliers come later.
8. Operator decisions
A — Extension distribution. Recommend keeping source in agent-board and creating a release-only gh-agent-board distribution repository. Alternative: rename source to gh-agent-board to avoid a second release destination.
B — Initial authority and turn. Recommend the strict four mutation types above, project Turn, operator approval before execution, and no coordinator-native assignment/comment/parent writes. Alternative: explicitly add narrowly bounded comments, two known assignees and same-owner sub-issue links after agentic-job validates them. This is an authority expansion, not an implementation detail.
C — Test owner and credential. Recommend a dedicated test organization and a dedicated App minting short-lived tokens. Alternative: a dedicated account's user projects plus classic PAT; simpler setup but broader standing credential. Configure through CI administration, never hand the secret to the agent.
D — Spending and autonomy. Recommend one worker slot, finite run/period ceilings, missing usage blocks new work, and explicit approval for destructive downstream operations. Later enable policy-approved low-risk automatic admission and additional slots after replay/live tests demonstrate stable accounting. Neither option allows the model to raise its bounds.
Evidence and verification limits
This is a design, not implemented or live-tested behavior. Research used public HTTPS sources. Paperclip and homegit PR 170 links above are commit-pinned; homegit main, agentic-job main, gh-aw main and product manuals are moving observations, not release pins. Implementation must select compatible exact commits and contract-test them. The fetched tracker#405 page did not expose its comments in this environment; the five drift incidents are attributed to the supplied task context, not independently verified quotations. Paperclip runtime behavior, live Projects writes and real-model integration were not exercised. No GitHub API calls, commits, pushes or checkout-file edits were performed for this analysis. This comment is prepared as a safe output for independent validation/application, not posted directly.
Operator decisions (cgwalters, 2026-10-07)
- A, distribution: decide later. Build the binary as
agent-board, usable as a gh extension locally; pick how it is distributed when there is something to install. - B, authority: the strict four mutation types: project field edits, creating issues, closing issues, and typed requests to other jobs. Whose turn it is lives in a project field. No comments, assignees or sub-issue links from the agent yet.
- C, test credential: a fine-grained token for the bot account that reaches only the staging organization, https://github.com/cgwalters-forge-stage, stored by cgwalters as an Actions environment secret. That organization exists and the bot is an owner; creating and deleting a Project v2 there with the bot's token was verified by hand. Tests never touch cgwalters-forge.
- D, autonomy: one worker slot, finite per-run and per-period ceilings, missing usage data blocks new work, and his approval before each run starts and before any destructive downstream request. Changed 2026-10-11 (agent-board#27): runs started by the tracker polling job within its fixed bounds (our repositories, at most 2 fix rounds per pull request, auto-merge only on review success and green required checks) need no per-run approval.
The architecture records the operator's decisions of 23 October 2026, which replace these where they differ.
Earlier, on this project: homegit stays as v1 and is not migrated; this runs as an agentic job from the start; anything beyond board edits and opening and closing issues, even closing a pull request, is dispatched to another job; the CLI should feel like extensions to gh.