Daily Feature
Voice-first journaling with real-time streaming transcription, Omi wearable integration, and AI-powered reflections. The most complex audio processing in the app.
Module Structure
daily/
├── journal/ (31 files, ~8,300 lines) - Core journaling
│ ├── models/ - JournalEntry, JournalDay, AgentOutput
│ ├── services/ - JournalService, ReflectionService
│ ├── providers/ - Riverpod state management
│ ├── screens/ - JournalScreen (2,156 lines)
│ └── widgets/ - EntryCard, InputBar, AudioPlayer
│
├── recorder/ (32 files, ~12,500 lines) - Audio & transcription
│ ├── models/ - OmiDevice
│ ├── services/ - Transcription, Omi, background recording
│ │ ├── transcription/ - LocalAgreement-2 streaming
│ │ └── omi/ - Bluetooth device integration
│ ├── providers/ - Recording state
│ └── widgets/ - Audio controls, debug overlay
│
├── capture/ (4 files, ~750 lines) - Photo & handwriting
│ ├── services/ - PhotoCaptureService
│ └── screens/ - HandwritingScreen
│
└── search/ (3 files, ~750 lines) - Journal search
├── services/ - Text search
└── screens/ - Search UI
Streaming Transcription Pipeline
Three-stage pipeline with VAD-based auto-pause and LocalAgreement-2 text stability:
┌───────────────────────────────────────────────────────────────────────┐ │ STREAMING TRANSCRIPTION PIPELINE │ │ │ │ Stage 1: Audio Capture │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ Microphone → SimpleNoiseFilter → SmartChunker (VAD) → Buffer │ │ │ │ │ │ │ │ • 16kHz, 16-bit PCM, mono │ │ │ │ • Noise filter pre-processing │ │ │ │ • VAD detects speech vs silence │ │ │ │ • Rolling buffer (30 seconds max) │ │ │ └─────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ Stage 2: Transcription │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ Re-transcribe every 3s during speech │ │ │ │ │ │ │ │ iOS/macOS: FluidAudio (Parakeet v3 CoreML) - faster │ │ │ │ Android: Sherpa-ONNX (Parakeet v3 ONNX) - v1.12.20 pinned │ │ │ └─────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ Stage 3: LocalAgreement-2 │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ Compare consecutive transcriptions │ │ │ │ │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ Confirmed │ │ Tentative │ │ Interim │ │ │ │ │ │ (2+ matches) │ │ (1 match) │ │ (changing) │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ │ │ │ │ Display: [confirmed] [tentative] [interim] │ │ │ └─────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ Finalization (on VAD silence ≥1s or stop) │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ Flush buffer with 2s silence → Final transcription │ │ │ │ Create JournalEntry with audio path + transcribed text │ │ │ └─────────────────────────────────────────────────────────────────┘ │ └───────────────────────────────────────────────────────────────────────┘
Key Configuration
| Setting | Value | Purpose |
|---|---|---|
| Rolling Buffer Max | 30 seconds | 480k samples at 16kHz |
| Re-transcribe Interval | 3 seconds | During speech detection |
| VAD Silence Threshold | 1 second | Detect end of speech |
| Min Chunk Duration | 500ms | Efficiency |
| Energy Threshold | 100-800 | Speech vs silence (adjustable) |
Journal Entry Types
Voice
Audio recording with transcription. Stored as WAV file with text content.
- Audio path in YAML frontmatter
- Duration tracking
- Transcription status
Text
Typed journal entries. Plain markdown content.
- Direct text input
- Markdown formatting
- Created timestamp
Photo
Image capture with optional caption.
- Camera or gallery source
- Optional cropping
- Date-organized storage
Handwriting
Canvas-based handwriting/drawing.
- Lined paper background
- PNG export
- Touch/stylus input
Para-ID System
Portable identifiers for cross-device synchronization:
# Journal file format: Daily/journals/{YYYY-MM-DD}.md
---
entries:
daily:abc123def456:
type: voice
audio: assets/2025-01-28/audio_abc123.wav
duration: 45
created: "10:30"
status: complete
---
# para:daily:abc123def456 Morning reflection
This is the transcribed text from the voice recording.
It was captured at 10:30 AM and processed through
the streaming transcription pipeline.
---
# para:daily:xyz789uvw012 Follow-up thought
Another entry with its own para ID and metadata.
ID Format
| Component | Value | Description |
|---|---|---|
| Prefix | para: |
Namespace identifier |
| Module | daily: |
Source module (daily, chat) |
| ID | 12 chars | Alphanumeric (a-z, 0-9) |
| Legacy ID | 6 chars | Backward compatible |
Omi Wearable Integration
Bluetooth Low Energy (BLE) integration with Omi pendant device:
┌─────────────────────────────────────────────────────────────────────┐ │ OMI DEVICE INTEGRATION │ │ │ │ ┌───────────────┐ ┌───────────────────────────────────┐ │ │ │ Omi Pendant │ ◀─BLE─▶│ OmiBluetoothService │ │ │ │ │ │ │ │ │ │ • Button │ │ • Scan for devices │ │ │ │ • Microphone │ │ • Auto-reconnect │ │ │ │ • SD Card │ │ • Battery level stream │ │ │ │ • Battery │ │ • Connection state │ │ │ └───────────────┘ └───────────────┬───────────────────┘ │ │ │ │ │ ▼ │ │ ┌───────────────────────────────────┐ │ │ │ OmiCaptureService │ │ │ │ │ │ │ │ Mode Auto-Detection: │ │ │ │ ┌──────────────────────────────┐ │ │ │ │ │ Store-and-Forward (default) │ │ │ │ │ │ Records to SD card │ │ │ │ │ │ Downloads when complete │ │ │ │ │ └──────────────────────────────┘ │ │ │ │ ┌──────────────────────────────┐ │ │ │ │ │ Real-time Streaming (fallback)│ │ │ │ │ │ Audio over BLE during record │ │ │ │ │ └──────────────────────────────┘ │ │ │ └───────────────────────────────────┘ │ │ │ │ Supported Codecs: PCM8, PCM16, mu-law, Opus │ │ Service UUID: 19b10000-e8f2-537e-4f6c-d104768a1214 │ └─────────────────────────────────────────────────────────────────────┘
Button Events
- Single Tap: Start/stop recording
- Double Tap: Cancel recording
- Triple Tap: Custom action
Core Services
JournalService (1,261 lines)
Core CRUD operations for journal entries with surgical file appending.
| Method | Purpose |
|---|---|
loadDay(date) |
Load all entries for a date |
addEntry(entry) |
Append new entry (preserves external edits) |
updateEntry(paraId, content) |
Surgical update of specific entry |
deleteEntry(paraId) |
Remove entry and metadata |
listRecordingIds() |
Get all para IDs with recordings |
LiveTranscriptionService (547 lines)
Main transcription orchestrator with VAD-based auto-pause.
// Public API
bool get isRecording
bool get isProcessing
List<TranscriptionSegment> get segments
String get interimText
StreamingTranscriptionState get currentStreamingState
Stream<bool> get vadActivityStream
Stream<AudioDebugMetrics> get debugMetricsStream
Stream<StreamingTranscriptionState> get streamingStateStream
Future<bool> initialize()
Future<bool> startRecording()
Future<String?> stopRecording() // Returns audio path
Future<void> cancelRecording()
AgentOutputService (171 lines)
Loads agent-generated outputs (reflections, content ideas).
- Parses markdown with YAML frontmatter
- Extracts agent name and timestamp
- Lists outputs by date or agent
Crash Recovery
Segments are persisted before transcription for recovery:
// pending_segments.json
{
"segments": [
{
"index": 0,
"audioFilePath": "/tmp/recording_abc123.wav",
"startOffsetBytes": 44,
"durationSamples": 160000,
"status": "interrupted",
"transcribedText": null,
"createdAt": "2025-01-28T10:30:00Z"
}
]
}
Recovery Strategy
- Segments marked
pending,processing, orinterruptedare recovered - Audio files retained for 7 days
- On restart, re-queues interrupted segments
Daily Agent Integration
Server-side agents process journal entries to generate reflections:
Journal Entry
│
├── Written to Daily/journals/{date}.md
│
▼
Server Scheduler (APScheduler)
│
├── Discovers agents from Daily/.agents/*.md
│
├── Morning Reflection Agent (configurable time)
│ └── Reads journal + chat logs
│ └── Generates morning reflection
│ └── Writes to Daily/reflections/{date}.md
│
└── Content Scout Agent (configurable time)
└── Extracts valuable insights
└── Writes to Daily/content-scout/{date}.md
See Modules & Agents documentation for server-side details.
File Storage
~/Parachute/Daily/
├── journals/
│ ├── 2025-01-28.md # Journal entries with YAML frontmatter
│ └── 2025-01-27.md
├── assets/
│ └── 2025-01-28/ # Date-organized media
│ ├── audio_abc123.wav
│ ├── photo_xyz789.jpg
│ └── handwriting_uvw012.png
├── reflections/
│ ├── 2025-01-28.md # AI-generated morning reflection
│ └── 2025-01-27.md
├── chat-log/
│ └── 2025-01-28.md # Chat session summaries
├── content-scout/
│ └── 2025-01-28.md # Content ideas extracted
└── .agents/
├── curator.md # Daily curator agent config
└── content-scout.md # Content scout agent config
Key Widgets
| Widget | Lines | Purpose |
|---|---|---|
journal_screen.dart |
2,156 | Main journal UI - timeline of entries |
journal_input_bar.dart |
1,379 | Text input + voice recording controls |
journal_entry_row.dart |
992 | Row item in list view |
journal_entry_card.dart |
606 | Card displaying single entry |
entry_edit_modal.dart |
572 | Modal for editing entry |
agent_output_header.dart |
511 | Header showing agent output |
mini_audio_player.dart |
260 | Audio playback widget |