···1# ROADMAP
23-## Task Management Commands (TaskWarrior-inspired)
45-### Implemented Commands
67-- [x] `todo add [description]` - Create new task with metadata (priority, project, context, due, tags)
8-- [x] `todo list` - Display tasks with filtering (status, priority, project, context) and interactive/static modes
9-- [x] `todo view [task-id]` - View task details with format options (detailed, brief, json)
10-- [x] `todo update [task-id]` - Edit task properties via flags
11-- [x] `todo edit [task-id]` - Interactive task editor with status picker and priority toggle
12-- [x] `todo done [task-id]` - Mark task as completed
13-- [x] `todo delete [task-id]` - Remove task permanently
1415----
1617-- [x] `todo projects` - List all project names (interactive/static modes)
18-- [x] `todo tags` - List all tag names (interactive/static modes)
19-- [x] `todo contexts` - List all contexts/locations (interactive/static modes)
2021----
0000000002223-- [x] `todo start [task-id]` - Start time tracking for a task
24-- [x] `todo stop [task-id]` - Stop time tracking for a task
25-- [x] `todo timesheet` - Show time tracking summaries (with date range and task filters)
2627-### Commands To Be Implemented
000002829-- [ ] Due dates & scheduling - Including recurring tasks
30-- [ ] Task dependencies - Task A blocks task B relationships
31-- [ ] `annotate` - Add notes/comments to existing tasks
32-- [ ] Recurring tasks
33-- [ ] Smart due date suggestions
34-- [ ] Completion notifications
35-- [ ] `calendar` - Display tasks in calendar view
3637-## Media Queue Management Commands
0000003839-### Implemented Commands
4041-Book Management
4243-- [x] `media book add [search query...]` - Search and add book to reading list (with interactive mode)
44-- [x] `media book list` - Show reading queue with progress and status filtering
45-- [x] `media book reading <id>` - Mark book as currently reading
46-- [x] `media book finished <id>` - Mark book as completed
47-- [x] `media book remove <id>` - Remove from reading list
48-- [x] `media book progress <id> <percentage>` - Update reading progress (0-100%)
49-- [x] `media book update <id> <status>` - Update book status (queued|reading|finished|removed)
5051-Movie Management
5253-- [x] `media movie add [title]` - Add movie to watch queue (with interactive mode)
54-- [x] `media movie list` - Show movie queue with status filtering
55-- [x] `media movie watched <id>` - Mark movie as watched
56-- [x] `media movie remove <id>` - Remove from queue
5758-TV Show Management
5960-- [x] `media tv add [title]` - Add TV show/season to queue (with interactive mode)
61-- [x] `media tv list` - Show TV queue with status filtering
62-- [x] `media tv watching <id>` - Mark TV show as currently watching
63-- [x] `media tv watched <id>` - Mark episodes/seasons as watched
64-- [x] `media tv remove <id>` - Remove from TV queue
6566-### Commands To Be Implemented
6768----
00006970-- [ ] Articles, papers, blogs support (implement article parser)
71-- [ ] Source tracking (recommendation sources)
72-- [ ] Ratings and personal notes
73-- [ ] Genre/topic tagging
74-- [ ] Episode/season progress tracking for TV
75-- [ ] Platform tracking (Netflix, Amazon, etc.)
76-- [ ] Watch status: queued, watching, completed, dropped
7778-## Management Commands
79-80-### Implemented Commands
81-82-Application Management
83-84-- [x] `status` - Show application status and configuration
85-- [x] `setup` - Initialize and manage application setup
86-- [x] `setup seed` - Populate database with test data (with --force flag)
87-- [x] `reset` - Reset the application (removes all data)
88-- [x] `config [key] [value]` - Manage configuration settings (stubbed)
89-90-### Commands To Be Implemented
91-92-Organization Features
93-94-- [ ] Custom queries and saved searches
95-- [ ] Context-aware suggestions
96-- [ ] Overdue/urgent highlighting
97-- [ ] Recently added/modified items
98-- [ ] Seasonal/mood-based filtering
99-- [ ] Full-text search across titles, notes, tags
100-101-Analytics
102-103-- [ ] Reading/watching velocity tracking
104-- [ ] Completion rates by content type
105-- [ ] Time investment analysis
106-- [ ] Personal productivity metrics
107-- [ ] Content source analysis
108-109-Integrations
110-111-- [ ] `import` - Import from various formats (CSV, JSON, todo.txt)
112-- [ ] `export` - Export to various formats
113-- [ ] Goodreads import for books
114-- [ ] IMDB/Letterboxd import for movies
115-- [ ] Todo.txt format compatibility
116-- [ ] TaskWarrior import/export
117-- [ ] URL parsing for automatic metadata
118-119-`todo.txt` Compatibility
120-121-- [ ] `archive` - Move completed tasks to done.txt
122-- [ ] `[con]texts` - List all contexts (@context)
123-- [ ] `[proj]ects` - List all projects (+project)
124-- [ ] `[pri]ority` - Set task priority (A-Z)
125-- [ ] `[depri]oritize` - Remove priority from task
126-- [ ] `[re]place` - Replace task text entirely
127-- [ ] `[pre]pend/[app]end` - Add text to beginning/end of task
128-129-Automation
130-131-- [ ] Auto-categorization of new items
132-- [ ] Smart due date suggestions
133-- [ ] Recurring content (weekly podcast check-ins)
134-- [ ] Completion notifications
135136-Storage
137138-- [ ] `sync` - Synchronize with remote storage
139-- [ ] `sync setup` - Setup remote storage
140-- [ ] Local SQLite database with optional cloud sync
141-- [ ] Multiple profile support
142-- [ ] `backup` - Create local backup
143-- [ ] Backup/restore functionality
144145-Configuration
146147-- [x] Enhanced `config` command implementation (basic stubbed version)
148-- [ ] `undo` - Reverse last operation
149-- [ ] Themes and personalization
150-- [ ] Customizable output formats
000151152-## Notes Management Commands
153154-### Implemented Commands
0000155156-Core Notes Operations
157158-- [x] `note create [title] [content...]` - Create new markdown note with optional interactive editor
159-- [x] `note list` - Interactive TUI browser for navigating and viewing notes (with archive and tag filtering)
160-- [x] `note read <note-id>` - Display formatted note content with syntax highlighting
161-- [x] `note edit <note-id>` - Edit note in configured editor
162-- [x] `note remove <note-id>` - Permanently remove note file and metadata
163164-Additional Options
165166-- [x] `--interactive|-i` flag for create command (opens editor)
167-- [x] `--file|-f` flag for create command (create from markdown file)
168-- [x] `--archived|-a` flag for list command
169-- [x] `--tags` filtering for list command
0000000000000000170171-### Commands To Be Implemented
172173-- [ ] `note search [query]` - Search notes by content, title, or tags
174-- [ ] `note tag <note-id> [tags...]` - Add/remove tags from notes
175-- [ ] `note recent` - Show recently created/modified notes
176-- [ ] `note templates` - Create notes from predefined templates
177-- [ ] `note archive <note-id>` - Archive old notes
178-- [ ] `note export` - Export notes to various formats
179-- [ ] Full-text search integration
180-- [ ] Linking between notes and tasks/content
00181182-## User Experience
183184-- [x] Interactive TUI modes for task lists, projects, tags, contexts, and notes
185-- [x] Static output modes as alternatives to interactive TUI
186-- [x] Color-coded priority and status indicators
187-- [x] Comprehensive help system via cobra CLI framework
00000000188189----
190191-- [ ] Quick-add commands for rapid entry
192-- [ ] Enhanced progress tracking UI
193-- [ ] Calendar view for tasks
194195-### Technical Infrastructure
196197-- [ ] CI/CD pipeline -> pre-build binaries
198-- [ ] Complete README/documentation
199-- [ ] Installation instructions
200-- [ ] Usage examples
00201202-## Tech Debt
203204-### Signatures
000205206-We've got inconsistent argument parsing and sanitization leading to calls to strconv.Atoi in tests & handler funcs.
207-This is only done correctly in the note command -> handler sequence
208209-- [ ] TaskCommand
210-- [ ] MovieCommand
211-- [ ] TVCommand
212-- [ ] BookCommand
213214-### Movie Commands - Missing Tests
215216-- [x] movie watched [id] - marks movie as watched
00217218-### TV Commands - Missing Tests
219220-- [x] tv watching [id] - marks TV show as watching
221-- [x] tv watched [id] - marks TV show as watched
00222223-### Book Commands - Missing Tests
224225-- [x] book add [search query...] - search and add book
226-- [x] book reading `<id>` - marks book as reading
227-- [x] book finished `<id>` - marks book as finished
228-- [x] book progress `<id>` `<percentage>` - updates reading progress
0229230-## Ideas
231232-### Task Management Enhancements
00233234-- Sub-tasks and hierarchical tasks - Break complex tasks into child tasks for better organization
235-- Linking - Establish relationships between related tasks without strict dependencies
236-- Batching - Group related tasks for bulk operations (completion, priority changes, etc.)
237-- Retrospectives - Analysis of completed tasks to improve future estimates and planning
238-- Automation rules - Create rules that automatically modify tasks based on conditions
239-- Habit formation - Track recurring micro-tasks that build into larger goals
240-- Context switching - Automatically adjust system settings, apps, or environment based on current task
241-- Forecasting - Predict future tasks based on patterns, calendar events, or seasonal trends
242-- "Energy" matching - Recommend tasks based on current energy levels or time of day
243-- Priority rebalancing - Automatically suggest priority adjustments based on deadlines and importance
244-- Dependency visualization: Visual flow charts showing how tasks connect and block each other
245246-### Media Management Enhancements
0000247248-- Podcast management: Add podcast tracking with episode progress and subscription management
249-- YouTube/video content management: Track video content queues and viewing progress
250-- Multi-format media support: Include audiobooks, comics, and other content formats
251-- Media consumption goals: Set reading/watching goals (e.g., "2 books per month")
252-- Media cross-referencing: Connect related content across different media types
253- - Series
254-- Media note integration: Link notes to specific books, movies, or shows for reviews
255- - Review system - Write and store personal reviews of consumed content
256-- Media budget tracking: Track spending on media content (subscriptions, purchases)
257-- Media consumption patterns: Analyze personal consumption patterns and preferences over time
258-- Media seasonal tracking: Track seasonal media preferences and suggest accordingly
259-- Media completion streaks: Gamification elements for consistent media consumption
260-- Media progress synchronization: Sync progress across different devices or platforms
261262-### Notes Management Enhancements
00263264-- Linking and graph view: Create bidirectional links between related notes
265-- Templates system: Predefined templates for different note types (meeting notes, book summaries)
266-- Versioning and history: Track changes to notes over time with ability to revert
267-- Export with formatting: Rich export options with preserved formatting and links
268-- Import capabilities: Import notes from other systems (Notion, Evernote, etc.)
269-- Content extraction: Extract key points or action items from longer notes
270-- Encryption: End-to-end encryption for sensitive notes
271-- Content validation: Check for broken links, missing references, or inconsistent information
272273-### System Integration & Automation
274275-- Calendar integration: Sync tasks with calendar systems (Google Calendar, Outlook)
276-- Email integration: Create tasks or notes from emails automatically
277-- Browser extension: Quick capture of web content as tasks or notes
278-- IDE/plugin integration: Direct integration with code editors and development environments
279-- File system integration: Monitor files for content that should become tasks or notes
280281-### Advanced UI/UX Features
282283-- Customizable themes: Multiple visual themes and color schemes
284-- Terminal interface enhancements: Rich TUI with advanced navigation and visualization
285-- Web-based interface: Alternative web UI for browser-based access
286-- Advanced filtering and sorting: Complex query systems for data manipulation
287-- Visual task mapping: Gantt charts, Kanban boards, and other visual representations
288-- Quick entry mode: Rapid capture interface for minimal friction
289-- Keyboard customization: Fully customizable keyboard shortcuts
290291-### Security and Privacy
292293-- End-to-end encryption: Full encryption of sensitive data
294-- Local-first architecture: Guarantee that all data remains local
0000000000000000
···1# ROADMAP
23+Noteleaf is a command-line and TUI tool for managing tasks, notes, media, and articles. This roadmap outlines milestones: current capabilities, planned baseline features (v1), and future directions.
45+## Core Usability
67+The foundation across all domains is implemented. Tasks support CRUD operations, projects, tags, contexts, and time tracking. Notes have create, list, read, edit, and remove commands with interactive and static modes. Media queues exist for books, movies, and TV with progress and status management. SQLite persistence is in place with setup, seed, and reset commands. TUIs and colorized output are available.
00000089+## RC
1011+### CORE
001213+- [ ] Ensure **all documented subcommands** exist and work:
14+ - Tasks: add, list, view, update, edit, delete, projects, tags, contexts, done, start, stop, timesheet
15+ - Notes: create, list, read, edit, remove
16+ - Books: add, list, reading, finished, remove, progress, update
17+ - Movies: add, list, watched, remove
18+ - TV: add, list, watching, watched, remove
19+ - Articles: add, list, view, read, remove
20+- [ ] Confirm all **aliases** work (`todo`, `ls`, `rm`, etc.).
21+- [ ] Verify **flags** and argument parsing match man page (priority, project, context, due, tags, etc.).
22+- [ ] Implement or finish stubs (e.g. `config management` noted in code).
2324+### Task Management Domain
002526+- [ ] Verify tasks can be created with all attributes (priority, project, context, due date, tags).
27+- [ ] Confirm task listing supports interactive and static modes.
28+- [ ] Implement status filtering (`pending`, `completed`, etc.).
29+- [ ] Validate time tracking (start/stop) writes entries and timesheet summarizes correctly.
30+- [ ] Ensure update supports add/remove tags and all fields.
31+- [ ] Test interactive editor (`task edit`).
3233+### Notes Domain
0000003435+- [ ] Implement note creation from:
36+ - Inline text
37+ - File (`--file`)
38+ - Interactive input (`--interactive`)
39+- [ ] Verify note list interactive TUI works, static list fallback works.
40+- [ ] Confirm filtering by tags and `--archived`.
41+- [ ] Ensure notes can be opened, edited in `$EDITOR`, and deleted.
4243+### Media Domains
4445+#### Books
4647+- [ ] Implement search + add (possibly external API).
48+- [ ] Verify list supports statuses (`queued`, `reading`, `finished`).
49+- [ ] Progress updates (`book progress`) work with percentages.
50+- [ ] Status update (`book update`) accepts valid values.
0005152+#### Movies
5354+- [ ] Implement search + add.
55+- [ ] Verify `list` with status filtering (`all`, `queued`, `watched`).
56+- [ ] Confirm `watched`/`remove` commands update correctly.
05758+#### TV
5960+- [ ] Implement search + add.
61+- [ ] Verify `list` with multiple statuses (`queued`, `watching`, `watched`).
62+- [ ] Ensure `watching`, `watched`, `remove` commands behave correctly.
006364+#### Articles
6566+- [ ] Implement article parser (XPath/domain-specific rules).
67+- [ ] Save articles in Markdown + HTML.
68+- [ ] Verify metadata is stored in DB.
69+- [ ] Confirm list supports query, author filter, limit.
70+- [ ] Test article view/read/remove.
7172+### Configuration & Data
0000007374+- [ ] Implement **config management** (flagged TODO in code).
75+- [ ] Define config file format (TOML, YAML, JSON).
76+- [ ] Set default config/data paths:
77+ - Linux: `~/.config/noteleaf`, `~/.local/share/noteleaf`
78+ - macOS: `~/Library/Application Support/noteleaf`
79+ - Windows: `%APPDATA%\noteleaf`
80+- [ ] Implement overrides with environment variables (`NOTELEAF_CONFIG`, `NOTELEAF_DATA_DIR`).
81+- [ ] Ensure consistent DB schema migrations and versioning.
00000000000000000000000000000000000000000000000008283+### Documentation
8485+- [ ] Finalize **man page** (plaintext + roff).
86+- [ ] Write quickstart guide in `README.md`.
87+- [ ] Add examples for each command.
88+- [ ] Document config file with defaults and examples.
89+- [ ] Provide developer docs for contributing.
09091+### QA
9293+- [ ] Verify **unit tests** for all handlers (TaskHandler, NoteHandler, Media Handlers).
94+- [ ] Write **integration tests** covering CLI flows.
95+- [ ] Ensure error handling works for:
96+ - Invalid IDs
97+ - Invalid flags
98+ - Schema corruption (already tested in repo)
99+- [ ] Test cross-platform behavior (Linux/macOS/Windows).
100101+### Packaging
102103+- [ ] Provide prebuilt binaries (via GoReleaser).
104+- [ ] Add installation instructions (Homebrew, AUR, Scoop, etc.).
105+- [ ] Version bump to `v1.0.0-rc1`.
106+- [ ] Publish man page with release.
107+- [ ] Verify `noteleaf --version` returns correct string.
108109+## v1 Features
110111+Planned functionality for a complete baseline release.
0000112113+### Tasks
114115+- [ ] Model
116+ - [ ] Dependencies
117+ - [ ] Recurrence (`recur`, `until`, templates)
118+ - [ ] Wait/scheduled dates
119+ - [ ] Urgency scoring
120+- [ ] Operations
121+ - [ ] `annotate`
122+ - [ ] Bulk edit and undo/history
123+ - [ ] `$EDITOR` integration
124+- [ ] Reports and Views
125+ - [ ] Next actions
126+ - [ ] Completed/waiting/blocked reports
127+ - [ ] Calendar view
128+ - [ ] Sorting and urgency-based views
129+- [ ] Queries and Filters
130+ - [ ] Rich query language
131+ - [ ] Saved filters and aliases
132+- [ ] Interoperability
133+ - [ ] JSON import/export
134+ - [ ] todo.txt compatibility
135136+### Notes
137138+- [ ] Commands
139+ - [ ] `note search`
140+ - [ ] `note tag`
141+ - [ ] `note recent`
142+ - [ ] `note templates`
143+ - [ ] `note archive`
144+ - [ ] `note export`
145+- [ ] Features
146+ - [ ] Full-text search
147+ - [ ] Linking between notes, tasks, and media
148149+### Media
150151+- [ ] Articles/papers/blogs
152+ - [ ] Parser with domain-specific rules
153+ - [ ] Commands: `add`, `list`, `view`, `remove`
154+ - [ ] Metadata validation and storage
155+- [ ] Books
156+ - [ ] Source tracking and ratings
157+ - [ ] Genre/topic tagging
158+- [ ] Movies/TV
159+ - [ ] Ratings and notes
160+ - [ ] Genre/topic tagging
161+ - [ ] Episode/season progress for TV
162+ - [ ] Platform/source tracking
163164+## Beyond v1
165166+Features that demonstrate Go proficiency and broaden Noteleafโs scope.
00167168+### Tasks
169170+- [ ] Parallel report generation and background services
171+- [ ] Hook system for task lifecycle events
172+- [ ] Plugin mechanism
173+- [ ] Generics-based filter engine
174+- [ ] Functional options for configuration
175+- [ ] Error handling with wrapping and sentinel checks
176177+### Notes
178179+- [ ] Templates system for note types
180+- [ ] Versioning and history
181+- [ ] Export with formatting
182+- [ ] Import from other systems
183184+### Media
0185186+- [ ] External imports (Goodreads, IMDB, Letterboxd)
187+- [ ] Cross-referencing across media types
188+- [ ] Analytics: velocity, completion rates
0189190+### Articles
191192+- [ ] Enhanced parsing coverage
193+- [ ] Export to multiple formats
194+- [ ] Linking with tasks and notes
195196+### User Experience
197198+- [ ] Shell completions
199+- [ ] Manpages and docs generator
200+- [ ] Theming and customizable output
201+- [ ] Calendar integration
202203+### Tasks
204205+- [ ] Sub-tasks and hierarchical tasks
206+- [ ] Visual dependency mapping
207+- [ ] Forecasting and smart suggestions
208+- [ ] Habit and streak tracking
209+- [ ] Context-aware recommendations
210211+### Notes
212213+- [ ] Graph view of linked notes
214+- [ ] Content extraction and summarization
215+- [ ] Encryption and privacy controls
216217+### Media
0000000000218219+- [ ] Podcast and YouTube management
220+- [ ] Multi-format (audiobooks, comics)
221+- [ ] Media consumption goals and streaks
222+- [ ] Media budget tracking
223+- [ ] Seasonal and energy-based filtering
224225+### Articles
000000000000226227+- [ ] Content validation
228+- [ ] Encryption support
229+- [ ] Advanced classification
230231+## Technical Infrastructure
0000000232233+### Completed
234235+SQLite persistence, CI with GitHub Actions and Codecov, TUIs with Charm stack, initial help system.
0000236237+### Planned
238239+- Prebuilt binaries for releases
240+- Installation and usage documentation
241+- Contribution guide and developer docs
242+- Consistent argument parsing
243+- Backup/restore
244+- Multiple profiles
245+- Optional synchronization
246247+## v1 Feature Matrix
248249+| Domain | Feature | Status |
250+|----------|-----------------------|-----------|
251+| Tasks | CRUD | Complete |
252+| Tasks | Projects/tags | Complete |
253+| Tasks | Time tracking | Complete |
254+| Tasks | Dependencies | Planned |
255+| Tasks | Recurrence | Planned |
256+| Tasks | Wait/scheduled | Planned |
257+| Tasks | Urgency scoring | Planned |
258+| Notes | CRUD | Complete |
259+| Notes | Search/tagging | Planned |
260+| Media | Books/movies/TV | Complete |
261+| Media | Articles | Planned |
262+| Media | Source/ratings | Planned |
263+| Articles | Parser + storage | Planned |
264+| System | SQLite persistence | Complete |
265+| System | Synchronization | Future |
266+| System | Import/export formats | Future |
···1+NOTELEAF(1) User Commands NOTELEAF(1)
2+3+NAME
4+ noteleaf - manage tasks, notes, books, movies, TV shows, and saved
5+ articles from the command line
6+7+SYNOPSIS
8+ noteleaf [--help] [--version] <command> [<args>]
9+10+DESCRIPTION
11+ noteleaf is a terminal-first productivity tool written in Go. It combines
12+ task management (with time tracking), note-taking, and media queues
13+ (books, movies, TV shows, and saved articles) into a single command-line interface.
14+15+ The design borrows from Taskwarrior and todo.txt but extends them with
16+ features such as:
17+ - Interactive TUIs for browsing notes and tasks
18+ - Article parsing and storage
19+ - Unified commands across different domains
20+ - Time tracking with start/stop and timesheet summaries
21+22+ Subcommands are grouped by domain: task, note, book, movie, tv, and article.
23+ Each group has its own subcommands and options.
24+25+OPTIONS
26+ --help, -h
27+ Show help for noteleaf or any subcommand.
28+29+ --version, -v
30+ Print the current version and exit.
31+32+COMMANDS
33+ General
34+ help [command]
35+ Show help for a command or subcommand.
36+37+ version
38+ Print the program version.
39+40+ TASK COMMANDS
41+ noteleaf task add [description]
42+ Add a new task.
43+ Flags:
44+ -p, --priority <value> Set task priority
45+ --project <name> Set project
46+ -c, --context <name> Set context
47+ -d, --due YYYY-MM-DD Set due date
48+ -t, --tags tag1,tag2 Add tags
49+50+ noteleaf task list
51+ List tasks.
52+ Flags:
53+ -i, --interactive Force interactive mode
54+ --static Print static list
55+ -a, --all Show all tasks
56+ --status <status> Filter by status
57+ --priority <value> Filter by priority
58+ --project <name> Filter by project
59+ --context <name> Filter by context
60+61+ noteleaf task view <id>
62+ View task details.
63+ Flags:
64+ --format detailed|brief Output format
65+ --json Print JSON
66+ --no-metadata Hide metadata
67+68+ noteleaf task update <id>
69+ Update task fields.
70+ Flags:
71+ --description <text>
72+ --status <status>
73+ -p, --priority <value>
74+ --project <name>
75+ -c, --context <name>
76+ -d, --due YYYY-MM-DD
77+ --add-tag tag
78+ --remove-tag tag
79+80+ noteleaf task edit <id>
81+ Interactive edit with status/priority toggles.
82+ Alias: e
83+84+ noteleaf task delete <id>
85+ Delete task permanently.
86+87+ noteleaf task projects
88+ List projects.
89+ Flags: --static, --todo-txt
90+91+ noteleaf task tags
92+ List tags.
93+ Flags: --static
94+95+ noteleaf task contexts
96+ List contexts.
97+ Flags: --static, --todo-txt
98+99+ noteleaf task done <id>
100+ Mark task as completed.
101+ Alias: complete
102+103+ noteleaf task start <id>
104+ Start time tracking for a task.
105+ Flags: -n, --note <text> Add note to entry
106+107+ noteleaf task stop <id>
108+ Stop time tracking for a task.
109+110+ noteleaf task timesheet
111+ Show time tracking summary.
112+ Flags:
113+ -d, --days <n> Number of days (default 7)
114+ -t, --task <id> Timesheet for specific task
115+116+ MOVIE COMMANDS
117+ noteleaf movie add [query...]
118+ Search and add a movie to the watch queue.
119+ Flags: -i, --interactive
120+121+ noteleaf movie list [--all|--watched|--queued]
122+ List movies by status.
123+124+ noteleaf movie watched <id>
125+ Mark movie as watched.
126+ Alias: seen
127+128+ noteleaf movie remove <id>
129+ Remove from queue.
130+ Alias: rm
131+132+ TV COMMANDS
133+ noteleaf tv add [query...]
134+ Search and add a TV show to the watch queue.
135+ Flags: -i, --interactive
136+137+ noteleaf tv list [--all|--queued|--watching|--watched]
138+ List TV shows by status.
139+140+ noteleaf tv watching <id>
141+ Mark as currently watching.
142+143+ noteleaf tv watched <id>
144+ Mark as watched.
145+ Alias: seen
146+147+ noteleaf tv remove <id>
148+ Remove show from queue.
149+ Alias: rm
150+151+ BOOK COMMANDS
152+ noteleaf book add [query...]
153+ Search and add a book to the reading list.
154+ Flags: -i, --interactive
155+156+ noteleaf book list [--all|--reading|--finished|--queued]
157+ Show reading list.
158+159+ noteleaf book reading <id>
160+ Mark book as currently reading.
161+162+ noteleaf book finished <id>
163+ Mark book as finished.
164+ Alias: read
165+166+ noteleaf book remove <id>
167+ Remove from reading list.
168+ Alias: rm
169+170+ noteleaf book progress <id> <percent>
171+ Update reading progress percentage (0-100).
172+173+ noteleaf book update <id> <status>
174+ Update status (queued|reading|finished|removed).
175+176+ NOTE COMMANDS
177+ noteleaf note create [title] [content...]
178+ Create a note.
179+ Aliases: new
180+ Flags:
181+ -i, --interactive Open interactive editor
182+ -e, --editor Open note in editor
183+ -f, --file <path> Create from markdown file
184+185+ noteleaf note list
186+ List notes (interactive TUI or static).
187+ Aliases: ls
188+ Flags:
189+ -a, --archived Include archived
190+ -s, --static Static list
191+ --tags tag1,tag2 Filter by tags
192+193+ noteleaf note read <id>
194+ Display note content.
195+ Alias: view
196+197+ noteleaf note edit <id>
198+ Edit note in editor.
199+200+ noteleaf note remove <id>
201+ Remove note permanently.
202+ Aliases: rm, delete, del
203+204+ ARTICLE COMMANDS
205+ noteleaf article add <url>
206+ Parse and save article from URL.
207+208+ noteleaf article list [query]
209+ List saved articles.
210+ Aliases: ls
211+ Flags:
212+ --author <name>
213+ -l, --limit <n>
214+215+ noteleaf article view <id>
216+ Show article metadata and preview.
217+ Alias: show
218+219+ noteleaf article read <id>
220+ Display full content as Markdown.
221+222+ noteleaf article remove <id>
223+ Remove article and associated files.
224+ Aliases: rm, delete
225+226+EXIT STATUS
227+ noteleaf returns 0 on success.
228+ Non-zero exit status indicates an error.
229+230+EXAMPLES
231+ Add and list tasks:
232+ noteleaf task add "Write blog post" -p H --project blog --due 2025-10-15
233+ noteleaf task list --project blog
234+235+ Mark complete:
236+ noteleaf task done 42
237+238+ Track media:
239+ noteleaf book add "The Name of the Wind"
240+ noteleaf movie add "Blade Runner" -i
241+ noteleaf tv list --watching
242+243+ Work with notes:
244+ noteleaf note create "Ideas" "sketch out product roadmap"
245+ noteleaf note list --tags=work
246+247+ Save an article:
248+ noteleaf article add https://example.com/post
249+ noteleaf article list --author "Ada Lovelace"
250+251+FILES
252+ (TODO: configuration and data file paths once implemented)
253+254+SEE ALSO
255+ Taskwarrior(1), todo.txt(5), git(1), neovim(1), rsync(1)
256+257+AUTHOR
258+ Owais @ Stormlight Labs <https://github.com/stormlightlabs/noteleaf>
259+260+BUGS
261+ Please report issues at: https://github.com/stormlightlabs/noteleaf/issues
262+263+COPYRIGHT
264+ Copyright (c) 2025 Stormlight Labs, LLC.
265+ Licensed under the MIT License.
266+267+NOTELEAF(1) User Commands NOTELEAF(1)
268+
+178-19
internal/handlers/tasks.go
···53}
5455// Create creates a new task
56-func (h *TaskHandler) Create(ctx context.Context, desc []string, priority, project, context, due string, tags []string) error {
57- if len(desc) < 1 {
58 return fmt.Errorf("task description required")
59 }
6061- description := strings.Join(desc, " ")
00000000000000000000000006263 task := &models.Task{
64 UUID: uuid.New().String(),
65- Description: description,
66 Status: "pending",
67 Priority: priority,
68- Project: project,
69- Context: context,
70- Tags: tags,
0071 }
7273- if due != "" {
74- if dueTime, err := time.Parse("2006-01-02", due); err == nil {
75 task.Due = &dueTime
76 } else {
77 return fmt.Errorf("invalid due date format, use YYYY-MM-DD: %w", err)
78 }
79 }
8000000000000081 id, err := h.repos.Tasks.Create(ctx, task)
82 if err != nil {
83 return fmt.Errorf("failed to create task: %w", err)
···88 if priority != "" {
89 fmt.Printf("Priority: %s\n", priority)
90 }
91- if project != "" {
92- fmt.Printf("Project: %s\n", project)
93 }
94- if context != "" {
95- fmt.Printf("Context: %s\n", context)
96 }
97- if len(tags) > 0 {
98- fmt.Printf("Tags: %s\n", strings.Join(tags, ", "))
99 }
100 if task.Due != nil {
101 fmt.Printf("Due: %s\n", task.Due.Format("2006-01-02"))
102 }
000000000000103104 return nil
105}
···150}
151152// Update updates a task using parsed flag values
153-func (h *TaskHandler) Update(ctx context.Context, taskID, description, status, priority, project, context, due string, addTags, removeTags []string) error {
154 var task *models.Task
155 var err error
156···186 return fmt.Errorf("invalid due date format, use YYYY-MM-DD: %w", err)
187 }
188 }
0000000000000189190 for _, tag := range addTags {
191 if !slices.Contains(task.Tags, tag) {
···195196 for _, tag := range removeTags {
197 task.Tags = removeString(task.Tags, tag)
00000000000000000000198 }
199200 err = h.repos.Tasks.Update(ctx, task)
···681 fmt.Printf(" (due: %s)", task.Due.Format("2006-01-02"))
682 }
68300000000684 fmt.Println()
685}
686···710 fmt.Printf("Due: %s\n", task.Due.Format("2006-01-02 15:04"))
711 }
7120000000000000000000713 if !noMetadata {
714 fmt.Printf("Created: %s\n", task.Entry.Format("2006-01-02 15:04"))
715 fmt.Printf("Modified: %s\n", task.Modified.Format("2006-01-02 15:04"))
···740 return nil
741}
742000000000000000000000000000000000000000000000000743func removeString(slice []string, item string) []string {
744 var result []string
745 for _, s := range slice {
···772 return fmt.Sprintf("%.1fh", hours)
773 }
774 days := int(hours / 24)
775- remainingHours := hours - float64(days*24)
776- if remainingHours == 0 {
777 return fmt.Sprintf("%dd", days)
00778 }
779- return fmt.Sprintf("%dd %.1fh", days, remainingHours)
780}
···53}
5455// Create creates a new task
56+func (h *TaskHandler) Create(ctx context.Context, description, priority, project, context, due, recur, until, parentUUID, dependsOn string, tags []string) error {
57+ if description == "" {
58 return fmt.Errorf("task description required")
59 }
6061+ parsed := parseDescription(description)
62+63+ if project != "" {
64+ parsed.Project = project
65+ }
66+ if context != "" {
67+ parsed.Context = context
68+ }
69+ if due != "" {
70+ parsed.Due = due
71+ }
72+ if recur != "" {
73+ parsed.Recur = recur
74+ }
75+ if until != "" {
76+ parsed.Until = until
77+ }
78+ if parentUUID != "" {
79+ parsed.ParentUUID = parentUUID
80+ }
81+ if dependsOn != "" {
82+ parsed.DependsOn = strings.Split(dependsOn, ",")
83+ }
84+ if len(tags) > 0 {
85+ parsed.Tags = append(parsed.Tags, tags...)
86+ }
8788 task := &models.Task{
89 UUID: uuid.New().String(),
90+ Description: parsed.Description,
91 Status: "pending",
92 Priority: priority,
93+ Project: parsed.Project,
94+ Context: parsed.Context,
95+ Tags: parsed.Tags,
96+ Recur: models.RRule(parsed.Recur),
97+ DependsOn: parsed.DependsOn,
98 }
99100+ if parsed.Due != "" {
101+ if dueTime, err := time.Parse("2006-01-02", parsed.Due); err == nil {
102 task.Due = &dueTime
103 } else {
104 return fmt.Errorf("invalid due date format, use YYYY-MM-DD: %w", err)
105 }
106 }
107108+ if parsed.Until != "" {
109+ if untilTime, err := time.Parse("2006-01-02", parsed.Until); err == nil {
110+ task.Until = &untilTime
111+ } else {
112+ return fmt.Errorf("invalid until date format, use YYYY-MM-DD: %w", err)
113+ }
114+ }
115+116+ if parsed.ParentUUID != "" {
117+ task.ParentUUID = &parsed.ParentUUID
118+ }
119+120 id, err := h.repos.Tasks.Create(ctx, task)
121 if err != nil {
122 return fmt.Errorf("failed to create task: %w", err)
···127 if priority != "" {
128 fmt.Printf("Priority: %s\n", priority)
129 }
130+ if task.Project != "" {
131+ fmt.Printf("Project: %s\n", task.Project)
132 }
133+ if task.Context != "" {
134+ fmt.Printf("Context: %s\n", task.Context)
135 }
136+ if len(task.Tags) > 0 {
137+ fmt.Printf("Tags: %s\n", strings.Join(task.Tags, ", "))
138 }
139 if task.Due != nil {
140 fmt.Printf("Due: %s\n", task.Due.Format("2006-01-02"))
141 }
142+ if task.Recur != "" {
143+ fmt.Printf("Recur: %s\n", task.Recur)
144+ }
145+ if task.Until != nil {
146+ fmt.Printf("Until: %s\n", task.Until.Format("2006-01-02"))
147+ }
148+ if task.ParentUUID != nil {
149+ fmt.Printf("Parent: %s\n", *task.ParentUUID)
150+ }
151+ if len(task.DependsOn) > 0 {
152+ fmt.Printf("Depends on: %s\n", strings.Join(task.DependsOn, ", "))
153+ }
154155 return nil
156}
···201}
202203// Update updates a task using parsed flag values
204+func (h *TaskHandler) Update(ctx context.Context, taskID, description, status, priority, project, context, due, recur, until, parentUUID string, addTags, removeTags []string, addDeps, removeDeps string) error {
205 var task *models.Task
206 var err error
207···237 return fmt.Errorf("invalid due date format, use YYYY-MM-DD: %w", err)
238 }
239 }
240+ if recur != "" {
241+ task.Recur = models.RRule(recur)
242+ }
243+ if until != "" {
244+ if untilTime, err := time.Parse("2006-01-02", until); err == nil {
245+ task.Until = &untilTime
246+ } else {
247+ return fmt.Errorf("invalid until date format, use YYYY-MM-DD: %w", err)
248+ }
249+ }
250+ if parentUUID != "" {
251+ task.ParentUUID = &parentUUID
252+ }
253254 for _, tag := range addTags {
255 if !slices.Contains(task.Tags, tag) {
···259260 for _, tag := range removeTags {
261 task.Tags = removeString(task.Tags, tag)
262+ }
263+264+ // Handle dependency additions
265+ if addDeps != "" {
266+ deps := strings.Split(addDeps, ",")
267+ for _, dep := range deps {
268+ dep = strings.TrimSpace(dep)
269+ if dep != "" && !slices.Contains(task.DependsOn, dep) {
270+ task.DependsOn = append(task.DependsOn, dep)
271+ }
272+ }
273+ }
274+275+ // Handle dependency removals
276+ if removeDeps != "" {
277+ deps := strings.Split(removeDeps, ",")
278+ for _, dep := range deps {
279+ dep = strings.TrimSpace(dep)
280+ task.DependsOn = removeString(task.DependsOn, dep)
281+ }
282 }
283284 err = h.repos.Tasks.Update(ctx, task)
···765 fmt.Printf(" (due: %s)", task.Due.Format("2006-01-02"))
766 }
767768+ if task.Recur != "" {
769+ fmt.Printf(" \u21bb")
770+ }
771+772+ if len(task.DependsOn) > 0 {
773+ fmt.Printf(" \u2937%d", len(task.DependsOn))
774+ }
775+776 fmt.Println()
777}
778···802 fmt.Printf("Due: %s\n", task.Due.Format("2006-01-02 15:04"))
803 }
804805+ if task.Recur != "" {
806+ fmt.Printf("Recurrence: %s\n", task.Recur)
807+ }
808+809+ if task.Until != nil {
810+ fmt.Printf("Recur Until: %s\n", task.Until.Format("2006-01-02"))
811+ }
812+813+ if task.ParentUUID != nil {
814+ fmt.Printf("Parent Task: %s\n", *task.ParentUUID)
815+ }
816+817+ if len(task.DependsOn) > 0 {
818+ fmt.Printf("Depends On:\n")
819+ for _, dep := range task.DependsOn {
820+ fmt.Printf(" - %s\n", dep)
821+ }
822+ }
823+824 if !noMetadata {
825 fmt.Printf("Created: %s\n", task.Entry.Format("2006-01-02 15:04"))
826 fmt.Printf("Modified: %s\n", task.Modified.Format("2006-01-02 15:04"))
···851 return nil
852}
853854+// ParsedTaskData holds extracted metadata from a task description
855+type ParsedTaskData struct {
856+ Description string
857+ Project string
858+ Context string
859+ Tags []string
860+ Due string
861+ Recur string
862+ Until string
863+ ParentUUID string
864+ DependsOn []string
865+}
866+867+// parseDescription extracts inline metadata from description text
868+// Supports: +project @context #tag due:YYYY-MM-DD recur:RULE until:DATE parent:UUID depends:UUID1,UUID2
869+func parseDescription(text string) *ParsedTaskData {
870+ parsed := &ParsedTaskData{Tags: []string{}, DependsOn: []string{}}
871+ words := strings.Fields(text)
872+873+ var descWords []string
874+ for _, word := range words {
875+ switch {
876+ case strings.HasPrefix(word, "+"):
877+ parsed.Project = strings.TrimPrefix(word, "+")
878+ case strings.HasPrefix(word, "@"):
879+ parsed.Context = strings.TrimPrefix(word, "@")
880+ case strings.HasPrefix(word, "#"):
881+ parsed.Tags = append(parsed.Tags, strings.TrimPrefix(word, "#"))
882+ case strings.HasPrefix(word, "due:"):
883+ parsed.Due = strings.TrimPrefix(word, "due:")
884+ case strings.HasPrefix(word, "recur:"):
885+ parsed.Recur = strings.TrimPrefix(word, "recur:")
886+ case strings.HasPrefix(word, "until:"):
887+ parsed.Until = strings.TrimPrefix(word, "until:")
888+ case strings.HasPrefix(word, "parent:"):
889+ parsed.ParentUUID = strings.TrimPrefix(word, "parent:")
890+ case strings.HasPrefix(word, "depends:"):
891+ deps := strings.TrimPrefix(word, "depends:")
892+ parsed.DependsOn = strings.Split(deps, ",")
893+ default:
894+ descWords = append(descWords, word)
895+ }
896+ }
897+898+ parsed.Description = strings.Join(descWords, " ")
899+ return parsed
900+}
901+902func removeString(slice []string, item string) []string {
903 var result []string
904 for _, s := range slice {
···931 return fmt.Sprintf("%.1fh", hours)
932 }
933 days := int(hours / 24)
934+ if remainingHours := hours - float64(days*24); remainingHours == 0 {
0935 return fmt.Sprintf("%dd", days)
936+ } else {
937+ return fmt.Sprintf("%dd %.1fh", days, remainingHours)
938 }
0939}
···36 PriorityNumericMax = 5
37)
38000039// Model defines the common interface that all domain models must implement
40type Model interface {
41 // GetID returns the primary key identifier
···5657// Task represents a task item with TaskWarrior-inspired fields
58type Task struct {
59- ID int64 `json:"id"`
60- UUID string `json:"uuid"`
61- Description string `json:"description"`
62- // pending, completed, deleted
63- Status string `json:"status"`
64- // A-Z or empty
65- Priority string `json:"priority,omitempty"`
66- Project string `json:"project,omitempty"`
67- Context string `json:"context,omitempty"`
68- Tags []string `json:"tags,omitempty"`
69- Due *time.Time `json:"due,omitempty"`
70- Entry time.Time `json:"entry"`
71- Modified time.Time `json:"modified"`
72- // completion time
73- End *time.Time `json:"end,omitempty"`
74- // when task was started
75- Start *time.Time `json:"start,omitempty"`
76 Annotations []string `json:"annotations,omitempty"`
000077}
7879// Movie represents a movie in the watch queue
80type Movie struct {
81- ID int64 `json:"id"`
82- Title string `json:"title"`
83- Year int `json:"year,omitempty"`
84- // queued, watched, removed
85- Status string `json:"status"`
86 Rating float64 `json:"rating,omitempty"`
87 Notes string `json:"notes,omitempty"`
88 Added time.Time `json:"added"`
···9192// TVShow represents a TV show in the watch queue
93type TVShow struct {
94- ID int64 `json:"id"`
95- Title string `json:"title"`
96- Season int `json:"season,omitempty"`
97- Episode int `json:"episode,omitempty"`
98- // queued, watching, watched, removed
99- Status string `json:"status"`
100 Rating float64 `json:"rating,omitempty"`
101 Notes string `json:"notes,omitempty"`
102 Added time.Time `json:"added"`
···105106// Book represents a book in the reading list
107type Book struct {
108- ID int64 `json:"id"`
109- Title string `json:"title"`
110- Author string `json:"author,omitempty"`
111- // queued, reading, finished, removed
112- Status string `json:"status"`
113- // percentage 0-100
114- Progress int `json:"progress"`
115 Pages int `json:"pages,omitempty"`
116 Rating float64 `json:"rating,omitempty"`
117 Notes string `json:"notes,omitempty"`
···308 }
309 return 0
310 }
000000000000000000000000000000000000000000000000000311}
312313// IsWatched returns true if the movie has been watched
···36 PriorityNumericMax = 5
37)
3839+// RRule represents a recurrence rule (RFC 5545).
40+// Example: "FREQ=DAILY;INTERVAL=1" or "FREQ=WEEKLY;BYDAY=MO,WE,FR".
41+type RRule string
42+43// Model defines the common interface that all domain models must implement
44type Model interface {
45 // GetID returns the primary key identifier
···6061// Task represents a task item with TaskWarrior-inspired fields
62type Task struct {
63+ ID int64 `json:"id"`
64+ UUID string `json:"uuid"`
65+ Description string `json:"description"`
66+ Status string `json:"status"` // pending, completed, deleted
67+ Priority string `json:"priority,omitempty"` // A-Z or empty
68+ Project string `json:"project,omitempty"`
69+ Context string `json:"context,omitempty"`
70+ Tags []string `json:"tags,omitempty"`
71+ Due *time.Time `json:"due,omitempty"`
72+ Entry time.Time `json:"entry"`
73+ Modified time.Time `json:"modified"`
74+ End *time.Time `json:"end,omitempty"` // Completion time
75+ Start *time.Time `json:"start,omitempty"` // When the task was started
000076 Annotations []string `json:"annotations,omitempty"`
77+ Recur RRule `json:"recur,omitempty"`
78+ Until *time.Time `json:"until,omitempty"` // End date for recurrence
79+ ParentUUID *string `json:"parent_uuid,omitempty"` // ID of parent/template task
80+ DependsOn []string `json:"depends_on,omitempty"` // IDs of tasks this task depends on
81}
8283// Movie represents a movie in the watch queue
84type Movie struct {
85+ ID int64 `json:"id"`
86+ Title string `json:"title"`
87+ Year int `json:"year,omitempty"`
88+ Status string `json:"status"` // queued, watched, removed
089 Rating float64 `json:"rating,omitempty"`
90 Notes string `json:"notes,omitempty"`
91 Added time.Time `json:"added"`
···9495// TVShow represents a TV show in the watch queue
96type TVShow struct {
97+ ID int64 `json:"id"`
98+ Title string `json:"title"`
99+ Season int `json:"season,omitempty"`
100+ Episode int `json:"episode,omitempty"`
101+ Status string `json:"status"` // queued, watching, watched, removed
0102 Rating float64 `json:"rating,omitempty"`
103 Notes string `json:"notes,omitempty"`
104 Added time.Time `json:"added"`
···107108// Book represents a book in the reading list
109type Book struct {
110+ ID int64 `json:"id"`
111+ Title string `json:"title"`
112+ Author string `json:"author,omitempty"`
113+ Status string `json:"status"` // queued, reading, finished, removed
114+ Progress int `json:"progress"` // percentage 0-100
00115 Pages int `json:"pages,omitempty"`
116 Rating float64 `json:"rating,omitempty"`
117 Notes string `json:"notes,omitempty"`
···308 }
309 return 0
310 }
311+}
312+313+// IsStarted returns true if the task has a start time set.
314+func (t *Task) IsStarted() bool {
315+ return t.Start != nil
316+}
317+318+// IsOverdue returns true if the task is overdue.
319+func (t *Task) IsOverdue(now time.Time) bool {
320+ return t.Due != nil && now.After(*t.Due) && !t.IsCompleted()
321+}
322+323+// HasDueDate returns true if the task has a due date set.
324+func (t *Task) HasDueDate() bool {
325+ return t.Due != nil
326+}
327+328+// IsRecurring returns true if the task has recurrence defined.
329+func (t *Task) IsRecurring() bool {
330+ return t.Recur != ""
331+}
332+333+// IsRecurExpired checks if the recurrence has an end (until) date and is past it.
334+func (t *Task) IsRecurExpired(now time.Time) bool {
335+ return t.Until != nil && now.After(*t.Until)
336+}
337+338+// HasDependencies returns true if the task depends on other tasks.
339+func (t *Task) HasDependencies() bool {
340+ return len(t.DependsOn) > 0
341+}
342+343+// Blocks checks if this task blocks another given task.
344+func (t *Task) Blocks(other *Task) bool {
345+ return slices.Contains(other.DependsOn, t.UUID)
346+}
347+348+// Urgency computes a score based on priority, due date, and tags.
349+// This can be expanded later with weights.
350+func (t *Task) Urgency(now time.Time) float64 {
351+ score := 0.0
352+ if t.Priority != "" {
353+ score += 1.0
354+ }
355+ if t.IsOverdue(now) {
356+ score += 2.0
357+ }
358+ if len(t.Tags) > 0 {
359+ score += 0.5
360+ }
361+ return score
362}
363364// IsWatched returns true if the movie has been watched
···1+-- Add recurrence fields directly to tasks
2+ALTER TABLE tasks ADD COLUMN recur TEXT; -- e.g. "daily", "weekly", ISO8601 rule
3+ALTER TABLE tasks ADD COLUMN until DATETIME; -- optional end date for recurrence
4+ALTER TABLE tasks ADD COLUMN parent_uuid TEXT; -- parent/template task UUID
5+6+-- Create dependencies table
7+CREATE TABLE IF NOT EXISTS task_dependencies (
8+ id INTEGER PRIMARY KEY AUTOINCREMENT,
9+ task_uuid TEXT NOT NULL, -- the dependent task
10+ depends_on_uuid TEXT NOT NULL, -- the blocking task
11+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
12+13+ FOREIGN KEY(task_uuid) REFERENCES tasks(uuid) ON DELETE CASCADE,
14+ FOREIGN KEY(depends_on_uuid) REFERENCES tasks(uuid) ON DELETE CASCADE
15+);
16+17+-- Indexes for faster dependency lookups
18+CREATE INDEX IF NOT EXISTS idx_task_dependencies_task_uuid ON task_dependencies(task_uuid);
19+CREATE INDEX IF NOT EXISTS idx_task_dependencies_depends_on_uuid ON task_dependencies(depends_on_uuid);