Hi Russ - interesting use case! I’ll explain the architecture constraints and potential approaches.
The Challenge
Letta tools execute server-side (where the agent runs), not client-side. This means tools run either on Letta Cloud or your self-hosted Letta server - they don’t execute in your React Native app’s JavaScript runtime.
From the docs:
“When running Letta locally, the tools are executed inside of the Docker container running the Letta service”
Potential Architectures
Option 1: Local Letta Server on Device
Run a self-hosted Letta server on the same mobile device:
- Letta server runs as a background service
- Tools access local SQLite/vector stores directly
- React Native app connects via
http://localhost:8283
Challenges:
- Running Docker/Python on mobile is complex
- Resource constraints (battery, memory)
- Platform-specific (easier on Android than iOS)
Option 2: Callback Pattern (Recommended)
Run Letta server separately, but tools call back to your client:
// On React Native app - expose local API
const localServer = express();
localServer.post('/query-db', async (req, res) => {
// Access local SQLite here
const results = await localDB.query(req.body.sql);
res.json(results);
});
// On Letta server - custom tool
def query_local_db(query: str) -> str:
"""Query the mobile device's local database"""
import requests
# Call back to the React Native app's local API
response = requests.post(
"http://mobile-device-ip:3000/query-db",
json={"sql": query}
)
return response.json()
Benefits:
- Letta handles agentic behavior and memory
- Your client retains data control
- Clear separation of concerns
Considerations:
- Network latency for local calls
- Need to handle device IP addressing
- Security: authenticate callbacks
Option 3: Hybrid Memory Pattern
Use Letta for working memory, client-side for long-term storage:
// Client manages RAG/vector search locally
const searchResults = await localVectorDB.search(query);
// Send results to Letta as context
const response = await client.agents.messages.create({
agent_id: agentId,
messages: [{
role: "user",
content: `Context from local DB: ${searchResults}\n\nUser question: ${query}`
}]
});
Benefits:
- Simpler architecture
- Letta focuses on reasoning and conversation management
- Client handles all data access
For Your Privacy Requirements
The callback pattern (Option 2) or hybrid pattern (Option 3) best satisfy your privacy needs:
- All data stays on device
- Letta server only receives what you explicitly send
- You control data flow completely
If you’re running self-hosted Letta on a local network (not Cloud), Option 2 gives you full control while still leveraging Letta’s agentic capabilities.
MCP Alternative
You could also explore creating an MCP server that runs alongside your React Native app and connects to Letta via stdio/SSE, though this adds complexity.
Does one of these architectures align with what you’re trying to build? Happy to elaborate on any approach.