Worklog uses a hybrid architecture with SQLite as the runtime source of truth and Git as the persistent storage, with JSONL serving as an ephemeral transport format for synchronization.
- All reads and writes happen against SQLite
- SQLite provides ACID guarantees and fast queries
- Full-text search is implemented via SQLite FTS5
- No runtime dependency on JSONL files
- Git repositories store the canonical data
- Enables collaboration across teams
- Provides version history and audit trail
- Branch-based workflows for data isolation
- JSONL files exist only during sync operations
- Created on-demand for push operations (export → push → delete)
- Fetched temporarily for pull operations (fetch → import → delete)
- Never persists locally beyond the sync window (typically seconds)
- Eliminates synchronous export operations after every write
- No more UI freezing during database operations
- Performance independent of data size
- No persistent JSONL files cluttering the workspace
grepand search tools don't match JSONL data- Agents and developers work with SQLite exclusively
- ACID transactions via SQLite
- Atomic Git operations for sync
- Conflict resolution during merge
┌─────────────┐ ┌─────────────┐
│ CLI/TUI │────▶│ SQLite │
└─────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ FTS Index │
└─────────────┘
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ SQLite │────▶│ JSONL │────▶│ Git Push │────▶│ Remote │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ DELETE │
└─────────────┘
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Remote │────▶│ Git Fetch │────▶│ JSONL │────▶│ SQLite │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ DELETE │
└─────────────┘
Previous versions of Worklog used persistent JSONL files with an autoExport feature that wrote to JSONL after every database operation. This caused:
- TUI freezing due to synchronous exports
- Grep pollution from large JSONL files
- File staleness issues
Users upgrading from older versions can migrate using:
# Import JSONL data into SQLite
wl migrate jsonl
# Verify migration succeeded
wl status
# Delete the old JSONL file
wl migrate jsonl --delete- The
wl importcommand still works for manual JSONL import - The system detects existing JSONL on startup and can import if SQLite is empty
- Old
autoExportconfig option is deprecated with a warning
- Check if SQLite has data
- If yes: Skip JSONL refresh entirely
- If no: Check for local JSONL (legacy migration)
- If JSONL exists: Import to SQLite, then delete JSONL
- Export SQLite data to temporary JSONL
- Acquire file lock
- Push JSONL to Git
- Release file lock
- Delete local JSONL (if push succeeded)
- Offline: Graceful error message, local data preserved
- Merge conflicts: Conflict resolution during sync, manual resolution guidance
- Push failure: JSONL retained for retry
- Import errors: SQLite transaction rollback
.worklog/
├── worklog.db # SQLite database (runtime source of truth)
├── worklog.lock # File lock for concurrent access
├── config.yaml # User configuration
├── config.defaults.yaml # Default configuration
└── initialized # Initialization semaphore
# Note: worklog-data.jsonl is NOT here - it's ephemeral
- Speed: Milliseconds (SQLite index lookups)
- Scalability: O(log n) with proper indexing
- Consistency: ACID transactions
- Speed: Milliseconds (SQLite writes)
- No export overhead: Exports only happen during explicit sync
- Batching: Multiple operations in single transaction
- Export: ~100ms per 1000 items
- Git push: Depends on network (typically 1-5s)
- Import: ~100ms per 1000 items
- Incremental sync: Only sync changed items
- Background sync: Async sync without blocking UI
- Compression: Compress JSONL for large datasets
- Delta encoding: Send only diffs for efficiency
- Phase 1 (Complete): Remove autoExport infrastructure
- Phase 2 (Complete): Implement ephemeral JSONL pattern
- Phase 3 (Complete): Clean architecture and migration path