Skip to content
Merged
Show file tree
Hide file tree
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
101 changes: 101 additions & 0 deletions .claude/skills/commit-format/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
name: commit-format
description: Use when authoring, amending, squashing, fixup-ing, rebasing, or cherry-picking any git commit message in the pokemax repo — covers subject line, bullet body, backtick rules, and the ban on AI attribution.
---

# Commit format

Every commit is a subject line plus a bullet body. Measured across the last 60 commits: 188 bullets, **zero** ending in a period, **zero** prose paragraphs in a body.

Match `git log`. It is the specification.

## Subject

- **`PMX: ` prefix, always** — repo code, colon, one space, then the subject
- Imperative verb first after the prefix — `Add`, `Drop`, `Fold`, `Make`, `Give`
- Sentence case; capitalize the first word after the prefix
- Backtick every identifier, path, script, and package name
- No second prefix — no `feat:`, no `chore:`, no ticket id
- No trailing period
- Target 72 characters including the prefix; the subject body median is 53

```text
Good: PMX: Give the region model one owner in `generations.ts`
Good: PMX: Make `isObtainFile` validate the shape its consumers index
Bad: Give the region model one owner in `generations.ts`
Bad: PMX: feat: refactored the region stuff.
```

The prefix is on every hand-written commit, version bumps included — `PMX: 0.3.4`.

`(#5)` suffixes are appended by GitHub on squash-merge; never type one yourself. Commits made before this convention landed keep their bare subjects.

## Body

**The body is bullets. Nothing else.** No lede, no prose paragraph, no closing summary.

- Every line starts `- ` or is a continuation
- Start lowercase — unless the first token is an identifier or proper noun
- No trailing period, ever
- Wrap at ~72 characters; indent continuations 2 spaces
- One fact per bullet

```text
PMX: Drop the nullable expansion state from `ObtainRegions`

- `Set<string> | null` existed only because the default region was unknown
until the file loaded — inside `ObtainRegions` it is known at mount
- plain `useState<Set<string>>` with a lazy initializer replaces it
- not routed through `useExpandedRegions` on purpose: its persisted value
would carry one Pokémon's open region onto the next
```

## What the bullets say

The subject says what. The bullets say **why**, and prove it.

- Lead with the thing that changed, then what happened to it
- Use ` — ` to join a fact to its consequence
- Numbers, not adjectives — `410 lines, ~250 of them static label tables`
- Cite verification inline — e.g. verified all 1351 files in `public/obtain/` still pass
- State what was deliberately not done, and why — the `not routed through` bullet above
- Name the wrong assumption a fix corrects, not just the fix

## Backticks

This repo backticks aggressively. Sister repos do not — do not carry their lighter style here.

Backtick: identifiers, type names, file paths, directories, npm scripts, packages, CSS custom properties and class names, branch names, config keys, literal values.

## Writing the message

Use `-F -` with a quoted heredoc. Backticks inside a double-quoted `-m` string are executed by the shell.

```bash
git add <specific files>
git commit -F - <<'EOF'
PMX: Subject line here

- first bullet
- second bullet
EOF
```

## Hard rules

- **Zero AI attribution.** No `Co-Authored-By: Claude`, no "generated with", no agent or model name anywhere in subject or body.
- **One logical change per commit.** Unrelated work gets its own commit.
- **No bullet-per-changed-file.** A file list is not a rationale.

## Quick reference

| Element | Rule |
|---|---|
| Prefix | `PMX: ` — mandatory, every commit |
| Subject | Imperative, sentence case, backticked, no period, ≤72 chars |
| Body form | Bullets only — no prose lines |
| Bullet case | Lowercase, unless it opens with an identifier |
| Bullet period | Never |
| Wrap | ~72 chars, continuations indented 2 spaces |
| Content | Why over what; numbers over adjectives |
| Attribution | None, ever |
98 changes: 98 additions & 0 deletions .claude/skills/create-pull-request/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
---
name: create-pull-request
description: Use when opening a pull request in the pokemax repo, writing or rewriting a PR title or body, or editing an existing PR's description — including when the user says "open a PR", "raise a PR", "push this for review", or asks to fix up a PR description.
---

# Creating a pull request

