Mobile

apps/mobile is the iOS-first Expo surface for fast intention capture, personality signal review, readiness, and the next opportunity action. The app should feel like a careful native product, not a prompt wrapper or a static landing page inside Expo.
This page describes the iOS-first interaction contract. The product flow itself lives in Mobile capture flow. The Expo UI ownership boundary and current apps/mobile wiring also belong there.

Product Rule

Every mobile interaction must reinforce the Clay contract:
  • Capture intentions as first-class inputs: goals, constraints, timing, readiness, and desired direction.
  • Treat personality as fit context, not entertainment.
  • Move users toward an opportunity action, not an endless chat loop.
  • Share translated fit signals and constraints only with consent.
  • Prefer tactile, decisive flows over large explanatory screens.

Interaction Standards

Expo UI Baseline

Use Expo UI when the control maps cleanly to a native iOS input or action.
  • Import universal controls from @expo/ui for standard components such as Button, TextInput, Picker, Slider, and Switch.
  • Wrap Expo UI controls in Host. Use matchContents for intrinsic controls and compact grouped panels; use explicit sizing when the hosted subtree must fill available space.
  • Keep React Native responsible for screen layout, scrolling, safe areas, keyboard avoidance, and custom Clay-specific cards.
  • Do not force every surface into Expo UI. Use React Native Pressable for custom opportunity cards, personality cards, and compound rows where Clay owns the full interaction.
  • Install Expo SDK packages through pnpm --dir apps/mobile expo install <pkg> so versions stay aligned.
  • Avoid SwiftUI-only visual styles such as glass until the minimum iOS and Xcode targets explicitly support them.
Current application:
  • apps/mobile/app/index.tsx uses @expo/ui for the intention form, native picker, readiness slider, consent switch, and save button.
  • Custom personality cards remain React Native Pressable surfaces so Clay controls selected and pressed feedback.
  • Keyboard-aware scrolling is handled outside the native hosted panel with KeyboardAvoidingView and ScrollView.
  • The next-action panel behaves as a useful empty state until an intention is saved.

Press Feedback

Every tappable primary surface needs immediate feedback before navigation or mutation happens.
  • Primary buttons, option cards, fit cards, consent actions, and next-action rows should visibly respond on touch down.
  • The feedback should be subtle: scale, opacity, shadow, or color pressure, then release.
  • If the user scrolls or drags away, the pressed state must cancel cleanly.
  • Do not leave important actions as flat rectangles that only react after the action fires.
Implementation direction:
  • Start with React Native Pressable state for simple surfaces.
  • For gesture-rich cards or spring behavior, prefer UI-thread animation via Reanimated and Gesture Handler once those dependencies are intentionally added.
  • Install Expo-aligned native dependencies through pnpm --dir apps/mobile expo install <pkg>.
Clay-specific places:
  • Intention capture CTA.
  • Personality trait selection.
  • Opportunity fit review cards.
  • Consent grant/deny controls.
  • Introduce, save, remind, or route next-action buttons.

Subtle Motion

Motion should explain a state change, not perform for the user.
  • Fade in generated fit summaries, suggested opportunities, and newly saved intentions.
  • Use native navigation transitions when a list/detail relationship exists.
  • Prefer transform and opacity animations over layout-thrashing motion.
  • Avoid bouncy, decorative, repeated motion on stable reading surfaces.
  • Respect reduced-motion settings before adding loops, shimmer, or gesture-driven transitions.
Good motion cues:
  • A selected fit option cross-fades its indicator.
  • A newly generated recommendation fades in instead of popping onto the screen.
  • A detail view opens from the card that launched it.
  • Toasts or confirmation banners enter and leave quickly without blocking reading.

Haptics

Haptics should make meaningful user intent feel physically acknowledged.
  • Use light haptics for toggles, preference chips, and trait selection.
  • Use a success pattern after an intention is saved, an opportunity is accepted, or consent is granted.
  • Use a warning/error pattern only when the user can immediately fix the issue.
  • Do not fire haptics for passive scrolling, decorative animation, or every render update.
Current app note:
  • Haptics ship through react-native-pulsar, owned by apps/mobile/lib/clay-haptics.ts. The helper exposes product-level events (intentionSaved, opportunityLaneChanged, readinessChanged, personalitySignalSelected) plus a dedicated playConsentBoundaryHaptic(shareTranslatedSignalOnly) so consent toggles get a distinct pattern from ordinary selection.
  • Preloaded presets: Propel, Ping, Snap, Latch. Keep this list small and intentional — presets get cached on app start so cold-tap latency stays low.
  • Verify haptic behavior on an iOS device or simulator path; typecheck alone cannot prove haptic quality.

Keyboard Behavior

