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
5 changes: 5 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"skills": {
"paths": [".claude/skills"]
}
}
141 changes: 141 additions & 0 deletions .claude/skills/commit-msg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Commit Message Protocol

Drafts a correctly structured commit message for this project. Invoke after completing
a unit of work and before running `git commit`.

Triggered by: `/commit-msg`

---

## Message structure

### Subject line
```
type(scope): imperative summary in present tense
```
- Max 72 characters
- Imperative mood: "add", "fix", "update" — not "added", "fixing", "updates"
- Types: `feat`, `fix`, `chore`, `docs`, `refactor`, `review`
- Scope: the subsystem, component, or file area affected (e.g. `ptt`, `panel`, `settings`)
- No trailing period
- **Never** include `Co-Authored-By` lines

### Body format
- Leave one blank line between subject and body
- Group related changes under a plain-text **section label** followed by a colon
(e.g. `Cursor companion:`, `Settings store:`, `Voice catalogue:`)
- Each point starts with `- ` and uses an em dash `—` to separate the change
from its rationale or mechanism
- Explain the **why** and **how**, not just the what
- Wrap all lines at ~72 characters
- Separate section groups with a blank line
- No bullet sub-nesting — keep it flat

### What belongs in the body
- Non-obvious decisions or constraints
- Failure modes the change addresses
- Subtle invariants a future reader would need to understand the diff
- Anything that would look arbitrary without context

### What does NOT belong
- Restatement of what the diff already shows
- References to the current task, issue number, or caller
("added for the X flow", "handles the case from issue #123") — these rot
- `Co-Authored-By` lines — ever

---

## Step 1 — Gather context

Run the following to understand what changed:
```
git diff --cached --stat
git diff --cached
git status
```

If nothing is staged, note it and ask the developer which files to include before drafting.

---

## Step 2 — Draft the message

Using the structure above, produce a complete commit message. Show it in a code block
so the developer can copy it directly.

### Choosing the type
| Situation | Type |
|-----------|------|
| New user-facing capability | `feat` |
| Bug fix or regression | `fix` |
| Build, tooling, deps, version bumps | `chore` |
| Documentation only | `docs` |
| Internal restructure, no behaviour change | `refactor` |
| Code review follow-up changes | `review` |

### Choosing the scope
Use the primary subsystem or component name affected. Examples from this codebase:
`ptt`, `panel`, `overlay`, `settings`, `voice`, `chats`, `cursor`, `ipc`, `types`, `build`

If multiple unrelated subsystems changed, consider whether this should be split into
multiple commits. If the changes are coherent, use the broadest accurate scope or omit
scope parentheses.

---

## Step 3 — Validate before presenting

Self-check before showing the draft:
- [ ] Subject ≤ 72 characters
- [ ] Present tense imperative subject
- [ ] No `Co-Authored-By` line present
- [ ] Body lines wrap at ~72 characters
- [ ] Rationale present for any non-obvious change (em dash format)
- [ ] No task/issue references in the body
- [ ] Section labels are plain text (no `##` markdown headers)

---

## Step 4 — Present and iterate

Show the draft. Ask: "Does this capture everything, or should any section be adjusted?"

If the developer requests changes, revise and re-validate before presenting again.

---

## Example (from this project's git history)

```
feat(sprint/v1.3.0): cursor companion, voice catalogue, chat export

Cursor companion:
- Add CursorCompanion.tsx — floats near the system cursor so the
overlay stays visible without covering active UI elements.
- Wire IPC channel for position updates — renderer polls on a 100ms
interval to keep latency imperceptible without saturating the main
process.

Voice catalogue:
- Extend VoiceTab with per-voice preview — lets users audition a voice
before committing; avoids settings round-trips.
- Add voice metadata to shared types — ElevenLabs model ID and category
fields needed downstream for the API call builder.

Chat export:
- Add export-to-clipboard action in ChatsTab — markdown format chosen
for portability; plain text would lose structural context.
- Persist export timestamp in settings-store — prevents duplicate
exports on accidental re-trigger.
```

---

## Hard constraints (always enforce)

- **Never include `Co-Authored-By`** — this project explicitly prohibits it
- **Never generate a subject line over 72 characters** — truncate scope or
rephrase rather than exceed the limit
- **Never use markdown in the commit body** — no `##`, `**bold**`, or backtick
code fences; plain text only
- **Never reference issue numbers, PR numbers, or task IDs** in the body
99 changes: 99 additions & 0 deletions .claude/skills/merge-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Merge Flow Protocol

Enforces the project's GitFlow PR routing rules. Invoke before opening any pull request
or when unsure where a branch should target.

Triggered by: `/merge-flow`

---

## Routing rules (canonical)

```
feature/* → dev (integration; all features stabilise here)
fix/* → master (hotfix) + dev (backport)
sprint/vX → dev (then dev → master via release/*)
release/vX → master (tagged) + dev
dev → master (via release/* only — never direct)
```

**master is a production release trigger, not an integration branch.**
Every merge to master = a versioned installer build fires in CI.
The project head gates master exclusively via PR review.

---

## Step 1 — Identify current branch

Run: `git rev-parse --abbrev-ref HEAD`

Classify the branch by prefix:

| Branch pattern | Correct PR target | Notes |
|----------------|-------------------|-------|
| `feature/*` | `dev` | Standard feature work |
| `sprint/vX.X.X`| `dev` | Port/selective rebase off master |
| `fix/*` | `master` + `dev` | Hotfix: merge to master (tagged), backport to dev |
| `release/vX.X.X`| `master` + `dev` | RC branch: merge to master (tagged), sync dev |
| `dev` | Never directly | Only via a `release/*` branch |
| `master` | Never | Production; no outbound PRs |
| anything else | Warn + confirm | Non-standard name — clarify intent |

