NeuronApp is a React Native mobile application that acts as a proactive, context-aware personal assistant. It integrates deeply with Google Workspace to understand your schedule, communications, documents, and tasks — then uses that context to provide semantic recall, daily intelligence briefings, and real-time background indexing.
Built around the Cognitive Sanctuary design system: tonally layered UI with no hard borders, asymmetric layout, and Manrope/Inter typography optimised for deep focus.
Eight Google services are synced automatically in the background without any user interaction after initial permission grant. Sync uses a hybrid push + polling architecture:
Push-based (real-time):
- Gmail — Google pushes change notifications via Cloud Pub/Sub (
gmail-pushtopic). Each notification triggers an incremental sync of new/modified messages. Extracts subject, sender, date, body, labels, importance markers, and category. - Google Drive — HTTP webhook channel on the Drive Changes endpoint. On every file change, Drive metadata is synced and document content extraction is triggered automatically.
- Google Calendar — HTTP webhook channel on the primary calendar. Syncs all calendars and events including RSVP status, attendees, video links, and multi-calendar support with per-event timezone handling.
Scheduled polling (every 15 minutes):
- Contacts — Incremental sync via People API using sync tokens. Extracts name, emails, phones, organisations, biographical notes, and photo URL. On 410 (token expired), falls back to full sync.
- Tasks — All task lists with completion status, due dates (midnight UTC), parent/child relationships, and position ordering.
- Google Keep — Note titles and body text. Fails gracefully if the account lacks Workspace Enterprise access.
- Google Chat — Space metadata (DMs, group chats, named spaces).
Watch renewal (every 6 hours): A scheduled function checks all active watch channels and renews any expiring within 12 hours. Gmail and Calendar watches expire after ~7 days; Drive watches after ~24 hours.
The client never passes access tokens to sync functions. On first sign-in:
- The React Native Google Sign-In SDK returns a
serverAuthCode(available becauseofflineAccess: true). - The app sends this one-time code to the
storeRefreshTokenCloud Function. - The backend exchanges it for a long-lived refresh token via the Google OAuth2 token endpoint and stores it at
users/{uid}/tokens/googlein Firestore (admin SDK only — clients are blocked by security rules). - Before every automated sync, the backend calls
refreshAccessTokenServer()to obtain a fresh access token (~60 min lifetime) without any client involvement.
All synced documents are automatically embedded using Vertex AI text-embedding-004 and stored as Firestore vector fields. Embeddings are generated asynchronously via a Cloud Tasks queue with retry on failure.
Collections indexed:
gmail_messages— Email body prepended with[Email], subject, sender, datedocs_content— Document title, extracted plain text (Docs/Sheets/Slides exported via Drive API), and unresolved commentskeep_notes— Note title and bodychat_messages— Text content
Semantic Chat (semanticChat Cloud Function) is a multi-stage RAG pipeline with a ReAct agent:
- Guardrails — a fast regex check rejects prompt-injection patterns (zero LLM cost) before any model call.
- Intent classification — hybrid keyword heuristics handle the common 80% instantly; an LLM fallback classifies ambiguous queries into
search,calendar,task_manage,briefing,general, orunsafe. - Routing —
briefingreads the pre-generated daily brief directly from Firestore (no agent overhead);generalgets a simple LLM response;search/calendar/task_managerun the full ReAct agent. - Multi-stage RAG (the
searchWorkspacetool):- Query expansion — Gemini generates 2–3 semantically diverse search variants from the user's query.
- Multi-query retrieval — fires (expanded queries × 4 collections) in parallel, then deduplicates by a composite key.
- LLM reranking — scores each candidate 0–10 for relevance, filters below threshold 6, and returns the top 5.
- ReAct agent — Gemini 2.5 Flash reasons in a Thought → Action → Observation loop (max 5 turns) with four tools:
searchWorkspace— full multi-stage RAG over indexed GSuite datagetCalendarEvents— reads synced calendar events for a dategetTasksByStatus— reads synced Google Tasks by completion statusgetEmailDetail— retrieves specific emails by subject keyword search
- Reasoning trace — the Thought/Action/Observation steps are extracted from Genkit's message history and sent to the frontend, where they're rendered inline in the chat UI.
- Synthesis — Gemini 2.5 Flash produces a grounded answer with a 45-second timeout.
- Returns
{ answer, sources, steps }with human-readable citations (Email: Subject — from sender,Document: Title, etc.) and the reasoning trace.
Idempotency: Firestore triggers skip re-embedding documents whose text content hasn't changed since the last embedding pass.
A scheduled Cloud Function runs every hour and generates a personalised morning brief for each user once per day after 07:00 in their local timezone.
Data aggregated (in parallel from Firestore, no Google API calls):
- Today's calendar events (all-day and timed, filtered by IANA timezone)
- Pending tasks due today or overdue
- Important emails from the last 24 hours
LLM synthesis: Gemini 2.5 Flash produces a structured output validated by Zod:
greeting — warm one-line greeting referencing the date
summary — 2–3 sentence synthesis of the day's priorities
eventHighlights — up to 3 most important calendar items
priorityTasks — up to 3 most urgent tasks
importantEmails — up to 3 emails needing attention
Idempotency: if a brief already exists for today (users/{uid}/daily_briefings/YYYY-MM-DD), the function skips that user. Per-user failures are isolated and logged without aborting the full fan-out.
After calendar sync, the backend detects overlapping timed events and uses Gemini 2.5 Flash to classify which event takes precedence (rules: external > internal, more attendees > fewer, one-time > recurring, video calls indicate importance). It produces a { highPriorityEvent, lowPriorityEvent, reason, suggestedAction } resolution written to users/{uid}/calendar_conflicts/. Pending conflicts surface in the Daily Briefing card on the home screen, where the user can acknowledge or dismiss them.
A full email drafting agent that learns the user's writing voice and automates replies. Implemented across 14 Cloud Functions in functions/src/services/ghostwriter.ts with a dedicated screen at app/home/ghostwriter.tsx.
Style extraction: extractStyle analyses up to 30 of the user's sent emails (requires ≥3) and produces a StyleProfile (tone, greeting style, sign-off, formatting quirks, average length, vocabulary notes) validated by Zod, persisted at users/{uid}/settings/style_profile. A scheduled function (refreshStyleProfiles) re-extracts monthly.
Drafting & replies:
generateSmartReplies— 3 context-aware, style-aligned reply options for an email (labels + bodies)generateDraft— full email draft from a short natural-language instruction (max 1,000 chars), injecting the Style ProfilerefineDraft— iterative refinement of an existing draft with follow-up instructionssummarizeThread— condenses an email thread into key pointssendDraft— sends a draft via the Gmail API (validates recipient format to prevent header injection)
Draft history & templates:
listDraftHistory/deleteDraftHistory— every generated/sent draft is persisted for reviewsaveTemplate/listTemplates/deleteTemplate/applyTemplate— reusable email templates
Follow-up detection: detectFollowUps (scheduled) scans the last 7 days of sent emails and flags any thread unanswered for 3+ days, writing reminders to users/{uid}/follow_ups/.
Semantic Chat maintains conversational continuity across turns and remembers past interactions:
- Conversation persistence — each exchange is saved to
users/{uid}/conversations/{conversationId}/messages. Recent history (up to 10 messages) is injected into the system prompt as context. - Episodic memory —
summarizeConversations(scheduled) condenses conversation histories into summary documents stored inusers/{uid}/episodic_memory/with vector embeddings. On each new query,searchEpisodicMemoryperforms a vector similarity search over these summaries and injects relevant past context into the prompt. - The
episodic_memorycollection has its own 768-dimension vector index infirestore.indexes.json.
- Google Sign-In with Firebase Auth. Session persisted to device via
AsyncStoragewith Firebase's built-in token refresh. - Biometric gating (Face ID / Touch ID / Android Biometrics): on first app launch after sign-in, the user must authenticate biometrically if enabled. Biometric state stored in Keychain (
react-native-keychain). - Firestore security rules enforce user-scoped access.
users/{uid}/tokens/**andwatch_channels/**are hard-blocked from client reads/writes (allow read, write: if false). - OAuth scopes are read-only across all eight Google APIs.
Mobile App (React Native)
│
├── Sign-in → captures serverAuthCode → storeRefreshToken Cloud Function
│ └── stores refresh token in Firestore
│
├── Permission grant → savePermissions → initializeSync Cloud Function
│ ├── syncs all enabled services (server-side)
│ └── sets up push watch channels
│
├── GSuiteStatus screen ─ onSnapshot(sync_meta/status) → real-time progress
├── GSuiteData screen ─ browses synced items per service (tonal tab nav)
├── DailyBriefing card ─ reads today's brief + pending calendar conflicts
├── SemanticChat screen → semanticChat Cloud Function → ReAct agent + Gemini 2.5 Flash
└── Ghostwriter screen → ghostwriter Cloud Functions → style-aware drafting
Cloud Functions
│
├── onGmailPush (Pub/Sub) ─┐
├── onCalendarPush (HTTP webhook) ├── refresh token → sync → update sync_meta
├── onDrivePush (HTTP webhook) ─┘
│
├── autoSyncPolled (cron: */15 * * * *) — contacts, tasks, keep, chat
├── renewWatches (cron: 0 */6 * * *) — renews expiring watch channels
├── generateDailyBriefings (cron: 0 * * * *) — timezone-aware morning briefs
├── refreshStyleProfiles (cron: monthly) — re-extracts writing style profiles
├── detectFollowUps (cron: daily) — flags unanswered sent emails
├── summarizeConversations (cron: scheduled) — condenses chats into episodic memory
│
├── processEmbedding (Cloud Tasks queue) — generates + stores vector embeddings
├── onDocsWrittenEmbed ─┐
├── onGmailWrittenEmbed ├── Firestore triggers → enqueue processEmbedding
├── onKeepWrittenEmbed ├── (4 collections: docs, gmail, keep, chat)
├── onChatWrittenEmbed ─┘
│
├── semanticChat (callable) — multi-stage RAG + ReAct agent + Gemini synthesis
├── resolveConflict (callable) — calendar overlap detection + LLM priority classification
└── ghostwriter (callable ×11) — extractStyle, smartReplies, draft, refine, send,
threadSummary, draftHistory, templates, follow-ups
Firestore Data Model
users/{uid}/
tokens/google — refresh token (admin SDK only)
settings/
timezone — IANA timezone string (written on sign-in)
gsuite_permissions — per-service enabled booleans
style_profile — extracted writing voice (tone, sign-off, quirks)
sync_meta/status — real-time sync progress per service
watches/ — active push channel metadata
calendar_events/ — synced events
calendar_calendars/ — calendar list
calendar_conflicts/ — detected overlaps with LLM priority classification
gmail_messages/ — messages with embeddings
drive_files/ — file metadata with folder paths
docs_content/ — extracted document text with embeddings
contacts_people/ — contact records
tasks_items/ — tasks with list context
tasks_lists/ — task list metadata
keep_notes/ — note text with embeddings
chat_spaces/ — Chat space metadata
chat_messages/ — Chat text with embeddings
daily_briefings/ — one document per day (YYYY-MM-DD)
conversations/ — chat sessions
{conversationId}/messages — per-turn message history
episodic_memory/ — conversation summaries with embeddings
draft_history/ — ghostwriter draft history
email_templates/ — saved reusable email templates
follow_ups/ — unanswered sent email reminders
watch_channels/{channelId} — channelId → {uid, service} reverse lookup
| Layer | Technology |
|---|---|
| Mobile | React Native 0.84.1 (TypeScript) |
| State | Zustand 5 (authStore, gsuiteStore) |
| Forms | react-hook-form + Zod |
| Navigation | React Navigation v7 (native stack) |
| Auth | Firebase Auth 12 + Google Sign-In 16 |
| Biometric | react-native-biometrics + react-native-keychain |
| Persistence | @react-native-async-storage |
| Backend | Firebase Cloud Functions v2 (Node 22) |
| Database | Cloud Firestore |
| Vector Search | Firestore Vector Search |
| AI Orchestration | Firebase Genkit 1.32 |
| LLM | Gemini 2.5 Flash (via Vertex AI) |
| Embeddings | Vertex AI text-embedding-004 |
| Async Jobs | Google Cloud Tasks |
| Push Sync | Google Pub/Sub + HTTP webhook channels |
| Secrets | Firebase Secret Manager |
- Node.js v22+
- React Native environment (Android Studio / Xcode)
- Firebase CLI:
npm install -g firebase-tools gcloudCLI authenticated to the project
git clone https://github.com/your-org/NeuronApp.git
cd NeuronApp
npm install
cd functions && npm install && cd ..# Store the OAuth web client secret
echo "YOUR_CLIENT_SECRET" | firebase functions:secrets:set GOOGLE_CLIENT_SECRET --project neuron-bb594
# Create the Gmail Pub/Sub topic
gcloud pubsub topics create gmail-push --project=neuron-bb594
# Grant Gmail push notifications permission to publish
gcloud pubsub topics add-iam-policy-binding gmail-push \
--project=neuron-bb594 \
--member="serviceAccount:gmail-api-push@system.gserviceaccount.com" \
--role="roles/pubsub.publisher"
# Create the Cloud Tasks queue for async embedding jobs
gcloud tasks queues create process-embedding \
--location=us-central1 --project=neuron-bb594Note: The OAuth web client ID is currently hardcoded in
App.tsx(GoogleSignin.configure). UpdatewebClientIdto match your own Google Cloud project's OAuth client before running the app.
cd functions
npm run deploy
cd ..
# Deploy Firestore security rules + vector/composite indexes
firebase deploy --only firestore:rules,firestore:indexes --project neuron-bb594The firestore.indexes.json defines 5 vector indexes (768-dim, flat, COSINE) for docs_content, gmail_messages, keep_notes, chat_messages, and episodic_memory, plus composite indexes for Gmail queries.
npm start # Metro bundler
npm run android # or open android/ in Android Studio
npm run ios # or open ios/ in Xcodenpm test # Jest (snapshot/render test in __tests__/)
npm run lint # ESLintThe UI is built around the concept of a focused, distraction-free mental workspace:
- Palette: Surgical white
#F8F9FAbase with Neuron Blue#1A73E8as the primary accent - No-Line Rule: Boundaries defined by tonal background shifts rather than borders
- Typography: Manrope (headlines) and Inter (body) for high legibility at small sizes
- Layout: Asymmetric compositions with intentional whitespace to reduce cognitive load
See src/theme/ and Design/DESIGN.md for the full token system.
NeuronApp/
├── App.tsx # Root: navigation stack, auth gate, biometric gating
├── index.js # React Native entry point
├── app/ # UI screens (Cognitive Sanctuary design system)
│ ├── auth/
│ │ └── login.tsx # Google Sign-In onboarding
│ └── home/
│ ├── index.tsx # Home hub (briefing card, navigation tiles)
│ ├── daily-briefing.tsx # Daily brief + calendar conflict cards
│ ├── semantic-chat.tsx # ReAct agent chat with reasoning trace
│ ├── ghostwriter.tsx # Email drafting, smart replies, templates
│ ├── gsuite-connect.tsx # Permission grant flow
│ ├── gsuite-status.tsx # Real-time sync progress
│ ├── gsuite-data.tsx # Synced data browser (tonal tab nav)
│ └── profile.tsx # User profile & settings
├── src/
│ ├── components/ # Button, Input, PasswordInput
│ ├── lib/ # firebase, firestore, auth, biometric, google-api, errors
│ ├── services/ # sync-engine (client-side sync orchestration)
│ ├── store/ # Zustand stores: authStore, gsuiteStore
│ └── theme/ # colors, typography, spacing tokens
├── functions/ # Firebase Cloud Functions (Node 22, Genkit)
│ └── src/
│ ├── index.ts # Function exports (storeRefreshToken, initializeSync, …)
│ ├── lib/ # genkit, google-api, oauth
│ └── services/ # 17 service modules (gmail, drive, calendar, …)
├── android/ # Native Android project (package: com.neuron)
├── ios/ # Native iOS project
├── Design/ # HTML prototypes + DESIGN.md per screen
├── firestore.rules # Security rules (user-scoped, admin-only tokens)
├── firestore.indexes.json # Vector + composite indexes
└── firebase.json # Firebase config (functions, firestore)
| Screen | Route | Purpose |
|---|---|---|
| Login | Login |
Google Sign-In onboarding |
| Home | Home |
Hub with daily briefing card and navigation tiles |
| Profile | Profile |
User profile & settings |
| GSuiteConnect | GSuiteConnect |
Google Workspace permission grant flow |
| GSuiteStatus | GSuiteStatus |
Real-time sync progress per service |
| GSuiteData | GSuiteData |
Browse synced items across 8 services |
| SemanticChat | SemanticChat |
ReAct agent chat with inline reasoning trace |
| Ghostwriter | Ghostwriter |
Style-aware email drafting, smart replies, templates |
ROADMAP.md— Strategic evolution from sync tool to agentic assistantGEMINI.md— Design system overview & redesign statusDesign/DESIGN.md— Full Cognitive Sanctuary token systemDesign/— HTML prototypes per screen (Daily Briefing, Onboarding, Project Hubs, Semantic Chat)test-cases-react-rag.md— RAG test casesAGENTS.md— Build & run instructions for Android Studio / CLI