Clay will depend on text capture, so keyboard handling is a quality bar, not cleanup work.
  • Inputs should focus when the flow clearly asks the user to type.
  • Primary submit/continue actions should remain reachable when the keyboard is visible.
  • The screen should animate with the keyboard instead of jumping.
  • Dragging or scrolling should dismiss or refocus intentionally, not accidentally.
  • Multi-line intention inputs should grow within a limit, then scroll internally.
Avoid:
  • Static inputs pinned above content while the keyboard covers the submit action.
  • Absolute-position keyboard hacks that fail on different iPhone sizes.
  • Permission or auth prompts triggered before the user understands why typing or access is needed.
Dependency direction:
  • Evaluate react-native-keyboard-controller when Clay moves beyond simple forms.
  • Because this is an Expo iOS app, any native keyboard dependency must follow the Expo install/prebuild rules in apps/mobile/AGENTS.md.

Empty, Loading, And Permission States

Do not ship bare spinners, blank screens, or abrupt system prompts. Empty states should:
  • Name what is missing.
  • Explain why it matters to the user’s next opportunity action.
  • Provide the direct next step.
  • Use a simple icon, illustration, or branded visual only when it clarifies the action.
Loading states should:
  • Say what Clay is doing in product language.
  • Preserve context so the user knows what will change.
  • Prefer skeletons, shimmer, or progressive text when generation takes time.
  • Complete with a visible state change and, for important user-initiated actions, optional haptic confirmation.
Permission states should:
  • Explain the benefit before the iOS permission sheet appears.
  • Ask at the moment of intent, not at app launch.
  • Connect permission to the feature, for example reminders, calendar context, camera, contacts, or notifications.

Clay Mobile Audit Checklist

Before calling a mobile screen polished, check:

Press feedback on every primary tap

Primary buttons, option cards, fit cards, consent actions, and next-action rows visibly respond on touch down and cancel cleanly when the gesture is interrupted.

Success, error, and cancellation states

Every mutation exposes all three terminal states. Never collapse error and cancel into silence.

Keyboard-visible layouts keep the next action reachable

Submit and continue controls stay above the keyboard on every supported iPhone size. The screen animates with the keyboard instead of jumping.

Empty states tell the user what to do next

Empty surfaces name what is missing, explain why it matters to the next opportunity action, and provide a direct next step.

Loading states explain the current job

Especially for AI-generated results, the loading state says what Clay is doing in product language and preserves context.

Permission prompts have an in-app rationale first

Explain the benefit and connect the permission to the feature before the iOS system sheet appears.

Motion is sparse, purposeful, and does not hide content

Fade and transform animations only. Respect reduced-motion settings. No decorative loops on reading surfaces.

Haptics, when installed, map to action weight

Light haptic for selection, success pattern for saved state, warning pattern only when the user can immediately fix the issue.

Text fits on small iPhones without overlap

Verify layout on the smallest supported iPhone size. No clipped labels, no overlapping cards.

The screen still reads as Clay

Intention, personality, readiness, fit, consent, and action remain visible. No screen drifts into a generic chat or marketing surface.

Current App Implications and Build Order

The current apps/mobile app now demonstrates the intended bar for the first capture flow: native input controls, immediate tactile card feedback, keyboard-aware layout, consent language, and an empty-to-saved next-action state. Keep evolving it toward a real opportunity workflow rather than replacing it with a generic chat or marketing screen.
1

Keep the first capture flow narrow

One intention, one readiness signal, one consent boundary, one next action. Resist scope creep on the home screen until the loop is provably tactile.
2

Extract reusable touch surfaces only after reuse

Wait until at least two Clay screens need the same press and selected states before promoting a shared component. Premature extraction locks in a shape that is not yet earned.
3

Add focused loading and error states first

Before connecting generated recommendations or network mutations, wire loading and error surfaces that say what Clay is doing in product language.
4

Add haptics after the interaction map is clear

Install expo-haptics deliberately, then verify on an iOS device or simulator path where the behavior can be felt. Typecheck alone cannot prove haptics.
5

Add keyboard-controller behavior when needed

Bring in react-native-keyboard-controller only when native keyboard avoidance is no longer enough for serious multi-step text capture.

Verification commands

pnpm --filter @clay/mobile typecheck
Use the Expo config check whenever mobile dependencies or app config change. Use iOS simulator/device review for interaction polish; typecheck alone cannot prove press states, keyboard behavior, haptics, or motion quality.

Architecture

How apps/mobile fits the four-app Turborepo surface alongside backend, landing, and specs.

Mobile capture flow

The current iOS capture flow and the Expo UI ownership boundary it depends on.

Design language

The visual system tokens, themes, and components the mobile screens draw from.