◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/AI Models
◉ AI Models/2026-03-22Intermediate

Integrate NemoClaw AI Agents into Your Rork App — A Practical Guide to Mobile Agent Integration

Learn how to embed NVIDIA NemoClaw AI agents into Rork-built mobile apps. Covers backend API design, Cloudflare Workers gateway, React Native frontend integration, and OpenShell security policies.

NemoClaw3Rork585AI agents5mobile appsNVIDIAOpenShellAPI integration

The Era of AI Agents in Mobile Apps

NVIDIA's NemoClaw announcement at GTC 2026 has dramatically lowered the barrier to integrating AI agents into applications. While AI agents were previously confined to server-side batch processing and CLI tools, NemoClaw's API layer now lets mobile apps built with Rork call agent capabilities directly.

Imagine an in-app AI assistant that doesn't just return text — it queries multiple data sources, performs calculations, and executes actions through external services. That's the kind of "think and act" assistant you can now build.

Architecture Design — Mobile App × NemoClaw

System Overview

┌──────────────┐     ┌──────────────────┐     ┌─────────────┐
│  Rork App    │────▶│  API Gateway     │────▶│  NemoClaw   │
│  (Frontend)  │◀────│  (Cloudflare     │◀────│  Agent      │
│              │     │   Workers)       │     │  (OpenShell)│
└──────────────┘     └──────────────────┘     └─────────────┘
                             │
                     ┌───────┴────────┐
                     │  External APIs  │
                     │  (Stripe, DB)   │
                     └────────────────┘

The key design decision: the Rork app never communicates with NemoClaw directly. Instead, an API Gateway (Cloudflare Workers) handles authentication, rate limiting, and logging, working alongside NemoClaw's OpenShell security for defense in depth.

API Gateway Implementation (Cloudflare Workers)

// workers/agent-gateway.ts
// AI agent API gateway for Rork apps
export interface Env {
  NEMOCLAW_ENDPOINT: string;
  NEMOCLAW_API_KEY: string;
  RATE_LIMITER: RateLimit;
}
 
interface AgentRequest {
  userId: string;
  message: string;
  context?: {
    currentScreen: string;
    userPreferences: Record<string, string>;
  };
}
 
interface AgentResponse {
  reply: string;
  actions?: Array<{
    type: string;
    payload: Record<string, unknown>;
  }>;
  suggestedFollowUps?: string[];
}
 
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // Authentication check
    const authHeader = request.headers.get("Authorization");
    if (!authHeader?.startsWith("Bearer ")) {
      return new Response(
        JSON.stringify({ error: "Unauthorized" }),
        { status: 401 }
      );
    }
 
    // Rate limiting
    const clientIP = request.headers.get("CF-Connecting-IP") || "";
    const { success } = await env.RATE_LIMITER.limit(clientIP);
    if (!success) {
      return new Response(
        JSON.stringify({ error: "Rate limit exceeded" }),
        { status: 429 }
      );
    }
 
    // Parse request body
    const body: AgentRequest = await request.json();
 
    // Forward to NemoClaw agent
    const agentResponse = await fetch(
      `${env.NEMOCLAW_ENDPOINT}/v1/agent/chat`,
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "Authorization": `Bearer ${env.NEMOCLAW_API_KEY}`,
        },
        body: JSON.stringify({
          model: "nemotron-mini",
          messages: [
            {
              role: "system",
              content: `You are an AI assistant for a mobile app.
Answer user questions concisely and suggest actions when appropriate.
Current screen: ${body.context?.currentScreen || "home"}`
            },
            { role: "user", content: body.message }
          ],
          tools: [
            {
              name: "navigate_to_screen",
              description: "Navigate to a specific screen in the app"
            },
            {
              name: "search_products",
              description: "Search products and return results"
            },
            {
              name: "create_reminder",
              description: "Set a reminder for the user"
            }
          ]
        })
      }
    );
 
    const result: AgentResponse = await agentResponse.json();
 
    return new Response(JSON.stringify(result), {
      headers: { "Content-Type": "application/json" }
    });
  }
};
 
// Expected response:
// {
//   "reply": "I found 3 matching products. Sort by price?",
//   "actions": [
//     { "type": "search_products", "payload": { "query": "...", "sort": "price" } }
//   ],
//   "suggestedFollowUps": ["Sort by lowest price", "Sort by highest rated"]
// }

Rork App Frontend Integration

Here's how to call the agent API from a React Native component in your Rork app.

// components/AIAssistant.tsx
// AI assistant component for Rork apps
import React, { useState } from 'react';
import {
  View, Text, TextInput, TouchableOpacity,
  FlatList, ActivityIndicator, StyleSheet
} from 'react-native';
 
interface Message {
  role: 'user' | 'assistant';
  content: string;
  actions?: Array<{ type: string; payload: any }>;
}
 
const AGENT_API = 'https://your-worker.your-domain.workers.dev/agent';
 