Every pokemax PR reads the same way: a reviewer scans the title, gets the shape from the lede, and finds the detail in bullets. Match the existing PRs (#3, #5, #6) — they are the reference.

**Bullets are the default. Prose is the exception.**

## Title

- **`PMX: ` prefix, always** — repo code, colon, one space, then the title
- Sentence case; no second prefix — no `feat:`, no `chore:`, no ticket id
- Names the outcome, not the mechanics
- Backticks on every identifier, path, and package name
- No trailing period; target 72 characters including the prefix
- Same voice as the commit subjects in `git log` — the title is a commit subject for the whole branch

```text
Good: PMX: Swap lint, format, and test toolchains for `oxlint`, `oxfmt`
Bad: Swap lint, format, and test toolchains for `oxlint`, `oxfmt`
Bad: PMX: chore: various fixes and improvements.
```

## Body contract

The body is these parts, in this order:

1. **Lede** — 1–2 sentences, no heading. What the PR does and why. Link prior work as `#5` when it is a follow-up.
2. **`## What changed`** — bullets, one fact each.
3. **`## Verification`** — bullets. Commands actually run, and their results.
4. **`## Notes`** — bullets. Include only when there is something to say.

**If the change spans more than one subsystem,** replace `## What changed` with one `##` section per subsystem (`## Formatting`, `## Linting`, `## Tests`), each holding its own bullets.

**If work was deliberately left undone,** it goes in `## Notes` — never omitted.

## Bullet style

- One fact per bullet, two lines maximum
- Lead with the thing that changed, then what happened to it
- Backticks on identifiers, paths, commands, scripts, CSS vars, branch names
- Numbers, not adjectives — `130 → 143 tests`, not `more tests`
- No trailing period on a single-clause bullet; use periods when a bullet runs to two sentences
- Cite the evidence inline — e.g. all 1351 files in `public/obtain/` still pass the tightened guard

## Verification section

Report what was run, not what should pass:

- `bun run system-check` green — `format:check`, `tsc -b`, `oxlint`, 143 tests, `vite build`
- Test count before → after
- Any dataset or generated-file impact, including "none"

A red or skipped check is stated plainly, with the output. Never claim a check passed without running it.

## Notes section

The place for judgment the diff cannot show:

- Deviations from the plan or from review feedback, and why
- Adjacent problems found and deliberately not fixed
- Known limitations shipping with the change
- Why a branch exists at all, given `CLAUDE.md` defaults to `main`

## Creating it

Write the body to a file first — backticks inside a double-quoted `--body` string get executed by the shell.

```bash
cat > /tmp/pr-body.md <<'EOF'
<body>
EOF
gh pr create --base main --title "<title>" --body-file /tmp/pr-body.md
```

Editing an existing PR: `gh pr edit <n> --body-file /tmp/pr-body.md`.

## Hard rules

- **Zero AI attribution** anywhere in the title or body — no `Co-Authored-By: Claude`, no "generated with", no agent mentions
- **No test plan checkboxes**, no `🤖` footers, no emoji section headers
- **No restating the diff** — a bullet per changed file is not a summary

## Quick reference

| Element | Rule |
|---|---|
| Prefix | `PMX: ` — mandatory, every PR title |
| Title | Sentence case, backticked identifiers, ≤72 chars |
| Lede | 1–2 sentences, no heading |
| Sections | `What changed` → `Verification` → `Notes` |
| Body form | Bullets; prose only in the lede |
| Identifiers | Always backticked |
| Evidence | Numbers and command output, never adjectives |
| Attribution | None, ever |
25 changes: 21 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,26 +1,43 @@
name: CI
name: 🔁 CI

on:
pull_request:
push:
branches: ['**']
branches: [main]
workflow_dispatch:

# `pull_request` already covers branch pushes; `branches: ['**']` ran every
# PR commit twice.
concurrency:
group: ci-${{ github.ref }}
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

env:
BUN_VERSION: 1.4.0

jobs:
checks:
name: 🔍 Checks
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: 📥 Checkout
uses: actions/checkout@v4

- name: 🥟 Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
bun-version: ${{ env.BUN_VERSION }}

- name: ♻️ Restore dependency cache
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }}
restore-keys: ${{ runner.os }}-bun-

- name: 📦 Install dependencies
run: bun install --frozen-lockfile
Expand Down
18 changes: 16 additions & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Deploy to GitHub Pages
name: 🚀 Deploy to GitHub Pages

on:
push:
Expand All @@ -14,22 +14,35 @@ concurrency:
group: pages
cancel-in-progress: true

env:
BUN_VERSION: 1.4.0

