This is a submission for the Built with Google Gemini: Writing
Challenge
Runi: Architecting a Real-Time, Multi-User AI Session System with Google Gemini
What I Built with Google Gemini
Runi is a real-time, multi-user AI session framework designed to embed a
large language model inside a structured collaborative environment.
Instead of treating Google Gemini as a conversational interface, I
designed it as a state-aware reasoning layer operating within a
distributed session architecture.
The system's goal is not simply to generate responses. It is to:
- Manage structured session state\
- Enforce permission-aware AI behavior\
- Coordinate multi-user interactions\
- Persist and update pinned objects\
- Operate within deterministic guardrails
System Architecture Overview
Runi is built around four primary layers.
1. Real-Time Session Layer
Each session is a structured document stored in Firestore containing:
- Session ID\
- Member list with assigned roles\
- Pinned object references\
- Active system-layer apps\
- Permission mappings\
- Metadata
Sessions are:
- Multi-user\
- Real-time synchronized\
- Permission-scoped\
- AI-aware
Firestore listeners maintain live synchronization between clients.
All state mutations are validated server-side before persistence.
2. Permission Model
Users are assigned roles at invitation time:
- Viewer\
- Editor\
- Admin
Every Google Gemini invocation includes:
- The current user's role\
- An explicit list of allowed actions\
- A structured session state snapshot\
- Referenced pinned objects
This prevents the AI from proposing state mutations the user is not
authorized to perform.
All AI-generated actions are treated as structured mutation proposals
and must pass validation before execution.
3. Pinned Object Model
Runi separates conversation from structured state.
Pinned objects are atomic entities that:
- Exist independently from chat history\
- Can be referenced by ID\
- Are versioned\
- Are schema-validated\
- Support controlled updates
The AI never directly mutates Firestore.
Instead, it returns structured mutation proposals which are validated
for:
- Schema conformance\
- Permission compliance\
- Object existence\
- Referential integrity
This separation prevents hallucinated writes and corrupted session
state.
4. System-Layer Apps
Sessions can instantiate structured applications inside the environment,
including:
- File Manager\
- Image Gallery\
- Image and Video Generation\
- Wiki Layer\
- Space Weather Module
Each app:
- Defines its own schema\
- Registers allowed actions\
- Maintains scoped storage\
- Exposes controlled interaction boundaries to the AI
Example flow for image generation:
- A user triggers media generation.\
- The controller sends structured intent to Gemini.\
- Gemini returns refined prompt metadata and structured output.\
- Media is generated and stored in Firebase Storage.\
- A versioned pinned object is created.\
- Firestore propagates the update in real time to all session members.
All writes pass through validation middleware.
Technology Stack
Frontend
- Vite\
- React\
- Component-based dashboard architecture\
- Firestore real-time listeners\
- Blob-based iframe isolation for project environments
Backend
- Node.js controller\
- Structured task runner\
- Schema validation layer\
- Mutation validator\
- Firestore (real-time state + indexes)\
- Firebase Storage (files + media assets)
Every AI response is treated as untrusted structured input.
AI Layer: Google Gemini
Gemini is used for:
- Intent classification\
- Structured JSON planning\
- Context-aware reasoning\
- Media prompt refinement\
- Wiki summarization\
- Permission-aware action proposals
Prompts are structured and always include:
- System role definition\
- Session state snapshot\
- User role\
- Allowed actions\
- Pinned object references\
- Expected output schema
Gemini functions as a probabilistic planner operating inside a
deterministic execution layer.
Key Engineering Challenges
AI in a Distributed Real-Time System
LLMs are non-deterministic.
Real-time collaborative systems are state-sensitive.
To reconcile this:
- All AI outputs are proposals\
- No direct database writes are allowed\
- All changes require validation\
- Session versioning mitigates race conditions
Context Scaling
Multi-user sessions rapidly expand context size.
Mitigation strategies:
- Structured state snapshots instead of replaying full conversation history\
- Object referencing instead of full content injection\
- Metadata summaries in place of raw file bodies
Role-Aware AI Behavior
Gemini must behave differently for:
- Viewers\
- Editors\
- Admins
Explicit role and action injection significantly improves compliance and
reduces invalid action proposals.
Google Gemini Feedback
Strengths
- Strong structured JSON generation\
- Reliable schema adherence when constrained\
- Effective reasoning over structured session state\
- High-quality summarization of linked knowledge objects
Limitations Observed
- Schema drift in very long sessions\
- Occasional assumption of unavailable system apps\
- Requires strong validation layers for deterministic workflows\
- Long context windows require active pruning strategies
Gemini performs best when embedded inside a clearly bounded execution
architecture.
What's Next
- Cross-session shared memory graphs\
- Version-controlled session file systems\
- More granular permission hierarchies\
- Domain-specific session templates\
- Bounded autonomous planning loops
Closing Reflection
Embedding an LLM inside a real-time collaborative system is not
primarily a prompt engineering challenge.
It is a distributed systems design challenge.
Google Gemini becomes most powerful when treated as a reasoning engine
inside a controlled, validated execution architecture.
That shift --- from chatbot to state-aware planner --- defines Runi.
Top comments (1)
Small development update since posting this article.
Over the past week I made a fairly major change to the Runi frontend: I migrated the platform from React to Svelte 5.
The original dashboard was built with Vite + React and worked well, but as the system evolved into something closer to a desktop-like multi-window environment, the component model started to feel heavier than necessary. Runi isn't a traditional page-based application — it's a persistent workspace where many independent “apps” run simultaneously inside draggable cards.
Svelte ended up being a much better fit for that model.
A few advantages became obvious almost immediately:
Many of the UI elements in Runi behave like small applications (file manager, gallery, generators, chatrooms, etc.).
With Svelte's reactive primitives, a lot of state logic that previously required hooks and reducers became straightforward reactive assignments.
The result is significantly less boilerplate and easier reasoning about UI state.
A Runi session can easily contain a large number of simultaneously mounted cards. Because Svelte compiles components rather than relying on a runtime virtual DOM, updates are very targeted. This makes the interface feel noticeably lighter when many cards are active.
Many cards share common behavior:
• draggable window logic
• modal systems
• real-time Firestore listeners
• role-based UI state
Svelte components made it much easier to extract those patterns into reusable primitives.
One of the biggest benefits so far is simply clarity. Components are smaller, easier to read, and the reactive model fits naturally with the real-time data streams coming from Firestore.
Runi is still evolving quickly, but this shift has already made the frontend feel much more aligned with the system's architecture.
It also opens the door to experimenting with more advanced workspace behaviors — like synchronized layouts and shared UI state across session members.
I'll likely write a deeper follow-up once the migration is fully complete.