Skip to content

onboarding a project

a project is a namespace: a github repo that receives approved specs as PRs. every spec belongs to exactly one, via namespace: owner/repo frontmatter or the board's default. only repos on the operator-controlled allowlist take part in the PR flow; specs pointing anywhere else get a red namespace chip and never open PRs.

board cards carrying their namespace chip

prerequisites

  • a github repo to hold the specs. features can live in other repos (see implementation-repos below).
  • the board's service token (GITHUB_TOKEN) needs contents read/write and pull requests read/write on the repo.
  • spec authors have write access on the repo and log in to the editor via github. login asks for no repo permissions, so spec PRs open under the board's service token rather than the author.

steps

  1. commit .specs/roles.yml to the repo's default branch:
approvers: [octocat, hubot]         # GitHub logins allowed to approve
approvals-required: 2               # quorum; default 1, explicit 0 disables it
implementation-repos: [owner/app]   # scanned for "implements #N"; default: this repo
commit-prefix: spec                 # PR/commit type; "" for a bare title
areas: [api, design, client]        # optional allowlist; also enables tag routing
specs-dir: specs                    # dir specs land in; "." for the repo apex

a spec picks its area with area: api in the note frontmatter and lands as specs/<area>/NNN-<slug>.md (specs/NNN-<slug>.md without one). any area routes by default; declare areas to restrict the set and to let a matching note tag route as fallback.

  1. protect the default branch and add a CODEOWNERS rule for specs/** (* in a repo-mode specs repo, see below). board approvals are cooperative workflow; the merge review on the spec PR is the enforceable gate. don't skip this and expect the board to be your security boundary.

  2. add the repo to the board's NAMESPACES env (comma-separated) and roll the deployment. to make it the default for specs with no namespace, also set DEFAULT_NAMESPACE on the board and CMD_SPEC_DEFAULT_NAMESPACE on the editor; the two must match.

  3. verify with curl https://<board-host>/api/namespaces: repo, push, and roles should be pass (protection stays unknown when the token can't read branch protection, which is fine), poller.stale should be false.

roles.yml semantics

  • approvers come only from this file, never from the editable note; the note records approved-by but the roster and quorum are repo-controlled.
  • approvals-required is clamped to the approver count. malformed values fall back to 1; an explicit 0 turns quorum off.
  • unresolved comment threads block approval regardless of quorum.
  • areas (legacy key: categories): optional. without it, any area: frontmatter routes as its slug and tags never route. with it, an unlisted area is ignored and the first note tag matching the list is the fallback. spec numbering (NNN) is per directory, and the area is pinned when the PR opens, so later frontmatter or tag edits never re-path an existing PR.
  • implementation-repos: repos scanned for implements commits. omit when features land in the spec repo itself.
  • specs-dir: where specs land. . (or "") publishes at the repo apex: <area>/NNN-<slug>.md, no specs/ dir. any other value is a subdir, nesting allowed (docs/specs). changing it orphans already-published specs: they stay where they are, and numbering starts over in the new dir.

repo mode

a repo that holds nothing but specs can commit roles.yml at the repo root instead of .specs/roles.yml. that flips the specs-dir default to the apex; set specs-dir explicitly to override in either direction. with the apex layout, point CODEOWNERS at * instead of specs/**.