name: git-style description: Load before any git commit, git push, PR creation, or PR editing in ~/vercel/* repositories. Load this skill as a prerequisite, not an afterthought.
Git Style — PR and Commit Conventions
Enforces matchai's PR title, commit message, and PR body conventions derived from Vercel repo history.
Commit Messages
Style Selection by Repo Type
| Repo Type | Style | Example |
|---|---|---|
| Monorepo with conventional commits | type(scope): message |
feat(agent): add skill loading |
| Monorepo without conventional commits | [scope] Message |
[subscriber-omniagent] Add webhook forwarding |
| Single-package repo | Plain imperative | Fix session page 404 for GitHub thread sessions |
Detection: Check git log -30 --oneline before committing. Match the dominant style.
Rules (all styles)
- Never amend commits. Always create new commits to fix issues
- Imperative mood: "Add", "Fix", "Replace" — never "Added", "Fixes", "Replacing"
- Lowercase after conventional prefix:
feat(agent): add ...notfeat(agent): Add ... - Sentence case for plain style:
Fix the thingnotfix the thing - No trailing period
- First line under 72 chars
- No emojis
Conventional Commit Types
Only use when the repo already uses them (check git log first):
| Type | When |
|---|---|
feat |
New capability |
fix |
Bug fix |
refactor |
Code restructuring, no behavior change |
chore |
Dependencies, config, CI |
docs |
Documentation only |
test |
Test additions/changes only |
perf |
Performance improvement |
Scope
- Scope = workspace directory or package name:
agent,web,knowledge,flags,evals - For service-level commits in api/infra:
[subscriber-omniagent],[secrets-management] - Omit scope if change spans the entire repo or doesn't fit a single area
PR Titles
PR titles follow the same style as commit messages. Check git log -30 --oneline and match the dominant style. If the repo uses conventional commits, the PR title should too.
Monorepo without conventional commits (vertex, api, infra)
Format: [scope] lowercase description
[agent] replace tsvector page collection search with LLM filtering
[web] add responsive right panel for mobile
[knowledge] prevent cache poisoning from transient fetch failures
[subscriber-omniagent] Fix webhook forward route to match omniagent endpoint
[secrets-management] add subscriber-omniagent to external ACL
- Scope = the workspace or subsystem being changed
- Lowercase after scope bracket
- No conventional commit prefix (no
feat:,fix:) - Imperative mood
Reverts
Format: Revert "[original title] (#number)"
PR Bodies
Default (most PRs)
Plain prose. No headers. Paragraphs and bullet points are enough.
Extends subscriber-omniagent's webhook enrichment to resolve the GitHub commenter to a Vercel user and mint a short-lived (15m) Vercel API token scoped to their team.
Allows Omniagent to use the Vercel CLI on behalf of the commenter — same capabilities as the Slack integration.
Also replaces the bulk of logging with tracing.
Bullets are fine inline — just don't wrap them in a ## Summary header:
Fixes the omniagent webhook forward URL from `/api/github/webhooks` to `/api/github` to match the actual route in the omniagent app.
Large (multi-system, needs subsections to stay readable)
Use bold text for subsections, not markdown headers. Headers are too heavy for PR bodies. Only reach for ### if the PR is exceptionally complex (5+ distinct areas).
Forward select GitHub webhook events for select repos to omniagent's `/api/github` endpoint.
**Approach**
Uses the existing proxy system in `src/utils/proxy/` that already forwards events to spaces, v0, grep, and code-review. Omniagent is added as another proxy target with body-aware filtering.
**Changes**
- `proxy-webhook-event.ts` — extends `ProxyTarget` with optional `enrichHeaders` hook
- `filter-event.ts` — adds `issue_comment` as allowed omniagent event
- `target-urls.ts` — adds `getOmniagentUrl()`
For features with components/modules, use a table:
| Skill | Tools |
|-------|-------|
| billing | refundInvoice, modifyInvoice |
| domains | domainAssist |
Structural elements
| Element | When | Format |
|---|---|---|
| Ticket reference | Always if ticket exists | Closes SPE-XXXX or Part of SPE-XXXX |
| Stacked PR | When building on another PR | Stacks on PR #XXXX |
| Companion PR | Cross-repo dependency | Companion PR: vercel/integrations -- slug |
Multiline PR bodies with gh
- Short body: use
$'...'so\nbecomes real newlines.gh pr create --body $'First paragraph\n\nSecond paragraph\n- bullet' - Long body: write Markdown to a temp file and pass
--body-file.
If GitHub shows literal \n, the body was quoted wrong.
What NOT to do
- No
##headers — use###at most, and only for large/complex PRs - No emojis
- No "This PR..." preamble — jump straight into the substance
- No list of changed files — don't enumerate filenames in the description
- No screenshots unless UI change
- Don't restate the title in the body
- No hard line wraps in PR bodies
Re-Signing Unsigned Commits
Some orgs require verified (GPG/SSH-signed) commits. When a branch contains unsigned commits (from tools, collaborators, or automated workflows), the push will be rejected. Re-sign before pushing.
Re-sign all commits on a branch
git rebase --exec 'git commit --amend --no-edit -S' -i <base>
<base> is the commit where the unsigned commits start (e.g., main, HEAD~5, or a specific hash). This re-signs every commit after <base> using your signing key.
- If conflicts occur, resolve normally (
git add+git rebase --continue) - Push with
--force-with-leaseafterward (commits are rewritten) - Verify with
git log --format='%h %G? %s'(G= good signature)
Re-sign during merge
If you're merging an unsigned branch and want to preserve individual commits (not squash), rebase the branch onto your target first:
git rebase --exec 'git commit --amend --no-edit -S' -i <target> <unsigned-branch> --onto <target>
Then fast-forward merge. If you only need to sign the merge commit itself:
git merge --no-ff -S <branch>
PR Maintenance
When a meaningful change is made to a PR after creation (new commits, scope change, added/removed features), update the PR title and body to reflect the current state.
- Before editing, run
gh pr view <number>to read the current title and body — match the existing tone and structure - Title should describe the full scope of the PR, not just the initial commit
- Body should be rewritten, not appended to — the description should always read as a fresh summary of the PR's current content
- Don't update for trivial fixups (typos, lint fixes) — only for changes that alter what the PR does