---
name: board
description: Show the repo workboard, then take it down in the fewest pull requests.
---

# /board — your workboard, and the fastest way through it

Two halves. The first shows a dev their board for this repo — what they hold, what is free, what others
took. The second is the reason this skill exists: plan the whole board into the **fewest pull requests**
that can safely be opened, then run those lanes in parallel.

Read-only until the dev says go. Rendering a board is not permission to take it.

## Step 1 — read the board

```bash
mmi-cli oracle board read --json --out .jerv/tmp/board.json
```

Prefer `--out` for a shell-independent UTF-8 receipt. Windows PowerShell 5.1's `>` writes
UTF-16LE with a BOM (#5802); Bash redirects preserve the CLI's UTF-8 output.

One call. Its JSON carries `viewer`, `repo` and the project title — do not spend extra calls on
`gh api user` or `gh repo view`. Use `primary` for this repo and `secondary` for other repos on the same
Project. Partial reads exit nonzero; pass `--allow-partial` only when the dev accepts an incomplete board.

Partition, as the CLI computes it:

- **Yours** — assignee includes the viewer, status in `Todo · In Progress · In Review`.
- **Free to claim** — status `Todo`, unassigned, and the viewer has push on the repo.
- **Taken** — someone else's, any active status.

## Step 2 — render it

Plain markdown, never a fenced block. Flat `-` lists under bold heads, never `##` headings, never tables.
Refs are `[RepoName#N](url) · short title` — no `owner/` prefix, no `[type]` brackets, title trimmed to
its essence. **Taken** renders id · status · owner only, never the title. Skip empty sections silently.
One screen.

> 👋 Welcome back, @dev — here's your board on **MMI-Hub**.
>
> **On your plate** — two train fixes in flight:
> - [MMI-Hub#834](https://github.com/mutmutco/MMI-Hub/issues/834) · automated hotfix apply path
> - [MMI-Hub#841](https://github.com/mutmutco/MMI-Hub/issues/841) · rcand stuck on required checks
>
> **Up for grabs** — nine open, I can take them in three PRs:
> - [MMI-Hub#821](https://github.com/mutmutco/MMI-Hub/issues/821) · redesign tenant env-writer
>
> **Taken**
> - MMI-Hub#827 · In Progress · @otherdev

Status moves happen automatically as work flows — claim, PR open, merge. Never offer a status move.

## Step 3 — plan the fewest PRs

This is the aggressive half. Do not offer one item at a time and do not default to one PR per issue.

Fetch the material you need to group by:

```bash
mmi-cli oracle board read --json --bodies --out .jerv/tmp/board-full.json
```

`--bodies` returns body and comments for **every** scoped row. `--bundle-details` is the cheaper variant
that covers only `userOwned` and `claimable` — prefer it when the plan is limited to claimable work.
`taken` stays metadata-only either way. Do not fetch Done items.

Then build the plan:

1. **Derive each issue's touch-set** — the files and directories it will change, read from the body,
   its comments and its `surface:*` label. An issue whose touch-set you cannot name is not plannable;
   leave it out of the batch and say so.
2. **Join issues whose touch-sets overlap.** Follow the overlap transitively: if A and B share a file and
   B and C share another, all three are one group. Each resulting group is one worktree and **one PR**.
3. **Groups are disjoint by construction**, so every group runs in parallel with no worktree contention.
   That is the whole trick — the number of groups is the number of PRs, and it is the smallest number
   reachable without two PRs fighting over the same file.

Forced splits — these override the grouping and each takes its own PR:

- **Another repo.** Never bundle across repos. Board advance is per-repo and deliberately refuses to move
  another repo's issue, so a cross-repo bundle lands the code and leaves those issues stranded open.
- **Irreversible or gated work** — migrations, secret rotation, release-train changes. Bundling hides them.
- **An issue that must stay open** (HOLD, prep, partial delivery).
- **Review size.** A PR no one can review is not cheap. When a group grows past roughly ten issues or
  spans unrelated subsystems, cut it at its weakest overlap and take two PRs.

Present the plan before touching anything — batch count, issue count, and one line per batch naming its
shared surface. Then stop and wait.

> Nine claimable, three PRs: **A** #6395–#6397 board routing · **B** #6398–#6401 train doctor heal ·
> **C** #6402–#6403 CLI flag validation. Say go and I'll run all three in parallel.

## Step 4 — on the dev's go, claim and run

Claim a whole batch in one call — it shares setup cost and returns per-item results:

```bash
mmi-cli oracle board claim <ref> <ref> <ref> --json
```

Claiming validates `Todo` + unassigned, assigns the viewer, moves Status to `In Progress`, and stamps a
lane-identity comment so other agents can attribute the hold. Any per-item failure exits nonzero — read
the per-item results rather than assuming the batch took. **Route is `oracle board claim` only**; there is
no `oracle issue claim` and no flat `board claim` — both refuse. Guessing either burns a call.

Then one worktree per batch, all batches concurrently. The host owns worktree mechanics; MMI owns board
and PR facts. On Windows set `git config core.longpaths true` on the main checkout before the first
`git worktree add` (#5499). Linked worktrees share one `.git`, so serialize `git branch -m` and other ref
renames across them, or retry serially when the error names `.tmp-renamed-log` (#5485).

## Step 5 — land one PR per batch

There is no `--issues` or `--closes` flag. A bundled PR is expressed in the **body**:

```
Closes #6395, #6396, #6397
```

`pr create` normalizes multiple closing directives, and after the merge the board advance walks GitHub's
full `closingIssuesReferences` list and moves **each** issue to Done, verifying every one and naming any
that did not move. So a bundle is a first-class landing, not a trick.

```bash
mmi-cli devops pr create --body-file .jerv/tmp/pr-batch-a.md
mmi-cli devops pr land <pr> --json
```

Materialize the body as a real UTF-8 file and pass its path; do not pipe it to `--body-file -`. Read
`mmi-cli explain devops pr create --json` before the write — flags change.

When an issue must stay open, write `Part of #N` or `Refs #N`. **Never** write `Does not close #N` —
GitHub closes it anyway (JC#495).

A repo running a guidance-learning gate also needs the body's learning line PLANNED here, not patched in
after a red check: when the batch's touch-set intersects that repo's guidance files (Jerv-JervCode:
`product/soul.md`, `product/runbooks/**`, `packages/*/skills/**/SKILL.md`), the body must carry a
standalone `learning: none — <reason>` line unless a closing learning issue's `promote.globs` names a
changed file. The line must stand alone on its own newline — a literal `\n` inside an inline edit fails
the gate again.

Landing requires a merged receipt before any cleanup: `state` `MERGED`, the head ref and OID matching the
local task branch, and a clean worktree. Anything else means retain and report, never clean.

## Guardrails

- **No go, no write.** The board render and the plan are free. Claims, branches, PRs are not.
- **Say the size out loud** before claiming: how many issues, how many PRs.
- **Same repo only** inside one PR.
- A batch is justified by a shared code surface, never by convenience. Unrelated changes in one PR make a
  worse PR, not a cheaper one.
- Surface any `gh` / `mmi-cli` error verbatim.

## Retro — one check before you finish
Before your final report, answer one question honestly: did **this skill's own instructions** misfire this
run — ambiguous wording, a misleading message, or an environment failure it should have warned about?
(Process only — never the user's code or task; e.g. a grouping rule that bundled two issues which turned
out to conflict, or a board read that misreported what was claimable.) If yes, file **one** lesson and
move on; a clean run is silent (hard cap: one per run). It lands on the owning board (deduped) and is
fixed only via a reviewed PR — never edit the skill live; the retro is advisory, so if the call fails,
note it and continue. File through MMI:
`mmi-cli learning skill-lesson --skill board --title "<what misfired>" --body "<what; evidence; proposed amendment>"`
