Integration
How the Flutter app and Parachute Computer server connect: API contracts, authentication, communication patterns, and deployment modes.
Communication Overview
┌────────────────────────────────────────────────────────────────────────────┐
│ PARACHUTE APP │
│ │
│ ┌─────────────────┐ │
│ │ ChatService │ ───── HTTP POST /api/chat ────────────────────┐ │
│ │ (2,059 lines) │ ◀──── SSE Stream ─────────────────────────────│ │
│ └─────────────────┘ │ │
│ │ │
│ ┌─────────────────┐ │ │
│ │ SyncService │ ───── HTTP POST /api/sync/* ──────────────────│ │
│ │ │ ◀──── JSON Response ──────────────────────────│ │
│ └─────────────────┘ │ │
│ │ │
│ ┌─────────────────┐ │ │
│ │ FileBrowserSvc │ ───── HTTP GET /api/fs/* ─────────────────────│ │
│ │ (remote) │ ◀──── JSON Response ──────────────────────────│ │
│ └─────────────────┘ │ │
│ │ │
└────────────────────────────────────────────────────────────────────────│────┘
│
│
┌──────────────────────────────▼────┐
│ COMPUTER SERVER │
│ http://localhost:3333 │
│ │
│ ┌───────────────────────────┐ │
│ │ FastAPI Router │ │
│ │ │ │
│ │ /api/chat → chat.py │ │
│ │ /api/auth → auth.py │ │
│ │ /api/fs → filesystem │ │
│ │ /api/sync → sync.py │ │
│ │ /api/health → health.py │ │
│ └───────────────────────────┘ │
│ │
└──────────────────────────────────┘
Service to Endpoint Mapping
| App Service | Server Endpoint | Protocol | Purpose |
|---|---|---|---|
ChatService |
POST /api/chat |
SSE | AI chat with streaming |
ChatService |
GET /api/chat |
HTTP | List sessions |
ChatService |
GET /api/chat/{id} |
HTTP | Get session details |
SyncService |
POST /api/sync/* |
HTTP | Journal sync |
RemoteFileBrowserService |
GET /api/fs/* |
HTTP | Remote file browsing |
BaseServerService |
GET /api/health |
HTTP | Server health check |
Authentication Flow
┌─────────────────┐ ┌─────────────────┐
│ App │ │ Computer │
└────────┬────────┘ └────────┬────────┘
│ │
│ 1. First launch (no API key) │
│ │
│ GET /api/health (localhost) │
│ ──────────────────────────────────────────────▶│
│ │ Auth bypassed
│ ◀────────────── {"status": "ok"} ─────────────│ (localhost)
│ │
│ 2. Create API key (Settings) │
│ │
│ POST /api/auth/keys │
│ {"label": "My iPhone"} │
│ ──────────────────────────────────────────────▶│
│ │
│ ◀──── {"key": "para_abc...", "id": "k_..."} ──│
│ │
│ 3. Store key in SharedPreferences │
│ │
│ 4. Future requests (any network) │
│ │
│ POST /api/chat │
│ X-API-Key: para_abc... │
│ ──────────────────────────────────────────────▶│
│ │ Validate key
│ ◀──────────── SSE response ───────────────────│
│ │
Key Storage Locations
| Location | What's Stored | Format |
|---|---|---|
| App (SharedPreferences) | Full API key | para_aBcDeFgHiJkLmNoPqRsT1234 |
| Server (server-config.json) | Key hash + metadata | sha256:abc123... |
Deployment Modes
Client Mode
App connects to external server URL. User configures server address in Settings. Used for remote/cloud deployments.
- Server URL from user input
- API key required (remote)
- Sync enabled
Computer Mode (Lima)
Server runs in isolated Lima VM on macOS. App auto-starts VM on launch. Most secure option.
- Server at localhost:3333
- Auth bypassed (localhost)
- Shared vault (no sync)
Computer Mode (Bare Metal)
Server runs directly on macOS. Best performance, full hardware access. For dedicated Parachute machines.
- Server at localhost:3333
- Auth bypassed (localhost)
- Shared vault (no sync)
Shared Vault Architecture
In Computer mode, app and server share the same vault directory:
┌─────────────────────────────────────────────────────────────────────┐
│ ~/Parachute (Vault) │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Daily/ │ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ App writes │ │ Server reads │ │ │
│ │ │ journal │ ◀─────▶ │ for agents │ │ │
│ │ │ entries │ │ │ │ │
│ │ └─────────────────┘ └─────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Chat/ │ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ App reads │ │ Server writes │ │ │
│ │ │ sessions │ ◀─────▶ │ sessions │ │ │
│ │ │ │ │ │ │ │
│ │ └─────────────────┘ └─────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ .claude/ │ │
│ │ │ │
│ │ Server writes SDK transcripts here │ │
│ │ App doesn't access directly (reads via API) │ │
│ └──────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
Benefits:
✓ No sync needed (same files)
✓ Immediate updates
✓ No data duplication
Considerations:
⚠ File locking important (concurrent access)
⚠ App must use server's vault path
Error Handling
Connection Errors
When the server is unreachable:
- Chat: Shows "Server unavailable" banner, retries on next message
- Daily: Works offline, queues sync for later
- Vault: Shows cached content, remote features disabled
Authentication Errors
When API key is invalid or expired:
- 401 response triggers key re-entry prompt
- Settings opens to API key section
- User can create new key from server
Streaming Errors
When SSE connection drops mid-stream:
- Partial message shown with error indicator
- Session can be resumed (session_id preserved)
- User can resend last message