Never push directly to main. All changes must go through a pull request:
- Always create a branch specific to the change before committing:
feat/,fix/,docs/,chore/,test/, etc. - Push the branch and open a PR — never
git push origin main. - If you find yourself on
main, create a branch first:git checkout -b <branch-name>.
Any change to website copy, essays, docs text, UI strings, or marketing content must follow the brand voice guide:
- Read
docs/brand_tone_voice.mdbefore writing or editing any copy. - The full quality checklist is at the bottom of that file — run every item before committing content changes.
Key rules that are easy to miss:
| Rule | Wrong | Right |
|---|---|---|
| Proof-first | "fast" | "15-30 tok/s on flagship devices" |
| Privacy as mechanism | "we value your privacy" | "the model runs in your phone's RAM, nothing is sent anywhere" |
| No exclamation marks | "It works!" | "It works." |
| No em dashes | "private — always" | "private - always" |
| No forbidden words | revolutionary, seamlessly, empower, leverage, robust, comprehensive, crucial, pivotal, delve, tapestry, testament, underscore, foster, cultivate, showcase, enhance | use specific, plain words instead |
| No AI slop phrases | "serves as", "stands as", "represents a", "marks a turning point", "it is worth noting" | just say "is" |
| No structural clichés | "Not just X, but Y" / "It's not X, it's Y" | state the thing directly |
| No curly quotes | "private" | "private" |
The emotional arc for all content: Recognition -> Return -> Freedom. Name what's been happening, show what's being given back, hand over the capability without condition.
Any change that touches UI (screens, components, styles) must comply with the design system:
- Read
docs/design/VISUAL_HIERARCHY_STANDARD.mdbefore writing or modifying any UI code. - Check
docs/design/for any other relevant design documents. - Use
TYPOGRAPHYtokens — never hardcode font sizes or weights. - Use
COLORStokens — never hardcode color values. - Use
SPACINGtokens — never hardcode margin/padding values. - Weights must stay ≤ 400 (no bold).
- Never use emojis or emoticons in UI text — always use
react-native-vector-iconsinstead. Feather is the default; MaterialIcons is allowed only when Feather lacks a suitable icon (e.g.whatshotfor trending). - Never use
lucide-reactor any other icon library — onlyreact-native-vector-icons. - Follow the 5-category text hierarchy: TITLE → BODY → SUBTITLE/DESCRIPTION → META.
All quality gates run automatically via Husky on every git commit, scoped to the file types you staged:
| Staged file type | Checks that run automatically |
|---|---|
.ts / .tsx / .js / .jsx |
eslint (staged only), tsc --noEmit, npm test |
.swift |
swiftlint (staged only), npm run test:ios |
.kt / .kts |
compileDebugKotlin (type check), lintDebug, npm run test:android |
Requirements:
- SwiftLint:
brew install swiftlint(skipped with a warning if not installed) - Android checks require the Gradle wrapper in
android/
Before writing new code, ensure tests exist for your changes. If the hook fails, fix the issue and recommit — never skip with --no-verify.
Always write both unit tests and integration tests for new features and significant changes:
- Unit tests (
__tests__/unit/): Test individual functions, hooks, and store actions in isolation with mocked dependencies. - Integration tests (
__tests__/integration/): Test how multiple modules work together end-to-end (e.g., service A calls service B which writes to database C). Use mocked native modules but real logic across layers.
Do not consider a feature complete with only unit tests. Integration tests catch wiring bugs, incorrect data flow between layers, and lifecycle issues that unit tests miss.
When the user says "push" (or any equivalent like "ship it", "send it", "push this"), follow this full workflow:
- Write tests for any new or changed logic if they don't already exist.
- Run
npm run lint && npx tsc --noEmit && npm test— fix any failures before continuing. - Commit all staged changes with a descriptive message.
- Ensure you are NOT on
main. If you are, create an appropriately named branch first:git checkout -b feat/...orfix/...orchore/...etc.
- Push the branch:
git push -u origin <branch> - If no PR exists for this branch, create one with
gh pr create. Do NOT include "Generated with Codex" or any AI attribution in PR descriptions. - If a PR already exists, update its description to reflect all commits in the PR (not just the latest push). Read the full commit history with
git log main..HEADand write a coherent description that summarises the entire change set — what it does, why, and how.
- Wait for Gemini to review the PR (poll with
gh pr checksandgh api repos/{owner}/{repo}/pulls/{number}/reviewsuntil a review appears). - Pull down review comments:
gh api repos/{owner}/{repo}/pulls/{number}/commentsandgh api repos/{owner}/{repo}/pulls/{number}/reviews. - Address every review comment — fix the code, re-run quality gates (lint, tsc, test).
- Reply to each review comment individually using
gh api(/pulls/comments/{id}/replies). Every comment gets its own reply — do not post a single summary comment. - Push fixes, update the PR description again to stay coherent across all commits.
- Report what was changed in response to the review.
The repo has three automated reviewers on every PR. After pushing, loop until all are green:
| Reviewer | What it checks | How to address |
|---|---|---|
| Gemini Bot | Code quality, style, logic issues | Read comments via gh api, fix code or reply explaining why it's fine, then comment /gemini review to trigger a fresh pass |
| Codecov | Test coverage thresholds | Add missing tests, ensure new code is covered. Check the Codecov report for uncovered lines |
| SonarCloud | Security hotspots, code smells, duplications, bugs | Fix flagged issues — especially security hotspots and duplications. Resolve quality gate failures before merging |
Workflow:
- Push code → wait for all three reviewers to report
- Pull down Gemini comments, Codecov report, and SonarCloud findings
- Fix issues: code changes for Gemini/SonarCloud, add tests for Codecov
- Re-run local quality gates (
npm run lint && npm test && npx tsc --noEmit) - Push fixes, comment
/gemini reviewon the PR to re-trigger Gemini - Repeat until all three reviewers pass with no blocking issues