Git
Branching, commits, stacked PRs, and the pre-commit hook.
These are general conventions any team can adopt and adapt - follow them and they should set you up for a solid, consistent workflow. They also form the basis of how we work on this project itself, so if you're contributing back to the template, see CONTRIBUTING.md for the full contribution guidelines.
Branches
Branch names follow a consistent format so the history is scannable and CI can infer intent from the name.
<type>/<issue-number>-<brief-description>
feat/EEP-123-user-invitations
fix/EEP-456-session-expiryTypes:
feat/- new featuresfix/- bug fixes- Ad-hoc (no issue):
fix/<brief-description>is fine for small isolated fixes
Commits
Commit messages follow Conventional Commits. At minimum, every commit message starts with one of:
feat: new feature
fix: bug fix
refactor: code change that neither fixes a bug nor adds a feature
chore: tooling, dependencies, config
docs: documentation only
BREAKING CHANGE: incompatible API changefeat: add user invitation flow
fix: resolve session expiry on mobile
chore: bump drizzle-kit to 0.21
docs: add git conventions pageStacked PRs
For large changes, stack branches rather than opening one giant PR. Each branch builds on the previous one, so you get smaller, reviewable diffs and can merge incrementally.
main
└── feat/EEP-100-payments-foundation ← merged first
└── feat/EEP-101-payments-ui ← depends on foundation
└── feat/EEP-102-payments-webhooks# Start from the base branch, not main
git checkout feat/EEP-100-payments-foundation
git checkout -b feat/EEP-101-payments-uiWhen the base branch merges, rebase the dependent branch onto main:
git checkout feat/EEP-101-payments-ui
git rebase mainPre-commit hook
The pre-commit hook is intentionally aggressive. If you're not used to this level of enforcement it will feel pretty heavy at first. A full typecheck, test run, and build on every commit is not typical but it's setup like this by design!
When you're working with an agent, unchecked commits are how a codebase quietly spirals. Types drift, tests go red, the build breaks and by the time anyone notices, the damage is spread across ten commits. The hook is the guardrail that keeps that from happening. It's the single most effective thing in this template for keeping agentic workflows from going off the rails.
The hook is powered by Husky and
lint-staged. Husky registers the
hook with git and runs .husky/pre-commit on every commit. lint-staged runs
ESLint and Prettier against staged files only, so you're never linting the
whole codebase, just what's about to be committed.
The hook itself is a bash script located at .husky/pre-commit.
| Trigger | What runs |
|---|---|
Any staged .ts / .tsx or config change | tsc --noEmit + full test suite + build |
package.json or pnpm-lock.yaml changed | Trivy security scan |
eslint.config.ts changed | ESLint config probe |
| All commits | lint-staged (ESLint + Prettier on staged files) |
| No relevant changes | Heavy checks skipped automatically |
Escape hatch - for intentional WIP or a TDD red phase only:
SKIP_CHECKS=1 git commit -m "wip: rough sketch"Lint, Trivy, and style still run even with SKIP_CHECKS=1. Never use it to
bypass failing tests on shippable code.