Offline Protocol CLI (offline)
One CLI to build offline-first apps on the Offline Protocol ecosystem — and the MCP server that makes the whole ecosystem AI-native.
New here? → docs/QUICKSTART.md (install, first app, MCP with AI agents)
What's inside
| Crate | Purpose |
|---|---|
crates/offline-cli |
The offline binary: login, create, init, add, plan, doctor, update, registry, skills, mcp |
crates/offline-registry |
Knowledge core: packages, skills, workflows, templates — embedded, fully offline |
crates/offline-generator |
Tera-based project scaffolding (used by create and MCP scaffold_project) |
crates/offline-mcp |
Model Context Protocol server: plan, scaffold, and integrate Offline Protocol components |
crates/offline-registry/registry/ |
Content: packages, skills, workflows, starter templates |
Workflows & templates
The three entrances for operational apps come first; the planner selects them from prompts about handoffs, retained events for a backend, or calling a service on a nearby device. Each starter ships the application logic the SDK leaves to you (durable records, stable IDs, explicit acceptance, retries, recovery) with tests, and the first two include a reference backend.
| Workflow | Templates |
|---|---|
local-handoff (share a local workflow) |
react-native-mesh-handoff |
backend-delivery (deliver retained events to a backend) |
react-native-mesh-event-delivery |
nearby-service (discover and invoke a nearby service) |
react-native-mesh-service |
custom-p2p-app |
react-native-mesh-custom-app |
offline-social-network |
react-native-social, nextjs-social, react-vite-social |
offline-id-mesh-chat |
react-native-social (+ mesh via enableMesh) |
offline-id-mobile |
react-native-id-only |
nearby-chat |
react-native-mesh-app |
group-messaging |
react-native-mesh-app |
Example app scaffolds
Full React Native sample apps from offline-app-examples
(vendored packages/mesh, packages/ui, and native android/ios):
| Template | Demonstrates |
|---|---|
orderup |
Host-authoritative kitchen POS: waiters send orders over Bluetooth mesh to a kitchen display |
stocksync |
Shared inventory counter with host-authoritative sync and optimistic taps |
cowrite |
Collaborative plain-text editing with MLS group sync and live cursors |
Regenerate embedded copies after changing the upstream examples:
Install
The installed command is always offline.
npm (recommended):
crates.io: not available yet. The offline-cli crate on crates.io is a
placeholder until the first real publish; use npm or build from source.
From source (developers):
From GitHub Releases (archives + SHA256SUMS; members of the
Offline-Protocol organization only, because the repository is internal):
- Download the archive for your platform from Offline-Protocol/CLI releases
- Verify with
SHA256SUMSor the matching.sha256file - Extract and put
offlineon yourPATH - Run
offline doctorandoffline update
Maintainer release process: docs/RELEASING.md.
Homebrew distribution is still planned.
Command reference
Quick map of top-level commands. Full descriptions, flags, and examples: docs/COMMANDS.md.
| Command | Purpose |
|---|---|
offline login / logout / whoami |
Interactive auth (localhost callback + poll); logout revokes the key server-side when possible |
offline login --email |
The same login without a browser (SSH, agents). Both ways store the developer session that setup, orgs, apps and keys need; on SSH or a machine with no display, offline login prints the URL instead of opening a browser |
offline login --email <address> --code <code> |
Finish the email sign-in without a prompt (agents, CI). Without a terminal, offline login --email <address> sends the code and exits |
offline setup / orgs / apps / keys |
Provision and manage organizations, applications and API keys (need a developer session). setup reuses the API key this machine already made for the app |
offline org use <org> / --org <id> |
Set the default organization (asked once at login if you belong to several), or override it for one command |
offline apps status |
What the application has set up and what is missing for sign-in on iOS, Android, web and server, with the command that fixes each gap |
offline apps native add/remove/list/detect/dev-builds |
Native apps for app attestation: iOS bundle ID + Team ID, Android package + signing-certificate SHA-256; detect reads them from app.json, Xcode, Gradle and assetlinks.json |
offline apps native dev-mode on --hours N / off |
Development mode (1-72 hours, ends by itself): simulators, emulators and Expo Go sign in without attestation, email codes only |
offline apps native production on/off, degraded allow/refuse, history |
Mark the app production (no development mode), the policy for Android phones that cannot fully attest, and the audit history |
offline apps native setup-project [--write] |
Expo: add the App Attest entitlement to app.json and print the packages to install |
offline apps origins add/remove/list |
Web origins allowed to sign in from a browser |
offline apps features enable/disable/list |
Product features: telemetry, relay, proof-of-location |
offline apply [--detect] [--dry-run] |
Converge the application to the app block of offline.config.json (native apps, origins, features); additive and idempotent |
offline create |
Scaffold from workflow, template, or --prompt; runs npm install and starts the dev server (Metro for React Native) unless --skip-setup |
offline plan |
Plan only (workflow + packages + optional architecture docs) |
offline init |
Wire offline.config.json, .mcp.json, AGENTS.md into an existing app |
offline add <package> |
Add package (+ transitive requires) to package.json |
offline doctor |
Toolchain + auth + API reachability checks |
offline update |
Check npm for a newer CLI and print the upgrade command |
offline registry … |
List / search / show packages, workflows, skills, templates, capabilities; export llms.txt |
offline skills list / show |
List or read an integration skill |
offline mcp serve |
Run the MCP server (stdio) |
offline mcp install <client> |
Print client config (cursor, claude-desktop, vscode, claude-code, codex) |
offline mcp tools |
List MCP tools |
offline completions <shell> |
Shell completions |
offline login (browser) stores an application API key, which create and
whoami --verify use. Local BLE mesh starters (nearby-chat,
group-messaging, custom-p2p-app) scaffold without a login, as
does the local MCP server. A template opts out of the login step with
"requiresLogin": false in its template.json. setup, orgs,
apps and keys call the developer management API and need the developer
session that offline login stores; after offline login --api-key (CI) only,
they stop with an error that says so. When the API key is shared with the application,
offline logout clears this machine but leaves the key active; revoke it in the
developer portal if you no longer need it.
Every informational command supports --json. Config: ~/.offline/config.json (0600).
Overrides: OFFLINE_API_KEY, OFFLINE_API_BASE, OFFLINE_ENV (prod or dev/local),
OFFLINE_PORTAL_BASE, OFFLINE_CONFIG_DIR, OFFLINE_REGISTRY_DIR,
OFFLINE_CALLBACK_PORT (pin the localhost login callback port; default: an ephemeral port).
The npm launcher forwards SIGINT, SIGTERM and SIGHUP to the native binary and
exits with its status; OFFLINE_CLI_BINARY points the launcher at a locally
built binary.
What the CLI stores and sends
Stored on your computer. offline login and offline login --email write
~/.offline/config.json (or $OFFLINE_CONFIG_DIR/config.json): the
application API key, the developer session token from email sign-in, your
email address, developer, organization and application IDs, and any API or
portal base URL you set. The file is plain JSON, not encrypted and not in the
system keychain. On macOS and Linux the CLI creates it owner read and write
only (0600), replaces it atomically, keeps ~/.offline owner-only (0700) and
refuses a symlinked file or a directory other users can write to; on Windows
it keeps the default permissions of your user profile folder. Anyone who can
read the file can use the key.
Removed by offline logout. It deletes the file. A key the CLI created
for itself is also revoked on the server; a key shared with the application
stays active until you revoke it in the developer portal. After email
sign-in, logout clears the session token from this computer.
Sent to Offline Protocol. Sign-in requests (including this computer's
hostname as the device name, shown when you approve the sign-in), and the
calls each command makes to the developer API at api.offlineprotocol.com
with your key or session. The hosted MCP server
(mcp.offlineprotocol.com) receives the tool arguments your agent sends and
returns results; it keeps rate-limit counters, keyed by a hash of the
credential or by client address, in memory for about 90 seconds.
Sent elsewhere. offline update asks the public npm registry
(registry.npmjs.org, or OFFLINE_NPM_REGISTRY) for the latest
@offline-protocol/cli version, only when you run it. Scaffolding and the
local MCP server's scaffold_project and integrate_packages tools run
npm install and similar package-manager commands, which contact the package
registries you have configured. The AI agent or client you connect to the MCP
server receives tool inputs and results, and handles them under its own
terms.
No telemetry. The CLI and the local MCP server send no usage analytics and no crash reports.
Local MCP tools act with your permissions. offline mcp serve can write
files in your project and run package-manager commands, subject to your
agent client's approval settings. It is not sandboxed. The hosted MCP server
refuses those tools.
The privacy policy covers the same points for every Offline Protocol service. Report security issues to security@offlineprotocol.com (SECURITY.md).
For AI agents (MCP)
The MCP server is local stdio inside the CLI — no separate cloud deploy. Agents plan and integrate Offline Protocol components via tools (not from memory).
Set up Cursor / Claude
# Pick ONE client (do not use | — the shell treats it as a pipe):
# Claude Code shortcut:
# Codex shortcut:
Paste the printed JSON into the client’s MCP config. Ensure offline is on PATH,
then reload the agent / MCP session.
Ask the agent to create a project
Use Agent mode and a prompt like:
Using the offline-protocol MCP only (do not invent package names or SDK APIs):
1. Call generate_architecture with my idea.
2. Follow nextActions.
3. Call scaffold_project with name="festival-pulse" and platform="react-native".
4. Call get_skill for every skill listed before writing Offline Protocol code.
Idea: nearby festival chat with Offline ID login and BLE mesh messaging
Or use the MCP prompt plan-app with description, optional platform, and name.
Flow: generate_architecture → scaffold_project (new) or integrate_packages + init_project (existing) → get_skill → app code.
Full tool list and rules: docs/MCP.md.
Development
# live registry content (not the embedded copy):
OFFLINE_REGISTRY_DIR=./crates/offline-registry/registry
# local API gateway (typically :3010):
OFFLINE_ENV=dev
CI & releases
| Workflow | Trigger | What it does |
|---|---|---|
.github/workflows/ci.yml |
PR + push to main |
fmt, clippy, tests; release-build smoke on main |
.github/workflows/release.yml |
tag v* or manual bump |
Bumps version, updates CHANGELOG.md, builds binaries, publishes GitHub Release |
Manual release: Actions → Release → bump patch/minor/major (needs RELEASE_PAT).
Or push a tag: git tag v0.1.2 && git push origin v0.1.2 (add a CHANGELOG.md section for that version first if you skip the bump job).
Release notes on GitHub come from the matching ## [x.y.z] section in CHANGELOG.md, which git-cliff refreshes during the bump job (cliff.toml).
Documentation
- docs/QUICKSTART.md — install, portal login, first scaffold, MCP with AI agents
- docs/README.md — documentation index (coverage map for every command)
- docs/COMMANDS.md — full command reference
- docs/ARCHITECTURE.md — crates, planner, MCP integrate loop
- docs/REGISTRY.md — registry schema and authoring
- docs/MCP.md — MCP tools, agent prompts, local vs hosted
- docs/MCP-MESH-APP.md — React Native mesh scaffold flow
- docs/AUTH.md — device-flow login / logout
- CHANGELOG.md — release history
Contributing
See CONTRIBUTING.md for setup, PR expectations, and registry guidelines. Please follow the Code of Conduct.
Security reports: SECURITY.md (do not file public issues for vulnerabilities).
License
Licensed under the Apache License, Version 2.0. See NOTICE for copyright attribution.
Terms and privacy
The CLI's source code is licensed under Apache-2.0 (above). Signing in with
offline login, and using the Offline Protocol developer portal, the hosted
MCP server at mcp.offlineprotocol.com, and hosted services, are governed by
the Developer Terms of Service
and the Acceptable Use Policy.
The Privacy Policy explains what the
CLI stores on your computer and what it sends to Offline Protocol. All legal
documents: offlineprotocol.com/legal.
Status
Shipped: device-flow auth, deterministic planning, Tera scaffolds, MCP plan + scaffold + integrate,
CI, multi-platform GitHub Releases, offline update.
Also shipped: hosted MCP (Streamable HTTP) at https://mcp.offlineprotocol.com/mcp
(read-only tools; see docs/MCP-HOSTED.md).
Not yet: hosted registry refresh, Homebrew tap, official crates.io publish (install with npm until then).
Agent plugins and distribution
The agent plugin package provides a shared integration skill and local MCP configuration for Codex, Claude Code, Cursor and Gemini CLI. These packages are review candidates; public listings and client verification are tracked in the distribution plan.
Validate packaging with node scripts/check-agent-distribution.mjs; add --smoke to test the pinned published CLI over MCP.
node scripts/check-guidance.mjs fails on SDK guidance that is known to be wrong (web appId on id-react, camelCase event fields, string priorities, Wi-Fi Direct enabled in a cross-platform starter or listed next to BLE as an equal transport, the removed telemetry sink, a Maven Central dependency line for the Android preview before 0.29.0 or for Java before 0.30.0, a pub.dev line, a "no package" claim or a refused Nostr config for the Flutter plugin, a Ruby gem line before 0.31.0 or a "not on RubyGems" claim, an npm line for the browser binding's unpublished JavaScript client, a NuGet line for the C# binding, a silent React Native fallback); CI runs it on every pull request.
node scripts/scaffold-matrix.mjs generates every starter template variant with a locally built offline, installs the exact package versions the registry pins, and runs tsc --noEmit; the Scaffolds workflow runs it for every variant on pull requests that touch the registry, generator or CLI. OFFLINE_BIN=target/debug/offline node scripts/agent-readiness-e2e.mjs runs the MCP readiness scenarios against a local build instead of the published npm package.