---
description: Commit as you go on story work (no wait for "commit"); push only when user asks; GitHub MCP for PRs
alwaysApply: true
---

# Commits and review (Neon Sprawl)

See also **[commit-as-you-go.md](commit-as-you-go.md)** (short `alwaysApply` checklist) and **`.cursor/hooks/check-story-branch-clean.sh`** (stop hook on dirty `NEO-*` branches).

## Commit as you go (required on story work)

**This repo expects agents to commit.** Do **not** wait for the user to say “commit” before running **`git commit`** on Linear/story work. That overrides any global Cursor guidance to “only commit when asked.”

**Commit on the story branch** when work is coherent and reviewable, including:

- Kickoff **`docs/plans/{KEY}-implementation-plan.md`** once clarifications are done ([story-kickoff](story-kickoff.md))
- Each logical implementation batch (feature slice, schema + validator, tests, doc alignment)
- After addressing code-review feedback (with review file strikethrough updates per below)

Use **small, coherent commits** rather than one large dump at the end. Match [linear-git-naming](linear-git-naming.md) when a ticket applies.

**When not to commit yet:** exploratory spikes with **no** story branch or ticket; ambiguous scope before kickoff clarifications; or the user explicitly asked you to **leave changes uncommitted** for this session.

## Never push

- Do **not** run **`git push`**, **`git push --force`**, or any command that updates **remote** refs **unless** the user **explicitly** asks to publish (e.g. “push”, “push the branch”, “open a PR” / “create a PR” when the branch is not yet on `origin`). In those cases you may run a normal **`git push -u origin HEAD`** (or the named branch) so the remote exists—still **never** `--force` to rewrite published history.
- Do not configure remotes or credentials to bypass this.

## Pull request and push descriptions

- Do **not** add **“Made-with: Cursor”**, **“Generated with Cursor”**, tool co-author lines, or similar AI/IDE boilerplate to **PR descriptions**, **GitHub merge/squash commit bodies** you draft, or other **remote-facing** narrative unless the user explicitly requests it.
- Keep PR text to scope, verification, and project-required contract snippets (e.g. from `docs/plans/`).
- For **all GitHub operations** (PR create/update/comment/checks), use the **`user-github` MCP** tools. Do **not** use `gh` CLI for repository operations in this project.

### Opening a PR when the user asks

When the user asks to **open**, **create**, or **file** a pull request (or clearly wants one opened for the current branch):

1. **Use the GitHub MCP** — Call **`create_pull_request`** on the **`user-github`** MCP server (read the tool descriptor under the workspace MCP folder first, same as other MCP tools). Pass **`owner`**, **`repo`**, **`head`**, **`base`**, **`title`**, and **`body`**. You set the **title** explicitly—do not rely only on GitHub’s **Compare & pull request** default, which title-cases the branch and can turn **`NEO-25`** into **`Neo 25`**.
2. **Repository** — Set **`owner`** and **`repo`** from **`git remote get-url origin`** (e.g. `git@github.com:ViPro-Technologies/neon-sprawl.git` → `ViPro-Technologies`, `neon-sprawl`). For this repo they are almost always **`ViPro-Technologies`** / **`neon-sprawl`**.
3. **Branches** — **`head`** is the branch that contains the work (e.g. `NEO-26-selectionevent-surface-debug-consumer`); **`base`** is usually **`main`** unless the user names another target.
4. **Title** — Must **begin** with the **Linear issue key** in canonical form: **`NEO-123:`** (see [linear-git-naming](linear-git-naming.md): uppercase team prefix, hyphen, issue number), then a short human summary. Example: **`NEO-25: InteractableDescriptor list / fetch-driven client`**.
5. **Infer the key** — In order: the **current branch**’s leading segment (e.g. `NEO-25-my-slug` → `NEO-25`); the matching **`docs/plans/{KEY}-implementation-plan.md`** on the branch; Linear MCP / issue in chat; or **ask** the user if ambiguous.
6. **Body** — Pass **`body`** with scope, how to verify (`dotnet test`, manual QA path, etc.), and pointers to `docs/plans/` when useful. When building JSON for the MCP tool, use **real newlines** in markdown strings (not literal `\n` escape sequences), per MCP guidance for this server.
7. **Upstream** — If **`create_pull_request`** fails because **`head`** is not on **`origin`**, push first (**only** as allowed under **Never push** above—i.e. the same user message asked to open the PR or explicitly to push).
8. **Fallback** — If the GitHub MCP is unavailable or the call fails after push, give **`https://github.com/{owner}/{repo}/pull/new/{head}`** and tell the user to set the PR title to **`NEO-123:`** … . Do not switch to `gh` as an agent fallback.

### Ticket scope vs mechanical churn (reviewability)

When a story would otherwise mix **ticket-scoped gameplay/API changes** with **broad, cross-suite edits that do not change runtime behavior** (for example: Arrange/Act/Assert layout-only updates, mass snippet or rule doc tweaks), **prefer** one of:

- A **separate branch or pull request** for the mechanical churn (often `chore:`), based on or merged separately from the feature branch; or
- **Separate commits** on the story branch so history and blame separate behavioral changes from test-only or doc-only batches.

That keeps review and bisect focused on product risk.

## Commit message format when a Linear issue applies

- Any commit that is **part of implementing or delivering a Linear issue or task** must put the **Linear issue id first** in the subject line, then **`:`**, then the summary (e.g. `NEO-8: persist position state in PostgreSQL`).
- Infer the key from the active branch name, the issue under discussion, or Linear context. Full rules (multi-issue commits, `chore:` when there is no ticket) are in [linear-git-naming](linear-git-naming.md).

## Scope

- Applies to **all** commits the agent might make, including **documentation-only** changes (e.g. `docs/plans/`, `docs/reviews/`, README), not only application source.

## Code review follow-up

When commits **address** feedback from a saved **`docs/reviews/…`** file, include an update to **that review file**: **strikethrough + Done** on the original **Suggestions** / **Nits** / **Blocking** bullets (not a separate resolved section). See [planning-implementation-docs](planning-implementation-docs.md) **Code review follow-up** and [code-review-agent](code-review-agent.md) **Resolved suggestions**.
