Goal
setup-board must create (and reuse) a board dedicated to the target repo, not funnel every repo into one shared project. Today all projects pile into a single "Board", so cards from unrelated repos mix together.
Symptom
Run the bootstrap flow (setup-board <owner>/<repoA> then later setup-board <owner>/<repoB>) and both repos' issues land on the same Projects v2 board titled "Board". Observed on lipex360x (2026-06-06): the shared board #15 held cards from ledgerflow, web-view, pi-cli, claude-rag, etc. all at once. The intended outcome is one board per project.
Root cause
scripts/setup-board.sh:
- Line 58:
readonly BOARD_TITLE="Board" — a hardcoded constant title.
- Lines 98–115 (find-or-create):
gh project list --owner "$OWNER" is filtered to .title == "Board"; if a project with that title already exists for the owner, it is reused (EXISTS:project/Board#N). The first repo creates "Board"; every subsequent repo finds it and attaches to it.
Because the title is constant across repos, the find-or-create collapses all repos onto one board.
Fix path (chosen)
Derive the board title per repo, with an optional override:
- Default
BOARD_TITLE to the repo name: BOARD_TITLE="${REPO##*/}" (e.g. ledgerflow). This is the minimal change that makes find-or-create key on a per-repo title, so each repo gets and reuses its own board.
- Add an optional
--title <name> flag so a caller can override the default (some teams want a human label distinct from the repo slug). Parse it alongside --dry-run in the existing for arg in "${@:2}" loop.
- Everything downstream already references
$BOARD_TITLE (find, create, EXISTS/CREATED output, dry-run print), so no other logic changes — the dry-run line DRY_RUN:project/${BOARD_TITLE} now surfaces the real per-repo name in preview.
Rejected alternative: keying find-or-create on the repo→project link instead of the title. That is a larger rewrite (the link check happens after project resolution) and still needs a title to create with; deriving the title is smaller and sufficient.
Not in this fix: migrating cards already sitting on the shared "Board". That is a one-time manual cleanup per repo (delete the repo's items from the shared board, add them to the dedicated one), not something setup-board should do automatically. Call it out in the PR.
Implementation order (TDD)
Tests are bats with a PATH-injected gh mock (per this repo's CLAUDE.md). Land as separate commits. Use chained assertions (&& \).
- Red — in
tests/setup-board.bats, add a test that runs setup-board owner/repo-alpha and asserts the create/find path uses title repo-alpha (the gh project create/gh project list mock records the title, and the test asserts it equals the repo name, not the literal Board). A second test runs two different repos and asserts two distinct titles are requested. Commit: test: setup-board uses per-repo board title (failing). Confirm both fail because the title is currently the constant Board.
- Green — change
BOARD_TITLE to default to ${REPO##*/} and add the --title override until the tests pass. Add a --title test asserting the override wins over the default. Commit: fix: per-repo board title in setup-board.
- Refactor — only if arg-parsing duplication appears; keep tests green. Commit:
refactor: setup-board arg parsing.
Run the repo's quality gates between phases (bats suite + shellcheck, per CLAUDE.md).
Files to touch
| File |
What changes |
scripts/setup-board.sh |
BOARD_TITLE defaults to ${REPO##*/}; add optional --title flag; update usage header |
tests/setup-board.bats |
per-repo title assertions; two-repo distinctness; --title override |
Acceptance criteria
Tick each item below by editing this issue body (gh issue edit <N>) as you land the corresponding commit. Do not batch ticks at the end. A merged PR with unchecked items is a process violation, not a shortcut.
Out of scope
Dependencies
Independent of #1, but they touch adjacent board logic — land whichever first and rebase the other.
Branch
git checkout main && git pull
git checkout -b fix/per-repo-board-title-2
Open the PR with Closes #<N> in the body so the issue auto-closes on merge.
Guardrails
- Always: keep board work idempotent and non-fatal to issue/label creation; preserve the
CREATED/EXISTS/DRY_RUN/FAILED output contract.
- Ask first: changing the default away from the repo name; auto-migrating existing cards.
- Never: reintroduce a constant shared title; never use
--no-verify.
Final step — documentation and skill sync
Goal
setup-boardmust create (and reuse) a board dedicated to the target repo, not funnel every repo into one shared project. Today all projects pile into a single "Board", so cards from unrelated repos mix together.Symptom
Run the bootstrap flow (
setup-board <owner>/<repoA>then latersetup-board <owner>/<repoB>) and both repos' issues land on the same Projects v2 board titled "Board". Observed onlipex360x(2026-06-06): the shared board #15 held cards fromledgerflow,web-view,pi-cli,claude-rag, etc. all at once. The intended outcome is one board per project.Root cause
scripts/setup-board.sh:readonly BOARD_TITLE="Board"— a hardcoded constant title.gh project list --owner "$OWNER"is filtered to.title == "Board"; if a project with that title already exists for the owner, it is reused (EXISTS:project/Board#N). The first repo creates "Board"; every subsequent repo finds it and attaches to it.Because the title is constant across repos, the find-or-create collapses all repos onto one board.
Fix path (chosen)
Derive the board title per repo, with an optional override:
BOARD_TITLEto the repo name:BOARD_TITLE="${REPO##*/}"(e.g.ledgerflow). This is the minimal change that makes find-or-create key on a per-repo title, so each repo gets and reuses its own board.--title <name>flag so a caller can override the default (some teams want a human label distinct from the repo slug). Parse it alongside--dry-runin the existingfor arg in "${@:2}"loop.$BOARD_TITLE(find, create,EXISTS/CREATEDoutput, dry-run print), so no other logic changes — the dry-run lineDRY_RUN:project/${BOARD_TITLE}now surfaces the real per-repo name in preview.Rejected alternative: keying find-or-create on the repo→project link instead of the title. That is a larger rewrite (the link check happens after project resolution) and still needs a title to create with; deriving the title is smaller and sufficient.
Not in this fix: migrating cards already sitting on the shared "Board". That is a one-time manual cleanup per repo (delete the repo's items from the shared board, add them to the dedicated one), not something
setup-boardshould do automatically. Call it out in the PR.Implementation order (TDD)
Tests are bats with a PATH-injected
ghmock (per this repo'sCLAUDE.md). Land as separate commits. Use chained assertions (&& \).tests/setup-board.bats, add a test that runssetup-board owner/repo-alphaand asserts the create/find path uses titlerepo-alpha(thegh project create/gh project listmock records the title, and the test asserts it equals the repo name, not the literalBoard). A second test runs two different repos and asserts two distinct titles are requested. Commit:test: setup-board uses per-repo board title (failing). Confirm both fail because the title is currently the constantBoard.BOARD_TITLEto default to${REPO##*/}and add the--titleoverride until the tests pass. Add a--titletest asserting the override wins over the default. Commit:fix: per-repo board title in setup-board.refactor: setup-board arg parsing.Run the repo's quality gates between phases (bats suite + shellcheck, per
CLAUDE.md).Files to touch
scripts/setup-board.shBOARD_TITLEdefaults to${REPO##*/}; add optional--titleflag; update usage headertests/setup-board.bats--titleoverrideAcceptance criteria
setup-board owner/repocreates a board titled after the repo (repo), not the literalBoardsetup-boardfor two different repos under the same owner yields two distinct boardssetup-boardfor the same repo is idempotent (EXISTS:project/<repo>, no second board)--title <name>overrides the default title--dry-runprints the resolved per-repo (or overridden) title inDRY_RUN:project/<title>CLAUDE.md)Out of scope
create-issuesfield-setting behaviour (tracked in create-issues: set board Status (and Priority/Size) on added items #1).Dependencies
Independent of #1, but they touch adjacent board logic — land whichever first and rebase the other.
Branch
git checkout main && git pull git checkout -b fix/per-repo-board-title-2Open the PR with
Closes #<N>in the body so the issue auto-closes on merge.Guardrails
CREATED/EXISTS/DRY_RUN/FAILEDoutput contract.--no-verify.Final step — documentation and skill sync
CLAUDE.md/SKILL.mdif the board-setup behaviour is documented there.READMEupdated if it shows the old "Board" naming.