Paste this into Claude Code (or your coding agent of choice) in an empty git repo on day one, before writing any features. The goal isn't to scaffold features — it's to install the conventions, guardrails, and written standards that keep an AI-assisted codebase clean as it grows. Fill in the bracketed parts first.
You are helping me bootstrap a new iOS app called [APP NAME]. In one sentence, it does: [ONE-SENTENCE PRODUCT DESCRIPTION]. Primary users: [WHO]. It is a [FREE / PAID / FREEMIUM] app and the non-negotiable values are: [e.g. no tracking, kid-safe, privacy-first].
Do NOT start building features yet. First, set up the foundation. Work in this order and stop after each numbered step to let me review before continuing.
1. Monorepo + git hygiene.
- Create this structure:
ios/(SwiftUI app, latest iOS target),functions/(Firebase Cloud Functions v2, TypeScript, latest LTS Node),admin/(optional internal dashboard),marketing/(optional public site),infra/(Firestore rules, indexes, Storage rules),docs/. - Enforce Conventional Commits (
type(scope): lowercase subject) via commitlint. Scopes:ios,functions,admin,infra,docs. - Add Husky pre-commit hooks: SwiftLint/SwiftFormat for iOS, ESLint + Prettier for TS. Never
bypass with
--no-verify. - Rule: never commit to
main— always afeat/,fix/, orchore/branch + PR.
2. Write the instruction files BEFORE any code. These are the most important files in the repo — they are what you (the agent) read every session.
AGENTS.md— repo layout, core data flow, the Firestore schema, how to run/test each package, and the build/verify commands.CLAUDE.md— a pointer to AGENTS.md plus a "Project gotchas" section (start it empty; we will append a written rule every time we hit a bug, so the same mistake never recurs).PRODUCT.md— users, brand personality, explicit anti-references (the looks/patterns to avoid), accessibility target (WCAG 2.2 AA).DESIGN.md— color palette, type hierarchy, spacing/radius tokens, component list, do's/don'ts.
3. Firebase + iOS skeleton.
- iOS: SwiftUI with
@Observable+@Environmentdependency injection (noObservableObject). A singleAppEnvironmentroot container. Services own Firestore reads/writes; repositories are protocol-backed query abstractions; views never call Firestore directly. ADesignSystem/folder with color/spacing/typography tokens and a few reusable components — no hard-coded values. - Functions: TypeScript, all functions exported from
index.ts, secrets viadefineSecret(), admin callables gated by arequireAdminAuthhelper. Validaterequest.datashape at the trust boundary — never passunknownstraight through. Mutation callables return the canonical persisted values, not the client's payload. infra/: Firestore rules (default deny; reads/writes explicitly allowed),firestore.indexes.json(every composite-index query must be declared here, even ones created via the console URL), Storage rules.
4. The testing harness, early. Set up Firebase emulators with a committed seeded-data
snapshot, and a single command (npm run test:ui or similar) that boots the emulators from the
seed, waits for auth to be ready, runs the integration/UI suite against them, and tears everything
down pass-or-fail. Also wire iOS unit tests that run fully offline. Rule: run the whole suite
before pushing, not just the file you touched.
5. CI/CD + automated review.
- GitHub Actions: lint + test on every PR; deploy on push to the release branch.
- Add an automated PR-review Action (e.g. Claude Code Action) scoped to this stack's real risks: Firestore rules correctness, callable auth + input validation, and write atomicity.
Standing rules for the whole project (apply these unprompted):
- After we hit any non-obvious bug, append a one-paragraph rule to
CLAUDE.md's "Project gotchas" — the specific trap and the fix — so it never recurs. - Security lives in the rules, not the UI. A field hidden in the client but writable by the rules
is not protected. Gate admin-only fields with
isAdmin()server-side. - Prefer on-device / cheap paths for the common case; fall back to paid APIs only on uncertainty.
- For remote images in lists, cache + downsample — never plain
AsyncImage. - Keep heavy work (filtering, sorting, formatting) out of SwiftUI
body.
Start with step 1. Show me the structure and the commit/hook config, then stop.
This is awesome! the AI guardrails part was spot on, and we use immunity-agent which sits between claude code and your prompts for secure coding