Building 'Offline Brain': How I Wrote My First Custom Agent Skill for Android (Google I/O 2026) π±π§
Local-First Agent Runtimes: Implementing Custom Skills on Android with LiteRT-LM
Current Situation Analysis
Mobile AI development has long been constrained by a binary choice: leverage powerful cloud-based models with associated latency, privacy risks, and connectivity dependencies, or utilize limited on-device models that lack robust tool-use capabilities. This dichotomy forces developers to either compromise user privacy by proxying sensitive data through external APIs or accept a degraded user experience with offline-only constraints.
The industry is shifting toward Zero-Trust Agent Architectures, where the inference engine, tool execution, and data storage reside entirely within the device's secure boundary. Google AI Edge Gallery represents a critical inflection point in this evolution. By integrating the LiteRT-LM engine with the Gemma-4-E2B-it model, the platform now supports a full agent runtime on-device. This includes a 32K context window and fine-tuned tool-calling capabilities, previously exclusive to server-side infrastructure.
Despite these advancements, many developers overlook the extensibility of this runtime. The platform supports custom Agent Skills via an open standard compatible with the Model Context Protocol (MCP), allowing developers to inject domain-specific logic directly into the agent's decision loop. This enables scenarios where personal data, such as health metrics or development logs, can be processed by an AI without ever leaving the device silicon.
WOW Moment: Key Findings
The transition to local agent runtimes fundamentally alters the trade-off matrix for mobile AI applications. The following comparison highlights the operational differences between traditional cloud-dependent agents and the new Edge Gallery architecture.
| Feature | Cloud-Dependent Agent | Edge Gallery Agent |
|---|---|---|
| Inference Latency | 500ms β 2s (Network dependent) | <200ms (On-device silicon) |
| Data Privacy | Server-side processing; data egress | Zero-Trust; Local Sandbox execution |
| Offline Availability | None; requires connectivity | Full; runtime operates without network |
| Context Window | Variable; API rate limits apply | 32K tokens (Gemma-4-E2B-it) |
| Tool Execution | Remote function calls | Local V8 JavaScript runtime |
| Model Footprint | N/A (Server cost) | ~2.6GB (Gemma-4-E2B-it quantized) |
Why this matters: The 32K context window on-device is the critical enabler. In previous local models, tool execution outputs would rapidly consume available context, causing the model to forget earlier instructions or conversation history. With Gemma-4-E2B-it, the agent can maintain a long-running dialogue while dynamically invoking local tools, retrieving data, and retaining the full state of the interaction. This allows for complex, multi-step workflows that were previously impossible on mobile hardware.
Core Solution
Building a custom Agent Skill requires defining a contract via a manifest, implementing logic in a sandboxed JavaScript runtime, and packaging the artifacts for ingestion by Edge Gallery. The following implementation demonstrates a "Secure Vault" skill that archives and retrieves encrypted records locally.
1. Define the Skill Manifest
The manifest acts as the security boundary and interface definition. Edge Gallery parses this JSON to expose tools to the model and enforce permission checks. The structure aligns with MCP standards but is optimized for mobile sandbox constraints.
Create secure-vault-manifest.json:
{
"skill_id": "com.example.secure_vault",
"name": "Secure Vault",
"description": "Archives and retrieves encrypted records in local storage.",
"version": "1.0.0",
"permissions": [
"storage.read_local",
"storage.write_local"
],
"tools": [
{
"name": "archive_record",
"description": "Stores a new encrypted record under a unique identifier.",
"parameters": {
"type": "object",
"properties": {
"record_id": {
"type": "string",
"description": "Unique identifier for the record."
},
"payload": {
"type": "string",
"description": "The content to be archived."
}
},
"required": ["record_id", "payload"]
}
},
{
"name": "query_vault",
"description": "Retrieves a record by its identifier.",
"parameters": {
"type": "object",
"properties": {
"record_id": {
"type": "string",
"description": "The identifier of the record to fetch."
}
},
"required": ["record_id"]
}
}
]
}
Architecture Decision: Permissions are explicitly declared. If the skill attempts to access resources outside the declared scope, the LiteRT-LM engine intercepts the call and denies execution. This ensures the skill operates within a least-privilege model.
2. Implement the Logic Layer
Edge Gallery provides a lightweight V8 JavaScript runtime for skill execution. This runtime exposes a sandboxed file system API, preventing arbitrary access to the device. Implement the tool logic in vault_engine.js.
// vault_engine.js
// Runtime: V8 Sandbox via Edge Gallery
// API: EdgeSandboxIO
export async function archive_record(params) {
try {
const epoch = Date.now();
const vaultPath = `vault/${params.record_id}.enc`;
// Construct payload with metadata
const record = {
created: epoch,
data: params.payload
};
// Write to sandboxed storage
await EdgeSandboxIO.writeFile(vaultPath, JSON.stringify(record));
return {
success: true,
message: `Record archived successfully.`,
meta: { id: params.record_id, timestamp: epoch }
};
} catch (error) {
return {
success: false,
error: `Archive failed: ${error.message}`
};
}
}
export async function query_vault(params) {
try {
const vaultPath = `vault/${params.record_id}.enc`;
// Check existence before read to avoid exceptions
const exists = await EdgeSandboxIO.exists(vaultPath);
if (!exists) {
return {
success: false,
message: `Record ${params.record_id} not found.`
};
}
const rawContent = await EdgeSandboxIO.readFile(vaultPath);
const record = JSON.parse(rawContent);
return {
success: true,
data: record.data,
meta: { created: record.created }
};
} catch (error) {
return {
success: false,
error: `Query failed: ${error.message}`
};
}
}
Rationale: The logic uses async/await to handle I/O operations non-blockingly. The EdgeSandboxIO API is used instead of standard Node.js fs modules, ensuring the code runs safely within the mobile sandbox. Error handling returns structured objects, allowing the model to parse failures gracefully.
3. Package and Sideload
- Package: Compress
secure-vault-manifest.jsonandvault_engine.jsinto a single archive namedsecure-vault.skill. The files must be at the root of the archive. - Model Selection: Download Gemma-4-E2B-it (approx. 2.6 GB) within Edge Gallery.
- Critical Note: You must use the Gemma 4 variant. Earlier iterations like Gemma 3 lack the specific fine-tuning required for reliable tool-calling in the Agent Skills framework.
- Import: Navigate to the Agent Skills section in Edge Gallery, tap the import action, and select the
.skillfile. The skill will appear in the registry with a toggle control.
4. Execution Flow
Once enabled, the model can invoke the tools during chat. For example:
User: "Archive a note about the new auth flow. Use ID 'auth-v2'."
Model: Evaluates tools. Invokes
archive_recordwithrecord_id="auth-v2"andpayload="...".Skill: Writes to
vault/auth-v2.encviaEdgeSandboxIO. Returns success.Model: "Record archived under ID auth-v2."
The 32K context window ensures that subsequent queries can reference this interaction without losing earlier conversation state, even after multiple tool calls.
Pitfall Guide
Developers implementing custom skills often encounter specific constraints related to the sandbox environment and model behavior. The following pitfalls highlight common errors and their resolutions.
Model Version Mismatch
- Issue: Using Gemma 3 or unquantized variants results in the model failing to generate tool calls or hallucinating tool names.
- Fix: Always download and select Gemma-4-E2B-it. This model includes the necessary fine-tunes for the Agent Skills tool-calling protocol.
Permission Denial
- Issue: The skill attempts to read a file or access a resource without declaring the corresponding permission in the manifest. The LiteRT-LM engine blocks the call silently or returns an error.
- Fix: Audit all file paths and resource accesses. Ensure every required permission (e.g.,
storage.read_local) is listed in thepermissionsarray of the manifest.
Blocking I/O in V8 Runtime
- Issue: Using synchronous file operations or blocking loops in the JavaScript logic causes the sandbox to timeout or freeze the agent response.
- Fix: All I/O operations must use the asynchronous
EdgeSandboxIOmethods withawait. Avoid CPU-intensive loops; offload heavy computation or keep it minimal.
Context Window Bloat
- Issue: Returning large payloads from tools consumes tokens rapidly, reducing the effective context for the conversation.
- Fix: Return metadata or summaries from tools. If the model needs full content, design a two-step process: first retrieve a list of references, then fetch specific items on demand.
Path Traversal Vulnerabilities
- Issue: User input used directly in file paths could potentially escape the sandbox directory if not sanitized.
- Fix: Validate and sanitize all user-provided identifiers before constructing file paths. Use strict regex patterns to allow only alphanumeric characters and safe separators.
Zip Structure Errors
- Issue: The
.skillarchive contains nested folders, causing Edge Gallery to fail parsing the manifest. - Fix: Ensure the manifest and script files are at the root level of the zip archive. No parent directories should be included.
- Issue: The
Error Propagation Failures
- Issue: The JavaScript function throws an unhandled exception, causing the tool call to fail without a structured error message. The model cannot recover.
- Fix: Wrap all logic in
try/catchblocks. Return a consistent error object structure so the model can interpret the failure and adjust its strategy.
Production Bundle
Action Checklist
- Verify Device Resources: Ensure the target device has sufficient storage (~3GB) and RAM to host Gemma-4-E2B-it and the runtime.
- Draft Manifest: Define
skill_id, permissions, and tool schemas. Validate JSON syntax. - Implement Logic: Write JavaScript using
EdgeSandboxIO. Include error handling and input sanitization. - Package Artifacts: Create a
.skillzip with files at the root level. - Select Model: Download Gemma-4-E2B-it in Edge Gallery. Confirm version.
- Import Skill: Load the
.skillfile via the Agent Skills interface. - Test Tool Calls: Verify the model invokes tools correctly and handles errors.
- Validate Context: Test multi-turn conversations to ensure 32K window retention.
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|---|---|---|
| High Privacy Requirements | Edge Gallery Skill | Zero data egress; local sandbox execution. | Storage cost for model (~2.6GB). |
| Complex Reasoning / Large Context | Cloud API Integration | Access to larger models and unlimited context. | API usage costs; latency. |
| Offline-First Apps | Edge Gallery Skill | Full functionality without network connectivity. | Device resource usage. |
| Rapid Prototyping | Cloud API | Faster iteration; no model management. | Recurring API costs. |
| Hybrid Workflows | Edge + Cloud | Use Edge for sensitive data; Cloud for heavy lifting. | Increased architectural complexity. |
Configuration Template
Manifest Template (skill-manifest.json):
{
"skill_id": "com.yourdomain.skill_name",
"name": "Skill Name",
"description": "Brief description of capabilities.",
"version": "1.0.0",
"permissions": [
"storage.read_local",
"storage.write_local"
],
"tools": [
{
"name": "tool_name",
"description": "Description for model understanding.",
"parameters": {
"type": "object",
"properties": {
"param_key": {
"type": "string",
"description": "Parameter description."
}
},
"required": ["param_key"]
}
}
]
}
Logic Template (engine.js):
export async function tool_name(params) {
try {
// Sanitize inputs
const safeKey = String(params.param_key).replace(/[^a-zA-Z0-9_-]/g, '');
// Perform sandbox operation
const result = await EdgeSandboxIO.readFile(`data/${safeKey}.json`);
return {
success: true,
data: JSON.parse(result)
};
} catch (err) {
return {
success: false,
error: err.message
};
}
}
Quick Start Guide
- Install Edge Gallery: Download the application from the official distribution channel.
- Download Model: Navigate to the model manager and download Gemma-4-E2B-it. Wait for completion.
- Create Skill: Write your manifest and JavaScript logic. Zip them into a
.skillfile. - Import: Open Edge Gallery, go to Agent Skills, and import your
.skillfile. - Run: Enable the skill and start a chat. Test tool invocation with natural language prompts.
Mid-Year Sale β Unlock Full Article
Base plan from just $4.99/mo or $49/yr
Sign in to read the full article and unlock all tutorials.
Sign In / Register β Start Free Trial7-day free trial Β· Cancel anytime Β· 30-day money-back
