Brand from codebase
Overview
The product repo is the only source of brand truth. A brand kit is extracted once into marketing-videos/<brand>/brand.md, every value carries its source file:line, and the file records the repo commit it was read at so it can be refreshed instead of re-read.
brand.md contract
Write these sections, in this order. Every value ends with its source as (path:line).
- Sources: repo paths, branch,
git rev-parse --short HEADper repo, extraction date, and one machine-readable block per repo that pipeline gate G1 reads to detect a stale kit:```refresh repo: <product-repo> ref: HEAD commit: c8fb26e paths: src/data/content.ts src/app/globals.css public/brand ```repois the folder name underD:\Projects. A repo that is not git usesmtime: <ISO date>instead ofrefandcommit. - Identity: name, one-line positioning, tagline, tone (quote the copy file, do not paraphrase).
- Color tokens: semantic brand tokens first (
--color-brand-*,primary,AppColors.primary), then supporting tokens. One table per surface when they differ:landingvsapp. - Typography: per surface. Landing fonts often differ from app fonts; check both the root layout and any section-level
fonts.ts. - Logos and imagery: file paths, which are real product renders vs stock photos (stock must never be presented as real users), and their license or credit file.
- Allowed claims: features, modes, pricing, CTA labels, URLs, contact. Each a direct quote with source. Mark sample data as
SAMPLE(renders with dummy numbers) so a video labels it "Contoh". - Forbidden claims: anything that sounds plausible but has no source: user counts, revenue, ratings, testimonials, partner logos, "terpercaya", "#1".
- Capture targets: production and staging URLs, routes worth capturing, app screenshot folders, Play Store URL.
- Ambiguities: duplicate or conflicting tokens, copy that differs between site and app, values a brief elsewhere uses that the code contradicts. List them for the user; never resolve silently.
Extraction checklist
| Look for | Typical places |
|---|---|
| Copy, CTAs, pricing | src/data/content.ts, src/content/*.ts, landing section components, RELEASE_NOTES.md, docs/features/ |
| Web tokens | globals.css @theme / :root, tailwind.config.*, palette.ts |
| Flutter tokens | lib/core/constants/app_colors.dart, app_text_styles.dart, pubspec.yaml fonts |
| Fonts | app/layout.tsx (next/font), section fonts.ts, pubspec.yaml |
| Logos | public/brand/, docs/brand/, assets/icons/brand/ |
| URLs | grep -rn "https://<brand-domain>" across src/, metadataBase, site.ts, terms pages |
Search for a value before declaring it missing: grep the domain, the CTA text, and the token name across the whole src/.
Skip .env*, .mcp.json, google-services.json, keystores, and any key or token. Never copy their values into brand.md.
When the source repo is not checked out (cloud sessions)
Gate G1 reports brand_repo_absent as info and G2 verifies every claim against the exact quotes in brand.md instead of the repo (claim_verified_brand_kit). That only works when brand.md quotes copy verbatim with path:line, so extract quotes literally, never paraphrased. Refreshing brand.md needs the repo: do it on the laptop, or add the product repo to the cloud session and point MV_PROJECTS_ROOT at its parent folder.
Refresh rule
Gate G1 runs git -C <repo> log --oneline <commit>..<ref> -- <paths> for every refresh block and fails with brand_stale when anything changed. To fix it, re-read only the changed files, update their rows, and bump commit in the block. Non-git repos are compared by file modified time against mtime.
Capturing real UI
| Product surface | Method |
|---|---|
| Live website | HyperFrames website capture from the production URL (the product-launch-video route does this); staging only when the user says the feature is unreleased |
| Local dev server | Only when the user asks for an unreleased screen; label it unreleased in the brief |
| Flutter app | Existing real screenshots (site screens/, Play Store assets) or emulator screenshots, placed in a device frame |
| Small animated elements (CTA button, stat card) | Rebuilt as HTML with the brand.md tokens; never invent a screen that does not exist |
Storyboard claim references
Every on-screen claim in STORYBOARD.md carries its brand.md source, for example "Biaya layanan 2%" (<product-repo>/src/data/content.ts:212). A claim without a source is cut from the storyboard, not softened.
Common mistakes
- Picking the first navy found (
--navy-main) instead of the semantic brand token (--color-brand-navy). Prefer semantic names and list the other as an ambiguity. - Using app fonts for a landing-page video, or the reverse.
- Declaring a URL "not found" after checking one file.
- Showing stock photos as if they were customers.