Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,10 @@ All work should be driven by items on the project board.

Set the label at create time (`gh issue create --label v2 ...`, `gh pr create --label v2 ...`) — don't rely on backfilling later, since unlabeled PRs are easy to miss when filtering by version.
- **Add the issue to the board and set Status.** After creating an issue, add it to board #28 and set its Status. (PRs are never added to the board — they're tracked through their linked issue's card.) This is the step most easily forgotten because it needs several IDs — copy the recipes below verbatim.
- When work begins, create a feature branch and set the item's Status to **In progress** (or **SDK V2 + New Spec** for a card in that stack).
- When work begins, create a feature branch and set the item's Status to **In Progress** (or **V2 Go Live** for a card in the go-live phases, #1804).
- When work is complete:
- Run format, lint, typecheck, build, and test — ensure all checks pass
- Open a PR against the matching base branch (`main` for v1, `v2/main` for v2) and set the item's Status to **In review**
- Open a PR against the matching base branch (`main` for v1, `v2/main` for v2) and set the item's Status to **In Review**
- **Link the PR to its issue.** The PR body's **first line must be `Closes #<ISSUE_NUMBER>`**. ⚠️ Note: closing keywords only auto-link/auto-close for PRs targeting the repo's **default branch** (`main`). Because v2 PRs target `v2/main` (a non-default branch), `Closes #N` there is only a cross-reference — it will **not** create a hard link or close the issue on merge. (There is no `gh` flag for manual linking — `gh pr edit` has no `--add-issue`; closing keywords are the only mechanism GitHub exposes, and they're gated to the default branch.)
- **On merge of a v2 PR, manually close its issue and move the board item to Done** (option id `248a3910`), since auto-close won't fire on `v2/main`. Keep the `Closes #N` line anyway so the issues close automatically if/when `v2/main` is eventually merged to `main`.
- If new tasks are discovered or requested during development, create issues and add them to the board.
Expand All @@ -173,23 +173,23 @@ gh project field-list 28 --owner modelcontextprotocol --format json \
| Project node ID | `PVT_kwDOCt2Azc4BJVxt` |
| Status field ID | `PVTSSF_lADOCt2Azc4BJVxtzg5iI8c` |

Status option IDs (`--single-select-option-id`) — **last verified 2026-07-18** (the `Building …` and `MCP Apps Extension` columns were removed; their old IDs `4ac261ee` / `c28da89f` / `73d0b807` are now rejected):
Status option IDs (`--single-select-option-id`) — **last verified 2026-07-27**. `V2 Go Live` was added via the web UI on 2026-07-27 for the go-live phases (#1804); the other four IDs were unchanged by that addition, confirming the web-UI path is safe (see the ⚠️ hazard below). Removed columns whose IDs are now rejected: `SDK V2 + New Spec` (`1bbb6f57`), `Building CLI / TUI / CORE` (`4ac261ee`), `Building Web` (`c28da89f`), `MCP Apps Extension` (`73d0b807`).

| Status | Option ID |
| --- | --- |
| Todo | `fbdaf21e` |
| SDK V2 + New Spec | `1bbb6f57` |
| V2 Go Live | `b3a6966e` |
| In Progress | `195df262` |
| In Review | `159c8a02` |
| Done | `248a3910` |

Use **Todo** for approved-but-not-started work, **In Progress** for general active work (regardless of surface), **SDK V2 + New Spec** for cards in that stack, **In Review** once a PR is open, and **Done** on merge.
Use **Todo** for approved-but-not-started work, **In Progress** for general active work (regardless of surface), **V2 Go Live** for cards in the go-live phases (#1804), **In Review** once a PR is open, and **Done** on merge.

> ⚠️ **Never add, rename, or remove a board column (Status option) with the `updateProjectV2Field` GraphQL mutation unless you pass every existing option's `id`.** That mutation does a **full replace** of the option list: if you resend options by name/color/description but omit their `id`s, GitHub **deletes all existing options and mints new ones**, which **orphans the Status of every card on the board** (all items go blank) *and* invalidates every option id in the table above. This has happened once (required reconstructing ~197 items' statuses by inference). Safe alternatives, in order of preference:
> 1. **Add/rename/remove a column in the GitHub web UI** (Project #28 → Status field settings). This preserves ids of untouched options and never orphans cards.
> 2. If you must script it, first `gh api graphql` the current options **with their `id`s**, then call `updateProjectV2Field` echoing back every existing option **including its `id`**, appending only the new one. Verify afterward that no card lost its Status.
>
> `gh project item-add` and `gh project item-edit` are always safe — they set a card's value and never touch the field schema. When option ids change for any reason, **re-verify and update the table above** (and the `248a3910` / `195df262` references in the recipes below and the merge step above).
> `gh project item-add` and `gh project item-edit` are always safe — they set a card's value and never touch the field schema. When option ids change for any reason, **re-verify and update the table above** (and the `248a3910` / `195df262` / `159c8a02` references in the recipes below and the merge step above).

```sh
# 1. Add an issue to the board — prints the item id (PVTI_…); capture it.
Expand All @@ -210,6 +210,16 @@ ITEM_ID=$(gh project item-add 28 --owner modelcontextprotocol --url <issue-url>
gh project item-edit --project-id PVT_kwDOCt2Azc4BJVxt --id "$ITEM_ID" --field-id PVTSSF_lADOCt2Azc4BJVxtzg5iI8c --single-select-option-id 195df262
```

For an issue **already on the board** (moving an existing card, e.g. to **In Review** when its PR opens), look its item id up by issue number instead of re-adding it. Keep `--limit` above the board's item count (~200 as of 2026-07-27) — past it `item-list` truncates silently, `select` matches nothing, and `item-edit --id ""` fails with an opaque node-resolution error rather than saying the limit was too low:

```sh
# --limit must stay above the board's item count (~200 today) — past it the
# list truncates silently and item-edit fails with an opaque node-resolution error.
ITEM_ID=$(gh project item-list 28 --owner modelcontextprotocol --format json --limit 500 \
--jq '.items[] | select(.content.number==<ISSUE_NUMBER>) | .id')
gh project item-edit --project-id PVT_kwDOCt2Azc4BJVxt --id "$ITEM_ID" --field-id PVTSSF_lADOCt2Azc4BJVxtzg5iI8c --single-select-option-id 159c8a02
```

### Always test new or modified code
- Ensure all code has corresponding tests
- Ensure test coverage for each file is at least 90%
Expand Down
Loading