jobs:
build:
name: 🏗️ Build
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: 📥 Checkout
uses: actions/checkout@v4

- name: 🥟 Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
bun-version: ${{ env.BUN_VERSION }}

- name: ♻️ Restore dependency cache
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }}
restore-keys: ${{ runner.os }}-bun-

- name: 📦 Install dependencies
run: bun install --frozen-lockfile

# Kept despite CI covering `main` — `workflow_dispatch` can deploy a
# commit CI never gated.
- name: 🧪 Test
run: bun run test

Expand All @@ -48,6 +61,7 @@ jobs:
name: 🚀 Deploy
needs: build
runs-on: ubuntu-latest
timeout-minutes: 10
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
Expand Down
5 changes: 4 additions & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
staged=$(git diff --cached --name-only --diff-filter=ACMR)
[ -n "$staged" ] || exit 0

unformatted=$(printf '%s\n' "$staged" | tr '\n' '\0' | xargs -0 bunx oxfmt --list-different)
# `|| true`: oxfmt exits 2 when no staged file is a type it formats (a
# docs-only commit). husky runs hooks under `set -e`, so the bare
# assignment would abort the commit.
unformatted=$(printf '%s\n' "$staged" | tr '\n' '\0' | xargs -0 bunx oxfmt --list-different || true)
[ -n "$unformatted" ] || exit 0

printf '%s\n' "$unformatted" | tr '\n' '\0' | xargs -0 bunx oxfmt
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ Short, opinionated rules. When something here conflicts with a default behavior,
- Commit and push **directly to `main`** after every discrete change. No feature branches, no PRs.
- One logical change = one commit. Finish the change → `git add <specific files>` → `git commit` → `git push origin main` → move on.
- Write commit messages that explain **why**, not just what.
- Follow the `pokemax-commit-format` skill (`~/.Codex/skills/pokemax-commit-format/SKILL.md`) for subject/body/backtick rules.
- Follow the `commit-format` skill (`.claude/skills/commit-format/SKILL.md`) for subject/body/backtick rules.

### Don't
- Don't open pull requests. Don't create branches.
- Don't bundle unrelated changes into one commit "to save time" — the user explicitly wants tight, change-per-commit history.
- Don't pause to confirm the push each time. Standing authorization is granted for `git push origin main` in this repo.
- Don't run `git push --force`, `git reset --hard`, or anything destructive without explicit per-action approval.
- Don't append `Co-Authored-By: Codex` (or any AI/agent attribution) to commits. See the `pokemax-commit-format` skill — zero AI mentions anywhere in the message.
- Don't append `Co-Authored-By: Codex` (or any AI/agent attribution) to commits. See the `commit-format` skill — zero AI mentions anywhere in the message.

## Imports

Expand Down
5 changes: 3 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ Short, opinionated rules. When something here conflicts with a default behavior,
- **Branch and open a PR when the user asks for one.** Branch off `main`, keep one-logical-change-per-commit inside the branch, then `gh pr create --base main`.
- Prefer one branch over several when the changes touch the same files — parallel branches that rewrite the same file just conflict.
- Write commit messages that explain **why**, not just what.
- Follow the `pokemax-commit-format` skill (`~/.claude/skills/pokemax-commit-format/SKILL.md`) for subject/body/backtick rules — PR titles and bodies too, including the zero-AI-attribution rule.
- Follow the `commit-format` skill (`.claude/skills/commit-format/SKILL.md`) for commit subject/body/backtick rules, including the zero-AI-attribution rule.
- Follow the `create-pull-request` skill (`.claude/skills/create-pull-request/SKILL.md`) for every PR title and body — it owns the section order, bullet style, and the same zero-AI-attribution rule.

### Don't
- Don't open a PR for routine work the user didn't ask to review — branches are permitted, not the default.
- Don't bundle unrelated changes into one commit "to save time" — the user explicitly wants tight, change-per-commit history.
- Don't pause to confirm the push each time. Standing authorization is granted for `git push origin main` in this repo.
- Don't run `git push --force`, `git reset --hard`, or anything destructive without explicit per-action approval.
- Don't append `Co-Authored-By: Claude` (or any AI/agent attribution) to commits. See the `pokemax-commit-format` skill — zero AI mentions anywhere in the message.
- Don't append `Co-Authored-By: Claude` (or any AI/agent attribution) to commits. See the `commit-format` skill — zero AI mentions anywhere in the message.

## Imports

Expand Down
Loading
Loading