Implement complete key:value format parsing for change log entries and fix critical tag synchronization issue from server to client. Key Changes: 1. Shared Key:Value Parser (NEW: internal/engine/parser.go) - Created ParseKeyValueFormat() for both edit and sync operations - Supports flexible whitespace: 'key:value' and 'key: value' - Handles comment skipping for edit files - Consolidates parsing logic (DRY principle) 2. Database Triggers - Tags Support (internal/engine/database.go) - Added tags to track_task_create trigger - Added tags to track_task_update trigger - Tags sorted alphabetically via SQL ORDER BY - Format: 'tags: alpha,bravo,charlie' 3. Task Creation - Tag Update Fix (internal/engine/task.go) - CreateTaskWithModifier() now triggers update after adding tags - Ensures tags appear in change log (UPDATE entry) - Fixes missing tags in initial CREATE entries 4. Edit Command - Use Shared Parser (cmd/edit.go) - Replaced custom parseEditedFile() with shared ParseKeyValueFormat() - Added tag sorting in parseTags() - Removed ~30 lines, improved maintainability 5. Sync Client - Complete Implementation (internal/sync/client.go) - NEW: applyChangeDataToTask() - parses all fields from change log - NEW: Helper functions for status, priority, tag parsing - FIXED: parseChanges() - sort by timestamp+ID before grouping - Added parent/child task ordering (prevents FK violations) - Enhanced tag sync in merge loop with task reload - Specific validation error messages per field Critical Bug Fix: - When CREATE and UPDATE have same timestamp, old code kept CREATE (no tags) - New code sorts by ID as tiebreaker, ensuring UPDATE (with tags) is used - Verified: Server->client tag sync now works correctly Validation: - Description must not be empty (both edit and sync) - Recurrence validated (not negative, max 100 years) - All timestamps parsed correctly (Unix epoch) - Tags sorted alphabetically in all contexts Testing: - Fresh pull from server: ✅ All tags present - API-created tasks: ✅ Tags sync correctly - Local->server->client round-trip: ✅ No data loss - Same-second CREATE+UPDATE: ✅ Correct entry processed - Parent/child tasks: ✅ Correct ordering Files Changed: - NEW: internal/engine/parser.go (+44 lines) - Modified: internal/engine/database.go (+10 lines) - Modified: internal/engine/task.go (+8 lines) - Modified: cmd/edit.go (-25 lines net) - Modified: internal/sync/client.go (+280 lines) - Modified: srv/README.md (+1 line) Total: +318 lines added, -25 removed, net +293 lines This completes Phase 6: Full bidirectional sync with complete tag support.
Opal task manager
This is the counterpart to jade, where we track tasks.
Syntax
opal [<filter>] [<command>] [<modifier>]
Filters the Task to run a command on. Adressing a set of subtasks.
opal +home -garden status:pending list - lists all tasks with the +home tag and status pending, but excludes +garden tags. This is a compound filter with implicit AND.
add - Creates a new task
done - Completes a task
list - Lists task
count - Counts number of tasks
Modifies atributes of tasks.
Task
A task has multiple atributes:
status - pending, completed, deleted, recurring
description - One line summary
start - the most recent time at which this task was started (a task with no start key is not active)
end - if present, the time at which this task was completed or deleted
due - Use a due date to specify the exact date by which a task must be completed.created - Time task created
schedueled - represents the earliest opportunity to work on a task. If a task has a scheduled date, then once that date passes, the task is considered ready. Tasks with no scheduled is considered always ready.
wait - a wait date for a task, which has the effect of hiding the task from you until that date.
until - the point at which to mark task as deleted. an expiration date.
Recurrence
A task can be recurring. Then we have a template task and instances of that task.
opal add Change sheets due:sun recur:1w - A task to be done every sunday.
A recurring task is given a status of recurring which hides it from view. The recurring task you create is called the template task, from which recurring tasks instances are created. So the template remains hidden, and the recurring instances that spawn from it are the tasks that you will see and complete.
Storage
SQLite database stored in ~/.config/jade/opal.db
Server & Sync
Opal-task includes a REST API server for syncing tasks across multiple devices.
Quick Start
Server Setup:
# Build
go build -o opal main.go
# Generate API key
./opal server keygen --name "My Device" --db /var/lib/opal/opal.db
# Start server
./opal server start --addr :8080 --db /var/lib/opal/opal.db
Client Setup:
# Configure sync
opal sync init --url https://opal.yourdomain.com --key oak_abc123...
# Sync tasks
opal sync now
# Initial merge (for existing local database)
opal sync merge
Sync Commands
opal sync init- Configure sync with serveropal sync status- Show sync configuration and statusopal sync now- Bidirectional syncopal sync up- Push local changes to serveropal sync down- Pull server changes from serveropal sync merge- Initial database merge (for first-time sync)opal sync log- View conflict resolution log
Features
- Offline support - Queue changes when server is unreachable
- Conflict resolution - Automatic conflict handling (last-write-wins by default)
- Change tracking - Full change log with configurable retention
- API key authentication - Secure bcrypt-hashed keys
- Household sharing - Single shared database for all family members
See srv/README.md for detailed server deployment instructions.