geeknative

04Reference

Contracts

The format of every file in contracts/, its validation rules, and the code it generates on each platform.

contracts/ holds everything that must be identical in all three apps. make gen validates it and generates platform code. Generated files are committed and never edited by hand.

app.json

{
  "name": "GeekNative",
  "id": "com.example.geeknative",
  "version": "1.0.0",
  "build": 1,
  "defaultLocale": "en"
}
Field Rule Becomes
name Not empty; no $, // or line breaks The display name on iOS and Android, and the web page title
id Reverse-DNS, like com.acme.notes iOS bundle ID and Android application ID
version Like 1.0.0 iOS marketing version, Android versionName
build A whole number, 1 or more iOS build number, Android versionCode
defaultLocale A language code like en or pt-BR; defaults to en The source locale for strings

In code: AppIdentity.name and AppIdentity.version (iOS), AppIdentity.NAME and AppIdentity.VERSION (Android), AppIdentity.name and AppIdentity.version (web).

tokens.json

{
  "color": {
    "primary": { "light": "#4F46E5", "dark": "#A5B4FC" },
    "onPrimary": { "light": "#FFFFFF", "dark": "#1E1B4B" }
  },
  "spacing": { "xs": 4, "sm": 8, "md": 12, "lg": 16, "xl": 24, "xxl": 32 },
  "radius": { "sm": 6, "md": 10, "lg": 16, "full": 9999 },
  "typography": {
    "title": { "size": 20, "lineHeight": 26, "weight": 600, "ios": "title3", "android": "titleLarge" }
  },
  "font": { "family": "system" }
}

Names are camelCase letters and digits starting lowercase, and can't be reserved words in Swift, Kotlin or TypeScript (like default or class).

Colors are #RRGGBB or #RRGGBBAA. dark is optional and defaults to light. These colors are required: background, onBackground, surface, onSurface, surfaceVariant, onSurfaceVariant, primary, onPrimary, outline, error and onError. You can add more.

Spacing and radius values are numbers of points (iOS), dp (Android) or pixels (web). A radius of 9999 or more is fully rounded on the web.

Typography entries need:

Field Rule
size, lineHeight Positive numbers (sp on Android, converted to rem on web)
weight 100, 200, ... 900
ios The Dynamic Type style it maps to: largeTitle, title, title2, title3, headline, subheadline, body, callout, footnote, caption, caption2
android The Material 3 type style it fills: displayLarge to displaySmall, headlineLarge to headlineSmall, titleLarge to titleSmall, bodyLarge to bodySmall, labelLarge to labelSmall

A body style is required. On iOS, sizes come from Dynamic Type for the mapped style, so text follows the user's text size setting.

Font family must be "system" for now.

Generated

Token iOS Android Web
Colors AppColors.primary (adapts to dark mode) and the global accent color AppTheme.colors.primary, mapped onto Material 3 roles; @color/token_primary resources with night variants --color-primary in a Tailwind @theme: bg-primary, text-on-primary
Spacing AppSpacing.md AppSpacing.md --spacing-md: p-md, gap-md
Radius AppRadius.lg AppRadius.lg, and Material 3 shapes --radius-lg: rounded-lg
Type AppTypography.title AppTypography.title, and Material 3 typography --text-title: text-title

On Android, screens and app bars sit on background (as on iOS) and surface is used for cards. A color named after another Material 3 role (like secondary) replaces that role's default. On the web, the theme also defines shadcn/ui's variable names (foreground, card, muted, border, ...) mapped onto the tokens, so shadcn/ui components pick up the design. Dark values apply when <html> has the dark class.

strings/

One JSON file per locale: contracts/strings/en.json, contracts/strings/fr.json, and so on. The default locale's file (from app.json) is the source; other files translate its keys.

{
  "settings.title": "Settings",
  "settings.about.version": "Version {version} ({build:int})",
  "notes.count": { "one": "{count} note", "other": "{count} notes" }
}
Rule Detail
Keys Dot-separated camelCase words: settings.appearance.title. Two keys can't map to the same name. app.name isn't allowed (the name comes from app.json).
Placeholders {name} is a string, {name:int} an integer.
Plurals An object with zero, one, two, few, many and other forms. other is required, and the only placeholder allowed is {count}.
Translations Must use the same placeholders and plural shape as the source, and can't add keys the source doesn't have. Missing keys fall back to the source.

Generated

Key iOS Android Web
settings.title Strings.settingsTitle stringResource(R.string.settings_title) strings.settingsTitle
settings.about.version Strings.settingsAboutVersion(version:build:) stringResource(R.string.settings_about_version, version, build) strings.settingsAboutVersion({ version, build })
notes.count Strings.notesCount(count:) pluralStringResource(R.plurals.notes_count, count, count) strings.notesCount(count)

Files: App/Generated/Localizable.xcstrings and Strings.swift on iOS; res/values/generated_strings.xml (plus values-fr, values-pt-rBR, values-b+zh+Hans and so on) on Android, which also gets app_name; src/generated/strings.ts on web, with setLocale().

icons.json

{
  "settings": { "ios": "gearshape", "android": "Icons.Filled.Settings", "web": "Settings" },
  "back": { "ios": "chevron.backward", "android": "Icons.AutoMirrored.Filled.ArrowBack", "web": "ArrowLeft" }
}
Field Value
ios An SF Symbol name
android A Material icon: Icons.Filled.Name, Icons.Outlined.Name, Icons.Rounded.Name, Icons.Sharp.Name or Icons.TwoTone.Name, optionally with AutoMirrored. after Icons.
web A Lucide icon component name, like Settings

In code: Image(systemName: AppIcon.settings) on iOS, Icon(AppIcons.settings, contentDescription = ...) on Android, and <AppIcons.settings className="size-6" /> on web.

All generated files

Platform Files
iOS apps/ios/App/Generated/: AppIdentity.swift, Tokens.swift, Strings.swift, Icons.swift, Localizable.xcstrings, Colors.xcassets (accent color); apps/ios/Config/Identity.xcconfig
Android apps/android/app/src/main/kotlin/app/generated/: AppIdentity.kt, Tokens.kt, Icons.kt; res/values/generated_colors.xml, res/values-night/generated_colors.xml, res/values*/generated_strings.xml; apps/android/app/identity.properties
Web apps/web/src/generated/: app.ts, tokens.css, strings.ts, icons.ts

Validation errors

Problems are reported with the file and field, so an agent can fix them directly:

✖ contracts/tokens.json color.primary.light must be a hex color like "#4F46E5" or "#4F46E5CC" (got "#4F46E").
✖ contracts/strings/fr.json "settings.about.version" must use the same placeholders and plural shape as en.json.
✖ contracts/icons.json "star" needs "android": a Material icon like "Icons.Filled.Settings" or "Icons.AutoMirrored.Filled.ArrowBack".