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

  1. startRecording() - Initialize noise filter, VAD, temp WAV, wakelock
  2. _processAudioChunk() - Convert bytes to int16, apply filter, stream to disk
  3. _handleChunk() (VAD callback) - Queue chunk for async transcription
  4. _transcribeSegment() - Transcribe chunk, add to confirmed segments
  5. stopRecording() - Flush VAD, final transcription, fallback if empty
  6. getStreamingTranscript() - 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 directory
  • PORT - 3333 (configurable)
  • PATH - Inherited for external tool access
  • HOME - 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 debugPrint logging
  • 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