A cross-platform UI contract gives AI coding agents fewer ways to break your app
AI coding agents can produce a plausible screen quickly. The harder problem is preserving the agreements that make an app feel like one product on web, iOS, and Android. A cross-platform UI contract makes those agreements explicit: share meaning, states, tokens, and acceptance checks; allow platform-specific composition when the device requires it.
The contract should be short enough to load before a task and precise enough to review after it. It is not a giant style manual. It is a decision surface for the moments when an agent is about to invent a new spacing value, omit a loading state, or copy a desktop interaction onto a phone.
Start with user-visible promises
Write the contract in terms of what users should experience, not only component names. A name tells an agent what to import. A promise tells it how to choose when several implementations appear possible.
Useful starting promises include:
- The primary action is recognizable and predictable on every supported platform.
- Important status changes have a visible and accessible representation.
- Form errors appear next to the field that needs attention.
- Destructive actions require an intentional gesture or confirmation.
- Loading preserves the user’s context instead of making the screen jump.
- Touch targets remain comfortable on small screens.
- The same task uses the same words and state meanings everywhere.
Connect each promise to the implementation evidence that proves it. “The primary action is clear” can map to a semantic action token, a required button state, and a review check for narrow and wide layouts. This is more useful than telling an agent to “make the page consistent.”
Keep the first version to roughly five to ten promises. A contract that describes every visual detail becomes background noise. Add a rule when repeated ambiguity creates rework, not because a document feels incomplete.
Name intent, not appearance
Agents copy the nearest example. If the nearest example contains arbitrary values, that decision becomes the next example’s convention. Give the agent a small vocabulary based on intent.
export const space = {
xs: 4,
sm: 8,
md: 16,
lg: 24,
xl: 32,
} as const
export const color = {
surface: "#FFFFFF",
text: "#17202A",
mutedText: "#667085",
action: "#E85D2A",
danger: "#C9372C",
} as constThe exact values matter less than the boundary. color.action communicates a product role. color.blue500 communicates only what the value looks like today. Tell the agent to use an existing semantic token by default and to propose a new token only when no current role expresses the requirement.
Do the same for spacing, type, shape, emphasis, motion, and component states. Keep naming stable across the codebase. A token that changes names every few screens is not a contract; it is another source of translation work.
One codebase. iOS, Android, and web.
The Fitness Kit ships with auth, a database, and a backend already connected — no setup. Live demo at fitness-preview.otf-kit.dev.
Share behavior while allowing platform expression
Cross-platform does not mean identical pixels. It means that meaning, content hierarchy, state transitions, and product rules stay stable while the input method and layout can fit the device.
Document the boundary explicitly:
| Share across platforms | Allow to vary by platform |
|---|---|
| Component purpose | Navigation composition |
| Content hierarchy | Sidebar, tab bar, or action sheet |
| Required states | Keyboard focus or touch feedback |
| Semantic tokens | Dense table or stacked rows |
| Validation behavior | Pointer, keyboard, or gesture input |
This prevents two opposite agent mistakes. The first is forcing a desktop layout onto a narrow screen. The second is creating separate implementations whose behavior drifts because mobile and web were treated as unrelated products.
A primary action can be a sidebar item on a wide screen and a tab or prominent control on a phone. It should still have the same label, permission rule, loading behavior, and success state. Share the contract; vary the composition only where the platform requires it.
The React Native accessibility documentation makes this distinction concrete: Android and iOS provide different assistive-technology APIs, while the cross-platform layer offers complementary properties such as labels, hints, roles, and live regions. Your contract should record both the shared requirement and the platform-specific implementation check.
Specify states before screens
A component name is not a specification. Agents commonly generate the happy path and omit what happens when a request is slow, invalid, or complete.
For a submit control, define a typed state surface before composing the screen:
type SubmitState =
| "ready"
| "focused"
| "pressed"
| "disabled"
| "loading"
| "error"
| "success"Then describe the user-visible rule for each state. loading prevents repeated submission and communicates progress. error keeps the user’s input and gives a next step. success confirms completion without removing useful context too quickly. disabled communicates why the action is unavailable without relying on color alone.
Ask the agent to implement the states before it composes the larger screen. Missing states then show up as omissions in a small union instead of subjective polish issues in a large diff.
For forms, define field-level validation, focus order, error announcement, and submit behavior. For data views, define loading, empty, partial, stale, and failed states. For destructive actions, define confirmation, cancellation, and post-action recovery. These decisions reduce the number of times an agent has to guess.
Give the agent a repeatable working sequence
A contract works when it tells an agent how to decide, not just what the final code should resemble. Use a fixed sequence in project instructions or task prompts:
- Identify the user task and primary action.
- Find the closest existing component and screen pattern.
- Reuse semantic tokens and required states.
- Decide which layout choices are shared and which are platform-specific.
- Implement the smallest composition that satisfies the task.
- Check narrow, wide, loading, empty, error, and success conditions.
- Report every new token, component, or exception before calling the work complete.
The nearest example matters. Organize examples by reusable pattern, use descriptive filenames, and add a short “when not to use this” note for components with narrow purposes. Make the preferred path easier to discover than the exception path.
A useful task brief can be compact:
Add the account settings form.
Use the existing form field and primary action patterns.
Reuse semantic spacing and color tokens.
Preserve loading, invalid, and success states.
Keep the content hierarchy shared across web and mobile.
Allow navigation composition to vary by platform.
Before finishing, report new tokens, exceptions, and checks run.For more repository-level guidance, see why repository conventions matter for AI coding agents. The contract is most effective when the agent can find it before it starts editing.
Make exceptions visible and safe
No design system covers every product decision. The contract should make exceptions reviewable instead of pretending they will not happen.
Require the contributor to state:
- Which rule is being bypassed.
- Why an existing pattern is insufficient.
- Whether the exception is platform-specific or shared.
- What user problem it solves.
- Whether it should become a reusable pattern.
- How the exception will be tested.
This creates useful friction without blocking experimentation. It gives reviewers a precise question: is this genuinely new product behavior, or did the contributor miss an existing primitive?
Keep the exception near the code and easy to search. A short decision record or component note is better than an undocumented convention known only to the person who added it. When an exception appears three times, consider promoting it into a reusable pattern and updating the contract.
Turn the contract into evidence
The final part of the contract is a checklist another person or agent can run. A practical review should ask:
- Does the screen use semantic tokens rather than unexplained constants?
- Are all required component states represented?
- Does the primary action remain clear at supported widths?
- Do empty, loading, error, and success states preserve user context?
- Can keyboard and assistive-technology users reach and understand controls?
- Are touch targets and gestures appropriate for mobile?
- Does the implementation reuse an existing pattern where one exists?
- Are platform differences intentional and documented?
- Were new tokens and exceptions called out explicitly?
Use platform documentation as a primary reference rather than relying on a generic “responsive” label. Apple’s accessibility documentation and the React Native reference provide starting points for platform checks; your own contract should add the product-specific requirements.
Put the checklist in the agent’s completion response. “I reused the form field primitive, added invalid and loading states, verified the compact layout, and documented one platform-specific navigation choice” is useful evidence. “The screen is consistent” is not.
OTF’s free MIT SDK is one example of this approach: the same component name, props, and look are designed to work across web, iOS, and Android, while design tokens provide one theme across platforms. The OTF templates page is the verified place to inspect the current options.
A cross-platform UI contract is the smallest set of decisions that prevents predictable drift when work is distributed across people and AI coding agents. Start with one product surface and a handful of high-frequency components. Add rules where ambiguity creates rework, remove rules that no longer guide decisions, and review the contract whenever the product changes.
The payoff is not identical pixels. It is a shared product language that survives parallel implementation: agents can move quickly, developers can review against explicit expectations, and users get an interface that behaves intentionally wherever they encounter it.
Sources
Stop wiring. Start shipping.
- Login, database, and backend already connected — nothing to set up
- iOS + Android + web from one codebase
- AI configs pre-tuned + 40+ tested prompts included