---

## Step 2 — Validate the target

If the developer states or implies a PR target, check it against the table above.

### If target is correct:
Confirm: "Branch `[name]` → `[target]` is correct per GitFlow rules. Proceed."

### If target is `master` and branch is NOT `fix/*` or `release/*`:
Block and warn:
> "Direct merge to master is not allowed for `[branch-type]` branches.
> master is a production release trigger gated by the project head.
> Correct target for `[branch]` is `dev`.
> Open the PR against `dev` instead."

### If target is `dev` and branch is `fix/*`:
Warn:
> "Hotfixes must merge to `master` first (with a version tag), then backport to `dev`.
> If you merge only to `dev`, the fix will not ship until the next release cycle."

---

## Step 3 — Pre-PR checklist

Before the developer opens the PR, run through:

1. **Branch is aligned** — suggest running `/sprint-align` if branch is `sprint/vX.X.X`
2. **No direct commits to master or dev** — confirm work is on a proper branch
3. **Version bump** — for `release/*` branches only: confirm `package.json` version
is updated before merging to master
4. **Changelog** — `.changelog/` is gitignored and local only; do not attempt
`git add .changelog/`
5. **Commit messages** — suggest `/commit-msg` if any commits on this branch
need to be cleaned up before the PR

Report checklist status: which items pass, which need attention.

---

## Step 4 — PR description guidance

Remind the developer:
- PR title should follow the same conventional prefix as commits: `feat(scope): ...`
- PR body should summarise the WHY, not just the what
- For `release/*` → `master` PRs: include the version tag that will be applied post-merge
- The project head reviews all PRs into master; do not merge without approval

---

## Hard constraints (always enforce)

- **Never create, merge, or push PRs to master autonomously**
- **Never suggest bypassing the project head's review gate**
- **Never commit directly to `master` or `dev`** — always branch
- If asked to "just push to master directly", refuse and explain the release trigger risk:
> "Every master merge fires a CI build and ships a versioned installer.
> Unreviewed code reaching master is a production incident, not a shortcut."
110 changes: 110 additions & 0 deletions .claude/skills/new-branch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# New Branch Protocol

Creates a correctly named, correctly based branch for any GitFlow work type.
Invoke before starting any new unit of work.

Triggered by: `/new-branch`

---

## Branch types, bases, and naming

| Work type | Branch pattern | Base branch | Example |
|-----------|---------------|-------------|---------|
| New feature or experiment | `feature/<short-description>` | `dev` | `feature/voice-preview` |
| Bug fix on live production | `fix/<short-description>` | `master` | `fix/ptt-mic-stuck` |
| Release candidate / QA | `release/vX.X.X` | `dev` | `release/v1.2.0` |
| Upstream redesign port | `sprint/vX.X.X` | `master` | `sprint/v1.2.0` |

**Rules:**
- `feature/*` and `release/*` always base off `dev` — never master
- `fix/*` always base off `master` — hotfixes must ship without carrying unreleased dev work
- `sprint/*` always base off `master` — selective port after upstream redesign
- Descriptions use kebab-case, no version numbers in feature names
- Keep names short and unambiguous (3–5 words max)

---

## Step 1 — Clarify intent

Ask the developer:
> "What are you building? (feature / hotfix / release candidate / sprint port)"

If the developer describes the work without naming a type, infer from context:
- "add X feature" → `feature/*` off `dev`
- "fix a bug in prod" → `fix/*` off `master`
- "start the next sprint" → `sprint/vX.X.X` off `master`
- "prep a release" → `release/vX.X.X` off `dev`

Confirm the classification before proceeding:
> "This sounds like a `feature/*` branch. Correct?"

---

## Step 2 — Confirm base branch is current

Run: `git fetch origin --quiet --prune`

Then check the intended base is up to date locally:
```
git log --oneline HEAD..origin/<base-branch> | head -5
```

If the local base is behind origin, warn:
> "Your local `[base]` is behind origin by [N] commits. Update it first:
> `git checkout [base] && git pull --ff-only`"

Do not proceed until the developer confirms the base is current.

---

## Step 3 — Suggest branch name

Propose a name following the pattern. Use the developer's description, kebab-cased:

> "Suggested branch name: `feature/voice-preview`
> Base: `dev`
> Command: `git checkout -b feature/voice-preview dev`"

Ask: "Does this name work, or would you like to adjust it?"

---

## Step 4 — Output the exact command

Once name and base are confirmed, output the single command to run:

```
git checkout -b <branch-name> <base-branch>
```

**Do not run this command.** Present it for the developer to execute.

After the developer confirms the branch is created, suggest running `/sprint-align`
for `sprint/*` branches, or remind them that `/merge-flow` will validate the PR
target when they're ready to open a PR.

---

## Step 5 — Post-creation reminder

Once the branch exists, state:
> "Branch `[name]` created off `[base]`. When you're ready:
> - `/commit-msg` — draft a structured commit message
> - `/merge-flow` — confirm your PR target before opening a PR"

For `sprint/*` branches specifically, add:
> "Run `/sprint-align` now to confirm this branch is current with master."

---

## Hard constraints (always enforce)

- **Never base a `feature/*` branch off `master`** — unreleased features
must not bypass the `dev` integration gate
- **Never base a `fix/*` branch off `dev`** — hotfixes must not carry
unreleased dev work into production
- **Never create branches directly on `master` or `dev`** — those branches
receive merges, they do not originate work
- **Never run `git checkout -b` autonomously** — always present the command
and let the developer execute it
Loading
Loading