Core Services
The app's core services layer provides platform-adaptive abstractions for file systems, transcription, synchronization, and server management. These services enable the app to work seamlessly across macOS, iOS, Android, and Linux.
Service Overview
| Service | Purpose | Lines |
|---|---|---|
FileSystemService |
Modular vault management with platform-specific security | ~1,127 |
SyncService |
Multi-phase sync with conflict resolution | ~1,396 |
StreamingVoiceService |
Real-time transcription with VAD-based chunking | ~1,178 |
TranscriptionServiceAdapter |
Platform-adaptive transcription engine selection | ~313 |
LimaVMService |
Lima VM lifecycle for Parachute Computer | ~809 |
BundledServerService |
Embedded server process management | ~479 |
SmartChunker |
VAD-based audio segmentation | ~240 |
SimpleVAD |
RMS energy-based voice activity detection | ~176 |
FileSystemService
Unified file system service managing modular vault structures (Daily and Chat modules) with platform-specific security handling.
Module Architecture
~/Parachute/ (Vault Root - user configurable)
├── Daily/ (Module folder)
│ ├── journals/ (Required subfolder)
│ ├── assets/ (Required subfolder)
│ └── reflections/ (Required subfolder)
│
└── Chat/ (Module folder)
├── sessions/
├── assets/
├── artifacts/
└── contexts/
Key Methods
| Method | Purpose |
|---|---|
initialize() |
Async init with lazy loading, legacy migration, secure bookmarks |
getRootPath() |
Get module root path (e.g., ~/Parachute/Daily) |
getVaultPath() |
Get vault root (e.g., ~/Parachute) |
setVaultPath(path, migrateFiles) |
Configure vault with optional file migration |
getFolderPath(type) |
Get path for specific folder type |
getNewAssetPath() |
Generate date-organized asset path (YYYY-MM-DD) |
cleanupTempAudioFiles() |
Clean temp files with retention policies |
Platform-Specific Behavior
| Platform | Default Vault Path | Special Handling |
|---|---|---|
| macOS | Home directory ($HOME) |
SecureBookmarks for sandbox compliance |
| iOS | App documents + Parachute/ | No external storage access |
| Android | External storage + Parachute/ | MANAGE_EXTERNAL_STORAGE permission |
| Linux | Home directory | Standard filesystem access |
Temp File Retention
- Recordings: 7 days
- Playback: 24 hours
- Segments: 1 hour
SyncService
Multi-phase sync orchestration between local Daily vault and server with conflict resolution and tombstone tracking.
Sync Protocol
1. Manifest Comparison └── SHA-256 hashing for content change detection 2. Local vs Server Decision └── Push/pull/merge based on timestamps and content hashes 3. Conflict Detection └── Files with close timestamps (<60s) + different content 4. Tombstone Tracking └── .tombstones/ directory tracks deleted files 5. Version Backups └── .versions/ keeps last 3 versions before overwriting
Conflict Resolution Strategy
| File Type | Resolution Method |
|---|---|
| Journal files (.md in journals/) | Entry-level merge via JournalMergeService |
| Other files | Create conflict file (.sync-conflict-{timestamp}-{deviceId}) |
Batching Strategy
- Text files: 50 files per batch (fast, checksummed)
- Binary files: 5 files per batch (slow, base64-encoded, longer timeouts)
Key Methods
| Method | Purpose |
|---|---|
sync() |
Full vault sync with batched operations |
syncDate(date) |
Efficient date-scoped sync for single day |
getServerManifest() |
Query server state |
pushFiles() |
Upload local changes to server |
pullFiles() |
Download server changes to local |
deleteFileWithTombstone() |
Delete with tombstone for sync propagation |
StreamingVoiceService
Real-time transcription feedback during Chat voice input with VAD-based audio chunking and streaming WAV file generation.
LocalAgreement-2 Algorithm
Rolling Buffer: 30-second max audio buffer
│
▼
VAD Chunker: Detects 1s silence threshold
│
▼
Transcription Queue: Only chunks with ≥1s speech
│
▼
Text Stability Tracking:
├── Confirmed (2+ iterations)
├── Tentative (1 iteration)
└── Interim (changing)
Streaming State Flow
startRecording()- Initialize noise filter, VAD, temp WAV, wakelock_processAudioChunk()- Convert bytes to int16, apply filter, stream to disk_handleChunk()(VAD callback) - Queue chunk for async transcription_transcribeSegment()- Transcribe chunk, add to confirmed segmentsstopRecording()- Flush VAD, final transcription, fallback if emptygetStreamingTranscript()- Join segments with fuzzy overlap removal
Model Status Tracking
notInitialized → initializing (lazy init) → ready
→ error
TranscriptionServiceAdapter
Platform-adaptive abstraction layer selecting optimal transcription engine per platform.
Platform Strategy
| Platform | Primary Engine | Fallback |
|---|---|---|
| iOS / macOS | FluidAudio (Parakeet v3 CoreML) | Sherpa-ONNX |
| Android | Sherpa-ONNX (Parakeet v3 ONNX Runtime) | None |
Key Features
- Lazy Initialization: Models not loaded until first transcription
- Progress Tracking: Broadcasts via
transcriptionProgressStream - Fallback Logic: FluidAudio failure falls through to Sherpa-ONNX
- Singleton Management: Sherpa-ONNX isolate reused across instances
LimaVMService
Complete lifecycle management for Parachute Computer - an isolated Lima VM running the Computer server.
Lifecycle States
notInstalled ──► notCreated ──► stopped ◄──► starting
│ │
▼ ▼
error running
▲ │
└── stopping ◄┘
Key Methods
| Method | Purpose |
|---|---|
checkStatus() |
Probe VM state from limactl |
createVM() |
First-time VM creation from YAML config |
start() / stop() / delete() |
VM lifecycle control |
startServer() |
Boot Computer server inside VM |
isServerHealthy() |
Health check via /api/health |
runClaudeLogin() |
Interactive auth in Terminal.app |
installBaseServer() |
Install/update server in VM |
Auto-Start (launchd)
- Label:
io.openparachute.vm - Path:
~/Library/LaunchAgents/io.openparachute.vm.plist - RunAtLoad: true (starts on login)
BundledServerService
Lifecycle management for bundled server binary in desktop distributions.
Status States
notBundled ──► stopped ◄──► starting
│ │
▼ ▼
error running
Cross-Platform Bundle Paths
| Platform | Bundle Location |
|---|---|
| macOS | MyApp.app/Contents/Resources/parachute-server/ |
| Linux | parachute-linux-x64/lib/parachute-server/ |
| Windows | parachute-windows-x64/data/parachute-server/ |
Environment Variables
VAULT_PATH- User's vault directoryPORT- 3333 (configurable)PATH- Inherited for external tool accessHOME- Explicit to prevent sandboxing issues
Health Monitoring
- Startup: Poll /api/health every 500ms for 30s
- Running: Check every 10s
- Max Restart Attempts: 3 (then error state)
VAD System
Voice Activity Detection for intelligent audio segmentation, ported from RichardTate.
SmartChunker
VAD-based audio segmentation preventing silent/noise-only chunks from reaching transcription.
Safety Thresholds
- Min speech duration: 1s (prevents hallucinations)
- Min chunk duration: 500ms (efficiency)
- Max chunk duration: 30s (safety limit)
- Silence threshold: 1s (configurable)
SimpleVAD
RMS energy-based voice activity detection for distinguishing speech from silence.
RMS Calculation
RMS = sqrt(sum(sample^2) / num_samples) Threshold Tuning: - 100.0: Default (ideal lab conditions) - 400-800+: Real-world with background noise - Lower = more aggressive (false positives) - Higher = conservative (may miss quiet speech)
State Tracking
- Silence/speech durations (cumulative)
- Consecutive frame counts
- Current speaking state
- Last frame classification
Error Handling Patterns
All services follow consistent patterns:
- Try-catch blocks with descriptive
debugPrintlogging - Platform-specific fallbacks (e.g., home directory detection)
- Timeouts on network operations (30-120s)
- Graceful degradation rather than exceptions
Logging Convention
debugPrint('[ClassName] message'); // Standard
debugPrint('[ClassName] Success'); // Success
debugPrint('[ClassName] Warning'); // Warning
debugPrint('[ClassName] Error reason: $e'); // Error
Resource Cleanup
- Timers always cancelled in
dispose() - Stream subscriptions unsubscribed
- File handles closed
- WakeLock explicitly disabled