MobileGraph is an open-source Kotlin Multiplatform SDK built strictly for the realities of Android and iOS edge devices. It allows you to orchestrate non-deterministic AI tasks — from streaming chatbots to autonomous ReAct agents — with absolute deterministic lifecycle control.
This is Part 1 (Introduction) of a series on building AI-powered mobile applications with MobileGraph.
Think of it as the architectural principles of LangGraph, re-engineered for mobile lifecycles.
It’s published on Maven Central, licensed under Apache 2.0, and designed to bind seamlessly to Jetpack Compose and SwiftUI state structures.
A Streaming Chat in 4 Lines
Let’s cut to the code. No callbacks, no listeners — just native Kotlin Flow for structured concurrency and cooperative cancellation.
val session = MobileGraph.instance.createSession()
// Safely collect in your ViewModel / Compose UI
session.stream("Plan a 3-day trip to Tokyo").collect { chunk ->
print(chunk.text)
}
That’s it. Session management, conversation history, provider communication — all handled for you.
What Can You Build?
MobileGraph isn’t just a chat wrapper. It’s a full AI application framework with below major capability areas:
💬 Multi-Provider Chat
Register multiple AI providers- OpenAI, Google Gemini, Anthropic Claude, DeepSeek, OpenRouter — all through a unified API. Your prompts, tools, and agents work identically across providers. You can swap between models based on prompt compexity or your requirement.
MobileGraph.initialize {
withModels {
openai(apiKey = "sk-...", name="gpt-4o-mini") { isDefault = true }
gemini(apiKey = "...",name="gemini-2.5-flash-lite")
claude(apiKey = "...",name="claude-3-5-sonnet-20241022")
}
}
Want to use a local Ollama instance? Just point to a custom endpoint:
val localModel = OpenAIChatModel(
name = "llama3",
apiKey = "ollama",
baseUrl = "http://10.0.2.2:11434/v1"
)
Developers are free to implement the ChatModel interface and can point to their own LLM provider.
📄 On-Device RAG
Load documents, split them into chunks, embed them, and search — all on-device:
// define vector embedding model
val embeddingModel = MediaPipeEmbeddingModel({ context })
// DB driver
val driver = AndroidSqliteDriver(
schema = VectorDatabase.Schema,
context = context,
name = "mobilegraph_vector.db")
// create vector store
val vectorStore = SQLiteVectorStore(driver, embeddingModel)
MobileGraph.knowledge.ingest {
docId("manual-001")
docName("Product User Guide")
loader(PdfDocumentLoader(pdfExtractor))
splitter(RecursiveTextSplitter(chunkSize = 500, chunkOverlap = 100))
vectorStore(SQLiteVectorStore(driver, embeddingModel))
}
MobileGraph ships with loaders for PDF, Markdown, HTML, JSON, CSV, and websites. Text splitters include RecursiveTextSplitter, TokenTextSplitter, and CharacterTextSplitter. You can implement custom loaders for any format with a single interface.
Retrieval is the act of finding relevant context from your knowledge base to answer a user’s question. MobileGraph supports several built-in retrievers to balance speed and accuracy. Retrival techniques inlude VectorStoreRetriever BM25Retriever HybridRetriever MultiQueryRetriever
RAG Pipeline: The RagPipeline orchestrates the entire process: Search -> Augment -> Generate.
// Basic setup
val vectorRetriever = VectorStoreRetriever(vectorStore)
MobileGraph.initialize() {
// ... model and vector store config ...
withRetrievers {
register("default", vectorRetriever, isDefault = true)
}
withRag {
retriever(vectorRetriever)
chatModel(myChatModel)
// contextBuilder(customBuilder) // Optional: for custom prompts/guardrails
}
}
// Execute a query
// Standard execution (returns model response)
val result = MobileGraph.rag.pipeline().execute("What is the battery life?")
🤖 Autonomous Tool-Calling Agents
Give your AI “hands” — define Kotlin functions it can autonomously decide to call:
val weatherTool = object : Tool<String, String> {
override val metadata = ToolMetadata(
name = "get_weather",
description = "Gets the current weather for a specific city."
)
override suspend fun invoke(input: String, context: ExecutionContext): String {
return "The weather in $input is 25°C and Sunny."
}
}
MobileGraph.initialize {
withTools { register(weatherTool) }
}
The LLM autonomously decides when to call which tool. MobileGraph even includes Semantic Tool Selection — using vector embeddings to pick only the most relevant tools, so you’re not wasting tokens sending 100 tool definitions every call.
🔀 Multi-Agent Workflows
For complex tasks, one agent isn’t enough. MobileGraph’s stateGraph DSL lets you orchestrate teams of agents:
val workflow = stateGraph {
start("researcher")
node(AgentNode("researcher", researchAgent, runtime))
node(AgentNode("writer", writerAgent, runtime))
node(EndNode("done"))
edge("researcher", "writer")
edge("writer", "done")
}
val result = agentRuntime.run(workflow, initialState)
This supports:
- Fan-Out / Fan-In — run agents in parallel, merge at a sync point
- Human-in-the-Loop — pause for user approval, then continue
- Hierarchical Sub-Agents — manager agents that own internal sub-workflows
- Conditional Branching — route based on state variables
💾 Durable Execution (Survives Process Death)
This is MobileGraph’s superpower for mobile. The framework automatically checkpoints state after every graph node execution. If the OS kills your app — or the user navigates away and comes back — you resume exactly where you left off:
// Resume after process death or human-in-the-loop approval
val result = agentRuntime.resume(
graph = workflow,
checkpointId = "trace_node_timestamp",
nodeId = "review",
input = mapOf("approved" to true)
)
This is powered by immutable state — every transition creates a new state snapshot (State S → Node → State S'), making the entire workflow replayable, debuggable, and recoverable.
🔧 Middleware Pipeline
Cross-cutting concerns live in composable middleware — just like HTTP middleware in Ktor:
middleware {
+LoggingMiddleware() // Log every prompt & response
+RetryMiddleware(maxRetries = 3) // Auto-retry on network failures
+ChatMemoryMiddleware() // Auto-manage conversation history
}
🌐 Connected Ecosystem: MCP & A2A Protocols
MobileGraph breaks out of single-app boundaries by supporting the industry’s two leading open communication standards.
-
Model Context Protocol (MCP) - Connect your agent to external tools on servers, lambdas, or local hardware over JSON-RPC 2.0 with auto-discovery and auto-registration into
ToolRegistry. -
Agent-to-Agent (A2A) Protocol — Delegate complex graph subtasks from on-device models to specialized cloud agents via
A2ANode, featuring Agent Card discovery, SSE artifact streaming, and native human-in-the-loop task resumption.
The Architecture in 30 Seconds
MobileGraph is organized in three layers, with dependencies flowing strictly downward:
📱 Application Layer (Your App)
│
🔷 MobileGraph SDK (Entry Point & DSL)
│
┌────┴────────────────────────────┐
│ │
🧠 Intelligence Layer 📚 Knowledge Layer
• Models & Providers • Documents & Loaders
• Prompts DSL • Embeddings
• Parsers • Vector Stores
• Tools & Agents • Retrieval
• Graph Runtime
│ │
└────────────┬────────────────────┘
│
⚙️ Foundation Layer
• Core Runtime
• State Management
• Checkpointing
Every module is independent. You only include what you need — a chat-only app doesn’t pull in the RAG or Agent modules.
Design Decisions That Make It Mobile-Ready
Three architectural choices set MobileGraph apart from server-side frameworks:
1. Capability-Based Abstraction, Not instanceof Checks
// ❌ Coupled to a specific provider
if (model is OpenAIChatModel) { /* use vision */ }
// ✅ Query capabilities generically
if (model.supports(Capability.Vision)) { /* use vision */ }
2. Deterministic Runtime, Probabilistic AI
AI outputs are inherently unpredictable. But the framework that runs them must be deterministic. Given a state and a node, MobileGraph always produces predictable execution behavior. This makes workflows testable, replayable, and debuggable.
3. Flow as the Universal Streaming Primitive
No callbacks. No listeners. No RxJava. Every streaming operation uses Kotlin Flow, giving you structured concurrency, cooperative cancellation, and seamless Compose integration for free.
Getting Started
1. Add the Dependency
repositories {
mavenCentral()
}
2. Initialize
dependencies {
implementation("io.github.mobilegraph:mobilegraph-sdk:0.5.0")
implementation("io.ktor:ktor-client-okhttp:3.5.1") // HTTP engine
}
3. Chat
lifecycleScope.launch {
MobileGraph.initialize {
withModels {
openai(apiKey = "sk-...") { isDefault = true }
}
}
}
val session = MobileGraph.instance.createSession()
session.stream("Hello, MobileGraph!").collect { chunk ->
print(chunk.text)
}
Requirements: Kotlin 2.0+, Gradle 8.4+, JDK 17+, Android Min SDK 24+.
Try It Yourself
MobileGraph is open source and available today.
🌟 Star it on GitHub: https://github.com/user/MobileGraphSDK
📦 Maven Central: io.github.mobilegraph:mobilegraph-sdk:0.5.0-alpha
📖 Documentation: Full guides for setup, RAG, agents, tools, MCP, A2A and multi-model orchestration
📱 Sample App: Clone the repo and run the :androidApp target — it includes demos for chat, RAG, tool agents, HITL, fan-out, A2A, MCP and hierarchical agents
I’d love to hear your feedback. Your collboration for the project is well appreciated. What AI capabilities do you wish existed in your mobile app?
Next up: a deep-dive into the architecture — how immutable state, checkpointing, and capability-based abstraction make AI workflows survive process death.
Tags: Kotlin, Android, iOS, Artificial Intelligence, Mobile Development, Kotlin Multiplatform, LangChain, RAG, AI Agents, Open Source, MobileGraph
Top comments (0)