export default function AIAssistant() {
  const [messages, setMessages] = useState<Message[]>([]);
  const [input, setInput] = useState('');
  const [loading, setLoading] = useState(false);
 
  const sendMessage = async () => {
    if (!input.trim()) return;
 
    const userMessage: Message = { role: 'user', content: input };
    setMessages(prev => [...prev, userMessage]);
    setInput('');
    setLoading(true);
 
    try {
      const response = await fetch(AGENT_API, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer YOUR_TOKEN',
        },
        body: JSON.stringify({
          userId: 'current-user-id',
          message: input,
          context: { currentScreen: 'home' },
        }),
      });
 
      const data = await response.json();
 
      const assistantMessage: Message = {
        role: 'assistant',
        content: data.reply,
        actions: data.actions,
      };
      setMessages(prev => [...prev, assistantMessage]);
 
      // Execute agent actions
      if (data.actions) {
        for (const action of data.actions) {
          handleAgentAction(action);
        }
      }
    } catch (error) {
      setMessages(prev => [...prev, {
        role: 'assistant',
        content: 'Sorry, a temporary error occurred. Please try again.'
      }]);
    } finally {
      setLoading(false);
    }
  };
 
  const handleAgentAction = (action: { type: string; payload: any }) => {
    switch (action.type) {
      case 'navigate_to_screen':
        // Navigate using React Navigation
        // navigation.navigate(action.payload.screen);
        break;
      case 'search_products':
        // Execute product search
        break;
      case 'create_reminder':
        // Set a reminder
        break;
    }
  };
 
  return (
    <View style={styles.container}>
      <FlatList
        data={messages}
        keyExtractor={(_, index) => index.toString()}
        renderItem={({ item }) => (
          <View style={[
            styles.message,
            item.role === 'user' ? styles.userMessage : styles.assistantMessage
          ]}>
            <Text style={styles.messageText}>{item.content}</Text>
          </View>
        )}
      />
      {loading && <ActivityIndicator size="small" />}
      <View style={styles.inputContainer}>
        <TextInput
          style={styles.input}
          value={input}
          onChangeText={setInput}
          placeholder="Ask the AI assistant..."
        />
        <TouchableOpacity onPress={sendMessage} style={styles.sendButton}>
          <Text style={styles.sendText}>Send</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}
 
const styles = StyleSheet.create({
  container: { flex: 1, padding: 16 },
  message: { padding: 12, borderRadius: 8, marginVertical: 4 },
  userMessage: { backgroundColor: '#E3F2FD', alignSelf: 'flex-end' },
  assistantMessage: { backgroundColor: '#F5F5F5', alignSelf: 'flex-start' },
  messageText: { fontSize: 16 },
  inputContainer: { flexDirection: 'row', alignItems: 'center', marginTop: 8 },
  input: { flex: 1, borderWidth: 1, borderColor: '#DDD', borderRadius: 8, padding: 12 },
  sendButton: { marginLeft: 8, backgroundColor: '#2196F3', padding: 12, borderRadius: 8 },
  sendText: { color: '#FFF', fontWeight: 'bold' },
});

Securing the Mobile API with OpenShell

NemoClaw's OpenShell policy restricts what the mobile-facing agent can access.

# mobile-agent-policy.yaml
# Security policy for mobile app-facing agent
version: "1.0"
name: "rork-mobile-agent"
 
network:
  allowed_domains:
    - "api.stripe.com"           # Billing data (read-only)
    - "your-database.com"        # App data
  default: "deny"
 
commands:
  allowed:
    - "node"
  blocked:
    - "rm"
    - "git"
    - "curl"
  default: "deny"
 
filesystem:
  read_only:
    - "/app/config"
  default: "deny"

Since mobile app requests originate from untrusted user devices, keeping agent permissions minimal is essential.

Practical Use Cases

E-Commerce Purchase Assistant

When a user types "red sneakers under $80," the agent searches your product database, returns matching items, and can even add selections to the cart when instructed — all through natural conversation.

Healthcare Personal Coach

The agent analyzes a user's exercise data and meal logs, then generates personalized suggestions like "Your protein intake is low today — consider adding grilled chicken to dinner."

Wrapping Up — AI Agents Transform the App Experience

Thanks to NemoClaw, integrating AI agents into mobile apps is far more accessible than before. An API Gateway layer handles auth and rate limiting, while OpenShell governs agent permissions — this dual-layer approach delivers secure, high-quality AI assistant features in your Rork app.

Start with a simple Q&A feature, gauge user response, and progressively add action capabilities from there.

For more on AI agent and app development, check out our OpenClaw Mobile App Integration and OpenClaw × Rork AI Partner App.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

◉ AI Models2026-10-14
Take the Prompt Out of the App: An Edge Function Gateway With the Guard on the Output Side
A system prompt shipped inside your app is readable from the day it ships. This walkthrough moves the prompt into a Supabase Edge Function, lets the client name only a task, and puts the guard on an output allowlist, with tested code.
◉ AI Models2026-10-05
Sonnet 5.5, GPT-6.1 Sol, or Opus 5.5? I Decide by the Kind of Fix Before I Pick the Model. A Week of Logging Where My Rork Credits Went
After Rork's model menu settled into Sonnet 5.5, GPT-6.1 Sol, and Opus 5.5, I sorted my fixes into three kinds and assigned a model and effort level to each. Here is how I read the changelog, the tiny ledger that tracks where each credit goes, and the rule I drew from a week of entries.
◉ AI Models2026-09-28
Keep Fixing in the Same Thread, or Restore and Rephrase? What I Learned Fixing One Rork Bug Both Ways
When a Rork fix request fails for the third time, do you keep going or use Restore and ask differently? I fixed the same bug both ways and compared round trips, leftover code, and where I now draw the line.