Gemma 4 Agents.
Now With Offline Authorization.

An Apache-2.0 package for Node.js-based on-device agent workflows — bounded offline verification, explicit consent records, and optional signed local audit logs.

npm npm install @grantex/gemma Copy
Read the Docs →
📱 Android Gemma 4
🧠 Agent On-Device
🔒 Grantex ConsentBundle
Verified locally · No network during a valid offline window
Day-zero integration Apache 2.0 Test-runner benchmark only Validate each device runtime

On-device agents need an explicit authorization layer

Gemma 4 runs locally — but your security model still assumes a cloud connection. These are the gaps.

🔑

API keys with no scope boundaries

An agent that carries a broad API key may lack per-action scope and expiry boundaries. Put verification at each protected action instead of relying on the model to limit itself.

📡

Unsigned offline logs are hard to trust

Without a configured local audit sink, offline actions may be recorded only in mutable application logs. Signed, hash-chained records can make later modification evident, but do not by themselves establish compliance.

No mid-session revocation without connectivity

If a user wants to stop an agent mid-task, they need network access to reach a revocation endpoint. Offline, a verifier cannot learn newer revocation state and may continue accepting a still-valid bundle until its configured offline TTL expires.

ConsentBundle: issue online, verify within a bounded offline TTL

A signed bundle contains cached token and key material for a configured offline window. It cannot discover key rotation or revocation changes until connectivity and synchronization return.

1

Issue online

Human approves scopes via consent flow. Grantex bundles the grant token, JWKS snapshot, and audit signing key.

One-time
2

Verify locally

The verifier checks the JWT and scopes against the bundled JWKS snapshot within the configured offline TTL. It cannot observe newer revocation state while disconnected.

Offline
3

Log locally, signed

Configured tool actions are appended to an Ed25519-signed, hash-chained audit log on the device.

Tamper-evident
4

Revocation at sync

When connectivity returns, the agent syncs its audit log and checks for revocation updates.

Resilient

Three phases. Ten lines each.

Issue a consent bundle online, then verify configured tools during its bounded offline TTL. Works with TypeScript, Python, and Google ADK.

import { createConsentBundle, createOfflineVerifier, createOfflineAuditLog } from '@grantex/gemma';

// Phase 1: Online — issue consent bundle (once)
const bundle = await createConsentBundle({
  apiKey: process.env.GRANTEX_API_KEY,
  agentId: 'ag_01HXYZ',
  userId: 'user_abc',
  scopes: ['calendar:read', 'files:write:max_10mb'],
  offlineTTL: '72h',
});

// Phase 2: Offline — verify within the configured TTL; benchmark your device
const verifier = createOfflineVerifier({
  jwksSnapshot: bundle.jwksSnapshot,
  requireScopes: ['calendar:read'],
});
const grant = await verifier.verify(bundle.grantToken);

// Phase 3: Audit — Ed25519-signed, hash-chained
const auditLog = createOfflineAuditLog({
  signingKey: bundle.offlineAuditKey,
  logPath: '/var/grantex/audit.jsonl',
});
await auditLog.append({
  action: 'calendar.read',
  agentDID: grant.agentDID,
  grantId: grant.jti,
  scopes: ['calendar:read'],
  result: 'success',
});
from grantex_gemma import (
    create_consent_bundle,
    create_offline_verifier,
    create_offline_audit_log,
)

# Phase 1: Online — issue consent bundle (once)
bundle = await create_consent_bundle(
    api_key=os.environ["GRANTEX_API_KEY"],
    agent_id="ag_01HXYZ",
    user_id="user_abc",
    scopes=["files:read", "email:send:max_10"],
    offline_ttl="48h",
)

# Phase 2: Offline — verify within the configured TTL; benchmark your device
verifier = create_offline_verifier(
    jwks_snapshot=bundle.jwks_snapshot,
)
grant = await verifier.verify(bundle.grant_token)

# Phase 3: Audit — Ed25519-signed, hash-chained
audit_log = create_offline_audit_log(
    signing_key=bundle.offline_audit_key,
    log_path="/var/grantex/audit.jsonl",
)
await audit_log.append(
    action="files.read",
    agent_did=grant.agent_did,
    grant_id=grant.jti,
    scopes=["files:read"],
    result="success",
)
import { withGrantexAuthADK, createOfflineVerifier, createOfflineAuditLog } from '@grantex/gemma';

// Wrap a configured Google ADK tool with offline authorization
const verifier = createOfflineVerifier({
  jwksSnapshot: bundle.jwksSnapshot,
});

const auditLog = createOfflineAuditLog({
  signingKey: bundle.offlineAuditKey,
  logPath: '/var/grantex/audit.jsonl',
});

// One line to protect any tool
const securedCalendarTool = withGrantexAuthADK(calendarTool, {
  verifier,
  auditLog,
  grantToken: bundle.grantToken,
  requiredScopes: ['calendar:write'],
});

// Tool now auto-verifies grants and logs every invocation
const securedEmailTool = withGrantexAuthADK(emailTool, {
  verifier,
  auditLog,
  grantToken: bundle.grantToken,
  requiredScopes: ['email:send'],
});

Runtime requirements

The current TypeScript package targets Node.js 18+ and uses a writable filesystem for its offline audit log. Validate Web Crypto, Ed25519, and storage support on any device runtime before deployment.

📱

Node.js 18+

Required by the published package

🍎

Web Crypto

Ed25519 verification and signing support

💻

Filesystem

Writable path for the JSONL audit log

🎮

JWKS snapshot

Pre-fetched keys for offline verification

🖥

Device testing

Required for each target runtime

Repository performance checks

The repository tests local verification performance on the test runner. Device-specific benchmark methodology and reproducible hardware results are not published yet.

Platform Verification Memory
Verifier unit test Under-5ms repository test target; not a device SLA Not measured
Production E2E test Under-5ms average in the repository test; not a device SLA Not measured
Device-specific results Not published Not published

Works With Your Stack

First-class adapters for the frameworks developers actually use. Wrap any tool with one line.

Get Started in 60 Seconds

npm npm install @grantex/gemma Copy
pip pip install grantex-gemma Copy