Cloud Services¶
Jarvis is self-hosted first --- every service can run on your own hardware. But three services are designed to optionally run on cloud infrastructure, providing capabilities that benefit from public internet access.
Architecture¶
graph TB
subgraph Self-Hosted ["Self-Hosted (your network)"]
direction TB
CC["Command Center<br/>:7703"]
Auth["Auth<br/>:7701"]
Notify["Notifications<br/>:7712"]
Node["Pi Zero Nodes"]
Mobile["Mobile App"]
end
subgraph Cloud ["Cloud (optional)"]
direction TB
Pantry["Pantry<br/>:7720"]
Relay["Notifications Relay"]
Web["Web Chat<br/>:7722"]
end
subgraph External ["External"]
Expo["Expo Push API"]
GitHub["GitHub"]
APNs["APNs / FCM"]
end
Node -->|voice commands| CC
Mobile -->|chat, settings| CC
Mobile -->|OAuth bounce| Relay
CC -->|browse/install| Pantry
Pantry -->|clone repos| GitHub
Notify -->|push delivery| Relay
Relay -->|forward| Expo
Expo -->|deliver| APNs
Web -->|proxy| CC
Web -->|login| Auth
Design Principles¶
No data leaves your network by default. Cloud services are opt-in and handle only what they must:
- Pantry serves a catalog and validates submissions --- your command code runs locally, never on Pantry servers
- Relay forwards push notification payloads to Expo --- it never stores messages, and rate-limits aggressively
- Web is a thin proxy to your command center --- all processing happens on your self-hosted infrastructure
Each cloud service is stateless or nearly so, meaning you can run your own instance or use a shared one.
Pantry (Command Store)¶
The community marketplace. Authors publish commands; users browse and install them with one CLI command.
Port: 7720 | Stack: FastAPI + PostgreSQL | Auth: GitHub OAuth (authors) + household JWT (nodes)
Pantry is the HACS-style command store for Jarvis. It hosts a catalog of community-built commands, agents, device protocols, device managers, and routines that any node can install.
How It Works¶
sequenceDiagram
participant Author
participant Pantry
participant GitHub
participant Node
Author->>Pantry: Submit (GitHub OAuth)
Pantry->>GitHub: Clone repo, validate structure
Pantry->>Pantry: Static analysis + security review
Pantry->>Pantry: Container tests (Docker sandbox)
Pantry-->>Author: Published (or rejection with feedback)
Node->>Pantry: Search/browse catalog
Pantry-->>Node: Command metadata + manifest
Node->>GitHub: Clone repo directly
Node->>Node: Install via install_command.py
Submission Pipeline¶
Every submission goes through a multi-stage validation pipeline before it reaches the catalog:
- Structure validation --- correct directory layout,
manifest.jsonpresent, required files exist - Static analysis --- imports checked against allowlist, no
subprocess/eval/exec, interfaces properly implemented - AI security review --- LLM-based code review using the submitter's own API key (BYOK, no Jarvis API key needed)
- Container tests --- components instantiated in a Docker sandbox (128MB RAM, 0.5 CPU, read-only filesystem, no network)
- Publish --- added to catalog with
pending_reviewstatus until an admin verifies
Bundles¶
A single Pantry package can include multiple component types:
my-smart-home-package/
manifest.json
commands/
control_widget.py # IJarvisCommand
agents/
widget_monitor.py # IJarvisAgent
device_families/
widget_protocol.py # IJarvisDeviceProtocol
device_managers/
widget_manager.py # IJarvisDeviceManager
routines/
morning_routine.json # Multi-step automation
The manifest declares which components are included. The node's install_command.py handles dependency resolution and secret seeding for the entire bundle.
Extracted packages that need persistent storage use JarvisStorage, a persistence facade provided by the SDK that abstracts over the node's CommandDataRepository. This lets Pantry packages store and retrieve data without depending on node internals.
CLI¶
jarvis pantry search "weather" # Search the catalog
jarvis pantry info smart-weather # View details + reviews
jarvis pantry install smart-weather # Install to your node
jarvis pantry install --local ./my-cmd # Install from local directory (dev)
jarvis pantry remove smart-weather # Uninstall
jarvis pantry list # List installed packages
jarvis pantry update --all # Update all installed packages
API Endpoints¶
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/v1/commands |
GET | None | Browse and search the catalog |
/v1/commands/{name} |
GET | None | Command details, versions, reviews |
/v1/commands/{name}/download |
GET | JWT | Download info (clone URL, manifest) |
/v1/commands |
POST | GitHub OAuth | Submit a new command |
/v1/commands/{name}/reviews |
GET/POST | JWT | List or submit reviews |
/v1/commands/{name}/installed |
POST | JWT | Track installation |
/v1/admin/commands/{name}/verify |
POST | Admin | Admin verification |
Notifications Relay¶
The postman. Receives push requests from your self-hosted notifications service and delivers them to phones via Expo.
Stack: FastAPI (stateless) | Auth: Household JWT | Target: Fly.io / Cloudflare Workers
The relay exists because Apple Push Notification service (APNs) and Firebase Cloud Messaging (FCM) require a publicly reachable server. Rather than exposing your self-hosted infrastructure, the relay acts as a minimal, stateless proxy.
How It Works¶
sequenceDiagram
participant CC as Command Center
participant Notify as Notifications (self-hosted)
participant Relay as Relay (cloud)
participant Expo as Expo Push API
participant Phone as Mobile App
CC->>Notify: Send notification (app-to-app auth)
Notify->>Relay: POST /v1/send (household JWT)
Relay->>Relay: Validate JWT + rate limit
Relay->>Expo: Forward to Expo Push API
Expo->>Phone: APNs / FCM delivery
Rate Limiting¶
The relay protects against abuse with layered rate limits:
| Scope | Limit | Window |
|---|---|---|
| Per household | 100 requests | 1 hour |
| Per device token | 20 requests | 1 hour |
| Burst | 10 requests | 1 second |
Repeated limit violations trigger escalating responses: warning at 3 consecutive 429s, error logging at 6, and a 1-hour suspension at 10.
OAuth Bounce¶
The relay also handles OAuth callback redirects. When a mobile user authenticates with an external provider (e.g., Google), the provider redirects to the relay, which bounces the authorization code to the mobile app via a custom URL scheme:
Provider → GET /oauth/bounce?code=xxx&state=yyy
Relay → 302 redirect to jarvis://oauth/callback?code=xxx&state=yyy
Mobile → Receives code, exchanges for tokens locally
This avoids exposing your self-hosted auth service to the public internet.
API Endpoints¶
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/health |
GET | None | Health check |
/v1/send |
POST | Household JWT | Forward push notification to Expo |
/oauth/bounce |
GET | None | OAuth callback redirect |
Web Chat¶
A browser-based interface to talk to Jarvis --- no Pi Zero required.
Port: 7722 | Stack: Next.js + React + Tailwind CSS | Auth: JWT (via jarvis-auth)
Web Chat provides a chat interface that connects directly to the command center. It is useful for testing commands during development, for users who do not have a Pi Zero node, or as a secondary interface alongside voice.
Architecture¶
Web Chat is a thin client. All intelligence lives in the command center --- the web app just proxies requests:
- No direct LLM access --- messages go through the command center's full pipeline (tool routing, validation, execution)
- SSE streaming --- responses stream in real-time via Server-Sent Events
- Node selector --- choose which node's command set to use (each node may have different commands installed)
API Proxy Routes¶
| Browser Path | Proxied To |
|---|---|
/api/auth/* |
jarvis-auth:7701/auth/* |
/api/cc/* |
jarvis-command-center:7703/api/v0/* |
Command SDK¶
The contract. A pure-Python library that defines every interface a Pantry package can implement.
Package: jarvis-command-sdk | Install: pip install jarvis-command-sdk
The SDK contains the abstract base classes for all plugin types. Community packages import from the SDK rather than from jarvis-node-setup directly, keeping the dependency lightweight and stable.
Exported Interfaces¶
| Interface | Role | Description |
|---|---|---|
IJarvisCommand |
The Specialists | Voice command handlers |
IJarvisAgent |
The Coordinators | Background scheduled tasks |
IJarvisDeviceProtocol |
The Translators | LAN/cloud device adapters |
IJarvisDeviceManager |
The Stewards | Device discovery backends |
Supporting Classes¶
Commands: PreRouteResult, CommandExample, CommandResponse, JarvisParameter, JarvisSecret, JarvisPackage, RequestInformation, ValidationResult
Agents: AgentSchedule, Alert
Devices: DiscoveredDevice, DeviceControlResult, DeviceManagerDevice
Utilities: JarvisStorage (persistence facade for extracted packages), DateKeys (date constant helpers), GeocodingHelper (location resolution for weather, local search, etc.)
Usage¶
from jarvis_command_sdk import IJarvisCommand, CommandResponse, JarvisParameter
class MyCommand(IJarvisCommand):
@property
def command_name(self) -> str:
return "my_command"
# ... implement the interface
The SDK has zero external dependencies. Node-side code in jarvis-node-setup re-exports from core.* for backwards compatibility, so existing commands do not need to change their imports.
Deployment¶
All cloud services can run self-hosted (same Docker containers as everything else) or on cloud infrastructure:
| Service | Self-Hosted | Cloud Target | Notes |
|---|---|---|---|
| Pantry | Docker + PostgreSQL | Any VPS | Needs GitHub OAuth app credentials |
| Relay | Docker | Fly.io / Cloudflare | Stateless, no database |
| Web Chat | Docker / npm run start |
Vercel / any Node.js host | Needs access to CC + Auth |
| SDK | PyPI package | N/A | Library, not a service |
The jarvis CLI manages cloud services the same way as local ones: