···30### First Steps
3132For a comprehensive walkthrough including task management, time tracking, notes, and media tracking, see the [Quickstart Guide](website/docs/Quickstart.md).
00000000000000000000000000000000000000000000000000
···30### First Steps
3132For a comprehensive walkthrough including task management, time tracking, notes, and media tracking, see the [Quickstart Guide](website/docs/Quickstart.md).
33+34+## Development
35+36+Noteleaf uses [Task](https://taskfile.dev) for build automation. Development builds include additional tooling commands not available in production builds.
37+38+### Building
39+40+```sh
41+# Production build
42+task build
43+44+# Development build (with version info and dev tools)
45+task build:dev
46+47+# Run tests
48+task test
49+task cov # ...with coverage
50+```
51+52+### Development Tools
53+54+Dev builds (`task build:dev`) include a `tools` subcommand with maintenance utilities:
55+56+**Documentation Generation:**
57+58+```sh
59+# Generate Docusaurus documentation
60+noteleaf tools docgen --format docusaurus --out website/docs/manual
61+62+# Generate man pages
63+noteleaf tools docgen --format man --out docs/manual
64+```
65+66+**Data Synchronization:**
67+68+```sh
69+# Fetch Leaflet lexicons from GitHub
70+noteleaf tools fetch lexicons
71+72+# Fetch from a specific commit
73+noteleaf tools fetch lexicons --sha abc123def
74+75+# Generic GitHub repository archive fetcher
76+noteleaf tools fetch gh-repo \
77+ --repo owner/repo \
78+ --path schemas/ \
79+ --output local/schemas/
80+```
81+82+Production builds (`task build:rc`, `task build:prod`) use the `-tags prod` flag to exclude dev tools.
···51 - echo "Built {{.BUILD_DIR}}/{{.BINARY_NAME}}"
5253 build:dev:
54+ desc: Build binary with dev version (includes git commit hash and dev tools)
55 vars:
56 VERSION: "{{.GIT_DESCRIBE}}"
57 LDFLAGS: "-X {{.VERSION_PKG}}.Version={{.VERSION}} -X {{.VERSION_PKG}}.Commit={{.GIT_COMMIT}} -X {{.VERSION_PKG}}.BuildDate={{.BUILD_DATE}}"
···61 - 'echo "Built {{.BUILD_DIR}}/{{.BINARY_NAME}} (version: {{.VERSION}})"'
6263 build:rc:
64+ desc: Build release candidate binary (requires git tag with -rc suffix, excludes dev tools)
65 vars:
66 VERSION: "{{.GIT_TAG}}"
67 LDFLAGS: "-X {{.VERSION_PKG}}.Version={{.VERSION}} -X {{.VERSION_PKG}}.Commit={{.GIT_COMMIT}} -X {{.VERSION_PKG}}.BuildDate={{.BUILD_DATE}}"
···72 msg: "Git tag must contain '-rc' for release candidate builds (e.g., v1.0.0-rc1)"
73 cmds:
74 - mkdir -p {{.BUILD_DIR}}
75+ - go build -tags prod -ldflags "{{.LDFLAGS}}" -o {{.BUILD_DIR}}/{{.BINARY_NAME}} {{.CMD_DIR}}
76 - 'echo "Built {{.BUILD_DIR}}/{{.BINARY_NAME}} (version: {{.VERSION}})"'
7778 build:prod:
79+ desc: Build production binary (requires clean semver git tag, excludes dev tools)
80 vars:
81 VERSION: "{{.GIT_TAG}}"
82 LDFLAGS: "-X {{.VERSION_PKG}}.Version={{.VERSION}} -X {{.VERSION_PKG}}.Commit={{.GIT_COMMIT}} -X {{.VERSION_PKG}}.BuildDate={{.BUILD_DATE}}"
···89 msg: "Working directory must be clean (no uncommitted changes) for production builds"
90 cmds:
91 - mkdir -p {{.BUILD_DIR}}
92+ - go build -tags prod -ldflags "{{.LDFLAGS}}" -o {{.BUILD_DIR}}/{{.BINARY_NAME}} {{.CMD_DIR}}
93 - 'echo "Built {{.BUILD_DIR}}/{{.BINARY_NAME}} (version: {{.VERSION}})"'
9495 clean:
+9-6
cmd/commands.go
···30 Short: "Manage movie watch queue",
31 Long: `Track movies you want to watch.
3233-Search TMDB for movies and add them to your queue. Mark movies as watched when
34-completed. Maintains a history of your movie watching activity.`,
35 }
360037 addCmd := &cobra.Command{
38 Use: "add [search query...]",
39 Short: "Search and add movie to watch queue",
···54 addCmd.Flags().BoolP("interactive", "i", false, "Use interactive interface for movie selection")
55 root.AddCommand(addCmd)
56057 root.AddCommand(&cobra.Command{
58 Use: "list [--all|--watched|--queued]",
59 Short: "List movies in queue with status filtering",
···102 return c.handler.Remove(cmd.Context(), args[0])
103 },
104 })
105-106 return root
107}
108···122 Short: "Manage TV show watch queue",
123 Long: `Track TV shows and episodes.
124125-Search TMDB for TV shows and add them to your queue. Track which shows you're
126-currently watching, mark episodes as watched, and maintain a complete history
127-of your viewing activity.`,
128 }
129130 addCmd := &cobra.Command{
···147 addCmd.Flags().BoolP("interactive", "i", false, "Use interactive interface for TV show selection")
148 root.AddCommand(addCmd)
1490150 root.AddCommand(&cobra.Command{
151 Use: "list [--all|--queued|--watching|--watched]",
152 Short: "List TV shows in queue with status filtering",
···30 Short: "Manage movie watch queue",
31 Long: `Track movies you want to watch.
3233+Search for movies and add them to your queue. Mark movies as watched
34+when completed. Maintains a history of your movie watching activity.`,
35 }
3637+ // TODO: add colors
38+ // TODO: fix critic score parsing
39 addCmd := &cobra.Command{
40 Use: "add [search query...]",
41 Short: "Search and add movie to watch queue",
···56 addCmd.Flags().BoolP("interactive", "i", false, "Use interactive interface for movie selection")
57 root.AddCommand(addCmd)
5859+ // TODO: add interactive list view
60 root.AddCommand(&cobra.Command{
61 Use: "list [--all|--watched|--queued]",
62 Short: "List movies in queue with status filtering",
···105 return c.handler.Remove(cmd.Context(), args[0])
106 },
107 })
0108 return root
109}
110···124 Short: "Manage TV show watch queue",
125 Long: `Track TV shows and episodes.
126127+Search for TV shows and add them to your queue. Track which shows you're currently
128+watching, mark episodes as watched, and maintain a complete history of your viewing
129+activity.`,
130 }
131132 addCmd := &cobra.Command{
···149 addCmd.Flags().BoolP("interactive", "i", false, "Use interactive interface for TV show selection")
150 root.AddCommand(addCmd)
151152+ // TODO: Add interactive list view
153 root.AddCommand(&cobra.Command{
154 Use: "list [--all|--queued|--watching|--watched]",
155 Short: "List TV shows in queue with status filtering",
···1package main
23import (
4+ "fmt"
5+ "strconv"
6 "strings"
78 "github.com/spf13/cobra"
···35 &cobra.Group{ID: "task-ops", Title: "Basic Operations"},
36 &cobra.Group{ID: "task-meta", Title: "Metadata"},
37 &cobra.Group{ID: "task-tracking", Title: "Tracking"},
38+ &cobra.Group{ID: "task-reports", Title: "Reports & Views"},
39 )
4041 for _, init := range []func(*handlers.TaskHandler) *cobra.Command{
42+ addTaskCmd, listTaskCmd, viewTaskCmd, updateTaskCmd, editTaskCmd, deleteTaskCmd, taskAnnotateCmd, taskBulkEditCmd,
43 } {
44 cmd := init(c.handler)
45 cmd.GroupID = "task-ops"
···55 }
5657 for _, init := range []func(*handlers.TaskHandler) *cobra.Command{
58+ timesheetViewCmd, taskStartCmd, taskStopCmd, taskCompleteCmd, taskRecurCmd, taskDependCmd, taskUndoCmd, taskHistoryCmd,
59 } {
60 cmd := init(c.handler)
61 cmd.GroupID = "task-tracking"
62 root.AddCommand(cmd)
63 }
6465+ for _, init := range []func(*handlers.TaskHandler) *cobra.Command{
66+ nextActionsCmd, reportCompletedCmd, reportWaitingCmd, reportBlockedCmd, calendarCmd,
67+ } {
68+ cmd := init(c.handler)
69+ cmd.GroupID = "task-reports"
70+ root.AddCommand(cmd)
71+ }
72+73 return root
74}
75···95 project, _ := c.Flags().GetString("project")
96 context, _ := c.Flags().GetString("context")
97 due, _ := c.Flags().GetString("due")
98+ wait, _ := c.Flags().GetString("wait")
99+ scheduled, _ := c.Flags().GetString("scheduled")
100 recur, _ := c.Flags().GetString("recur")
101 until, _ := c.Flags().GetString("until")
102 parent, _ := c.Flags().GetString("parent")
···104 tags, _ := c.Flags().GetStringSlice("tags")
105106 defer h.Close()
107+ // TODO: Make a CreateTask struct
108+ return h.Create(c.Context(), description, priority, project, context, due, wait, scheduled, recur, until, parent, dependsOn, tags)
109 },
110 }
111 addCommonTaskFlags(cmd)
112 addDueDateFlag(cmd)
113+ addWaitScheduledFlags(cmd)
114 addRecurrenceFlags(cmd)
115 addParentFlag(cmd)
116 addDependencyFlags(cmd)
···135 priority, _ := c.Flags().GetString("priority")
136 project, _ := c.Flags().GetString("project")
137 context, _ := c.Flags().GetString("context")
138+ sortBy, _ := c.Flags().GetString("sort")
139140 defer h.Close()
141+ // TODO: TaskFilter struct
142+ return h.List(c.Context(), static, showAll, status, priority, project, context, sortBy)
143 },
144 }
145 cmd.Flags().BoolP("interactive", "i", false, "Force interactive mode (default)")
···149 cmd.Flags().String("priority", "", "Filter by priority")
150 cmd.Flags().String("project", "", "Filter by project")
151 cmd.Flags().String("context", "", "Filter by context")
152+ cmd.Flags().String("sort", "", "Sort by (urgency)")
153154 return cmd
155}
···469 return root
470}
471472+func nextActionsCmd(h *handlers.TaskHandler) *cobra.Command {
473+ cmd := &cobra.Command{
474+ Use: "next",
475+ Short: "Show next actions (actionable tasks sorted by urgency)",
476+ Aliases: []string{"na"},
477+ Long: `Display actionable tasks sorted by urgency score.
478+479+Shows tasks that can be worked on now (not waiting, not blocked, not completed),
480+ordered by their computed urgency based on priority, due date, age, and other factors.`,
481+ RunE: func(c *cobra.Command, args []string) error {
482+ limit, _ := c.Flags().GetInt("limit")
483+ defer h.Close()
484+ return h.NextActions(c.Context(), limit)
485+ },
486+ }
487+ cmd.Flags().IntP("limit", "n", 10, "Limit number of tasks shown")
488+ return cmd
489+}
490+491+func reportCompletedCmd(h *handlers.TaskHandler) *cobra.Command {
492+ cmd := &cobra.Command{
493+ Use: "completed",
494+ Short: "Show completed tasks",
495+ Long: "Display tasks that have been completed, sorted by completion date.",
496+ RunE: func(c *cobra.Command, args []string) error {
497+ limit, _ := c.Flags().GetInt("limit")
498+ defer h.Close()
499+ return h.ReportCompleted(c.Context(), limit)
500+ },
501+ }
502+ cmd.Flags().IntP("limit", "n", 20, "Limit number of tasks shown")
503+ return cmd
504+}
505+506+func reportWaitingCmd(h *handlers.TaskHandler) *cobra.Command {
507+ cmd := &cobra.Command{
508+ Use: "waiting",
509+ Short: "Show waiting tasks",
510+ Long: "Display tasks that are waiting for a specific date before becoming actionable.",
511+ RunE: func(c *cobra.Command, args []string) error {
512+ defer h.Close()
513+ return h.ReportWaiting(c.Context())
514+ },
515+ }
516+ return cmd
517+}
518+519+func reportBlockedCmd(h *handlers.TaskHandler) *cobra.Command {
520+ cmd := &cobra.Command{
521+ Use: "blocked",
522+ Short: "Show blocked tasks",
523+ Long: "Display tasks that are blocked by dependencies on other tasks.",
524+ RunE: func(c *cobra.Command, args []string) error {
525+ defer h.Close()
526+ return h.ReportBlocked(c.Context())
527+ },
528+ }
529+ return cmd
530+}
531+532+func calendarCmd(h *handlers.TaskHandler) *cobra.Command {
533+ cmd := &cobra.Command{
534+ Use: "calendar",
535+ Short: "Show tasks in calendar view",
536+ Aliases: []string{"cal"},
537+ Long: `Display tasks with due dates in a calendar format.
538+539+Shows tasks organized by week and day, making it easy to see upcoming deadlines
540+and plan your work schedule.`,
541+ RunE: func(c *cobra.Command, args []string) error {
542+ weeks, _ := c.Flags().GetInt("weeks")
543+ defer h.Close()
544+ return h.Calendar(c.Context(), weeks)
545+ },
546+ }
547+ cmd.Flags().IntP("weeks", "w", 4, "Number of weeks to show")
548+ return cmd
549+}
550+551func taskDependCmd(h *handlers.TaskHandler) *cobra.Command {
552 root := &cobra.Command{
553 Use: "depend",
···611 root.AddCommand(addCmd, removeCmd, listCmd, blockedByCmd)
612 return root
613}
614+615+func taskAnnotateCmd(h *handlers.TaskHandler) *cobra.Command {
616+ root := &cobra.Command{
617+ Use: "annotate",
618+ Aliases: []string{"note"},
619+ Short: "Manage task annotations",
620+ Long: `Add, list, or remove annotations on tasks.
621+622+Annotations are timestamped notes that provide context and updates
623+about a task's progress or relevant information.`,
624+ }
625+626+ addCmd := &cobra.Command{
627+ Use: "add <task-id> <annotation>",
628+ Short: "Add an annotation to a task",
629+ Aliases: []string{"create"},
630+ Args: cobra.MinimumNArgs(2),
631+ RunE: func(c *cobra.Command, args []string) error {
632+ taskID := args[0]
633+ annotation := strings.Join(args[1:], " ")
634+ defer h.Close()
635+ return h.Annotate(c.Context(), taskID, annotation)
636+ },
637+ }
638+639+ listCmd := &cobra.Command{
640+ Use: "list <task-id>",
641+ Short: "List all annotations for a task",
642+ Aliases: []string{"ls", "show"},
643+ Args: cobra.ExactArgs(1),
644+ RunE: func(c *cobra.Command, args []string) error {
645+ defer h.Close()
646+ return h.ListAnnotations(c.Context(), args[0])
647+ },
648+ }
649+650+ removeCmd := &cobra.Command{
651+ Use: "remove <task-id> <index>",
652+ Short: "Remove an annotation by index",
653+ Aliases: []string{"rm", "delete"},
654+ Args: cobra.ExactArgs(2),
655+ RunE: func(c *cobra.Command, args []string) error {
656+ taskID := args[0]
657+ index, err := strconv.Atoi(args[1])
658+ if err != nil {
659+ return fmt.Errorf("invalid annotation index: %w", err)
660+ }
661+ defer h.Close()
662+ return h.RemoveAnnotation(c.Context(), taskID, index)
663+ },
664+ }
665+666+ root.AddCommand(addCmd, listCmd, removeCmd)
667+ return root
668+}
669+670+func taskBulkEditCmd(h *handlers.TaskHandler) *cobra.Command {
671+ cmd := &cobra.Command{
672+ Use: "bulk-edit <task-id>...",
673+ Aliases: []string{"bulk"},
674+ Short: "Update multiple tasks at once",
675+ Long: `Update multiple tasks with the same changes.
676+677+Allows batch updates to status, priority, project, context, and tags.
678+Use --add-tags to add tags without replacing existing ones.
679+Use --remove-tags to remove specific tags from tasks.
680+681+Examples:
682+ noteleaf todo bulk-edit 1 2 3 --status done
683+ noteleaf todo bulk-edit 1 2 --project web --priority high
684+ noteleaf todo bulk-edit 1 2 3 --add-tags urgent,review`,
685+ Args: cobra.MinimumNArgs(1),
686+ RunE: func(c *cobra.Command, args []string) error {
687+ status, _ := c.Flags().GetString("status")
688+ priority, _ := c.Flags().GetString("priority")
689+ project, _ := c.Flags().GetString("project")
690+ context, _ := c.Flags().GetString("context")
691+ tags, _ := c.Flags().GetStringSlice("tags")
692+ addTags, _ := c.Flags().GetBool("add-tags")
693+ removeTags, _ := c.Flags().GetBool("remove-tags")
694+695+ defer h.Close()
696+ return h.BulkEdit(c.Context(), args, status, priority, project, context, tags, addTags, removeTags)
697+ },
698+ }
699+700+ cmd.Flags().String("status", "", "Set status for all tasks")
701+ cmd.Flags().String("priority", "", "Set priority for all tasks")
702+ cmd.Flags().String("project", "", "Set project for all tasks")
703+ cmd.Flags().String("context", "", "Set context for all tasks")
704+ cmd.Flags().StringSlice("tags", []string{}, "Set tags for all tasks")
705+ cmd.Flags().Bool("add-tags", false, "Add tags instead of replacing")
706+ cmd.Flags().Bool("remove-tags", false, "Remove specified tags")
707+708+ return cmd
709+}
710+711+func taskUndoCmd(h *handlers.TaskHandler) *cobra.Command {
712+ cmd := &cobra.Command{
713+ Use: "undo <task-id>",
714+ Short: "Undo the last change to a task",
715+ Long: `Revert a task to its previous state before the last update.
716+717+This command uses the task history to restore the task to how it was
718+before the most recent modification.
719+720+Examples:
721+ noteleaf todo undo 1
722+ noteleaf todo undo abc-123-uuid`,
723+ Args: cobra.ExactArgs(1),
724+ RunE: func(c *cobra.Command, args []string) error {
725+ defer h.Close()
726+ return h.UndoTask(c.Context(), args[0])
727+ },
728+ }
729+730+ return cmd
731+}
732+733+func taskHistoryCmd(h *handlers.TaskHandler) *cobra.Command {
734+ cmd := &cobra.Command{
735+ Use: "history <task-id>",
736+ Aliases: []string{"log"},
737+ Short: "Show change history for a task",
738+ Long: `Display the history of changes made to a task.
739+740+Shows a chronological list of modifications with timestamps.
741+742+Examples:
743+ noteleaf todo history 1
744+ noteleaf todo history 1 --limit 5`,
745+ Args: cobra.ExactArgs(1),
746+ RunE: func(c *cobra.Command, args []string) error {
747+ limit, _ := c.Flags().GetInt("limit")
748+ defer h.Close()
749+ return h.ShowHistory(c.Context(), args[0], limit)
750+ },
751+ }
752+753+ cmd.Flags().IntP("limit", "n", 10, "Limit number of history entries")
754+755+ return cmd
756+}
+5
cmd/task_flags.go
···31func addDueDateFlag(cmd *cobra.Command) {
32 cmd.Flags().StringP("due", "d", "", "Set due date (YYYY-MM-DD)")
33}
00000
···31func addDueDateFlag(cmd *cobra.Command) {
32 cmd.Flags().StringP("due", "d", "", "Set due date (YYYY-MM-DD)")
33}
34+35+func addWaitScheduledFlags(cmd *cobra.Command) {
36+ cmd.Flags().StringP("wait", "w", "", "Task not actionable until date (YYYY-MM-DD)")
37+ cmd.Flags().StringP("scheduled", "s", "", "Task scheduled to start on date (YYYY-MM-DD)")
38+}
+13
cmd/tools_dev.go
···0000000000000
···1+//go:build !prod
2+3+package main
4+5+import (
6+ "github.com/spf13/cobra"
7+ "github.com/stormlightlabs/noteleaf/tools"
8+)
9+10+// registerTools adds development tools to the root command
11+func registerTools(root *cobra.Command) {
12+ root.AddCommand(tools.NewToolsCommand(root))
13+}
+8
cmd/tools_prod.go
···00000000
···1+//go:build prod
2+3+package main
4+5+import "github.com/spf13/cobra"
6+7+// registerTools is a no-op in production builds
8+func registerTools(*cobra.Command) {}
+193-42
internal/docs/ROADMAP.md
···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.
089## RC
10···43#### Publication
4445- [x] Implement authentication with BlueSky/leaflet (AT Protocol).
46- - [ ] Add OAuth2
47- [x] Verify `pub pull` fetches and syncs documents from leaflet.
48- [x] Confirm `pub list` with status filtering (`all`, `published`, `draft`).
49-- [ ] Test `pub post` creates new documents with draft/preview/validate modes.
50-- [ ] Ensure `pub patch` updates existing documents correctly.
51-- [ ] Validate `pub push` handles batch operations (create/update).
52-- [ ] Verify markdown conversion to leaflet block format (headings, code, images, facets).
5354### Media Domains
55···109 - Invalid IDs
110 - Invalid flags
111 - Schema corruption (already tested in repo)
112-- [ ] Test cross-platform behavior (Linux/macOS/Windows).
113114### Packaging
115···125126### Tasks
127128-- [ ] Model
129- - [ ] Dependencies
130- - [ ] Recurrence (`recur`, `until`, templates)
131- - [ ] Wait/scheduled dates
132- - [ ] Urgency scoring
133-- [ ] Operations
134- - [ ] `annotate`
135- - [ ] Bulk edit and undo/history
136- - [ ] `$EDITOR` integration
137-- [ ] Reports and Views
138- - [ ] Next actions
139- - [ ] Completed/waiting/blocked reports
140- - [ ] Calendar view
141- - [ ] Sorting and urgency-based views
142- [ ] Queries and Filters
143 - [ ] Rich query language
144 - [ ] Saved filters and aliases
···149### Notes
150151- [ ] Commands
152- - [ ] `note search`
153 - [ ] `note tag`
154 - [ ] `note recent`
155 - [ ] `note templates`
156 - [ ] `note archive`
157 - [ ] `note export`
158- [ ] Features
159- - [ ] Full-text search
160 - [ ] Linking between notes, tasks, and media
161000000000000000000000000000000000000000000000000000000000000000000000000000000000162### Media
163164- [ ] Articles/papers/blogs
···199- [ ] External imports (Goodreads, IMDB, Letterboxd)
200- [ ] Cross-referencing across media types
201- [ ] Analytics: velocity, completion rates
00000000000202203### Articles
204···206- [ ] Export to multiple formats
207- [ ] Linking with tasks and notes
2080000000000000000000000000000000000209### User Experience
210211- [ ] Shell completions
212- [ ] Manpages and docs generator
213- [ ] Theming and customizable output
214- [ ] Calendar integration
000215216### Tasks
217···243244### Local API Server
245246-A local HTTP server daemon that exposes Noteleaf data for web UIs and extensions. Runs on the user's machine and provides programmatic access to tasks, notes, and media.
0247248#### Architecture
249···371#### Post v1
372373- Backup/restore
00374- Multiple profiles
375- Optional synchronization
0000000376377## v1 Feature Matrix
378379-| Domain | Feature | Status |
380-|----------|-----------------------|-----------|
381-| Tasks | CRUD | Complete |
382-| Tasks | Projects/tags | Complete |
383-| Tasks | Time tracking | Complete |
384-| Tasks | Dependencies | Complete |
385-| Tasks | Recurrence | Complete |
386-| Tasks | Wait/scheduled | Planned |
387-| Tasks | Urgency scoring | Planned |
388-| Notes | CRUD | Complete |
389-| Notes | Search/tagging | Planned |
390-| Media | Books/movies/TV | Complete |
391-| Media | Articles | Complete |
392-| Media | Source/ratings | Planned |
393-| Articles | Parser + storage | Complete |
394-| System | SQLite persistence | Complete |
395-| System | Synchronization | Future |
396-| System | Import/export formats | Future |
0000000000000
···45## Core Usability
67+The foundation across all domains is implemented. Tasks support CRUD operations, projects, tags, contexts, and time tracking.
8+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.
910## RC
11···44#### Publication
4546- [x] Implement authentication with BlueSky/leaflet (AT Protocol).
47+ - [ ] Add [OAuth2](#publications--authentication)
48- [x] Verify `pub pull` fetches and syncs documents from leaflet.
49- [x] Confirm `pub list` with status filtering (`all`, `published`, `draft`).
50+- [x] Test `pub post` creates new documents with draft/preview/validate modes.
51+- [x] Ensure `pub patch` updates existing documents correctly.
52+- [x] Validate `pub push` handles batch operations (create/update).
53+- [x] Verify markdown conversion to leaflet block format (headings, code, images, facets).
5455### Media Domains
56···110 - Invalid IDs
111 - Invalid flags
112 - Schema corruption (already tested in repo)
0113114### Packaging
115···125126### Tasks
127128+- [x] Model
129+ - [x] Dependencies
130+ - [x] Recurrence (`recur`, `until`, templates)
131+ - [x] Wait/scheduled dates
132+ - [x] Urgency scoring
133+- [x] Operations
134+ - [x] `annotate`
135+ - [x] Bulk edit and undo/history
136+- [x] Reports and Views
137+ - [x] Next actions
138+ - [x] Completed/waiting/blocked reports
139+ - [x] Calendar view
140+ - [x] Sorting and urgency-based views
0141- [ ] Queries and Filters
142 - [ ] Rich query language
143 - [ ] Saved filters and aliases
···148### Notes
149150- [ ] Commands
151+ - [x] `note search` - TF-IDF search via `search query` command
152 - [ ] `note tag`
153 - [ ] `note recent`
154 - [ ] `note templates`
155 - [ ] `note archive`
156 - [ ] `note export`
157- [ ] Features
158+ - [x] Full-text search - TF-IDF ranking with Unicode tokenization
159 - [ ] Linking between notes, tasks, and media
160161+### Search
162+163+#### Ranking Improvements
164+165+- [ ] BM25 scoring algorithm
166+ - [ ] Implement Okapi BM25 with configurable parameters (k1, b)
167+ - [ ] Field-aware BM25F with title/body weighting
168+ - [ ] Pluggable scoring strategy interface (TF-IDF/BM25 interchangeable)
169+ - [ ] Benchmark against TF-IDF on sample corpus
170+171+#### Query Features
172+173+- [ ] Phrase and proximity queries
174+ - [ ] Positional inverted index (track term positions in documents)
175+ - [ ] Exact phrase matching (`"go programming"`)
176+ - [ ] Proximity scoring (boost when terms appear near each other)
177+- [ ] Query understanding
178+ - [ ] Synonym expansion with configurable dictionaries
179+ - [ ] Boolean operators (AND, OR, NOT)
180+ - [ ] Field-specific queries (`title:golang body:concurrency`)
181+ - [ ] Spelling correction with edit distance suggestions
182+ - [ ] Query boosting syntax (`title^3 golang`)
183+184+#### Linguistic Processing
185+186+- [ ] Text normalization
187+ - [ ] Porter stemmer for English (run/runs/running โ run)
188+ - [ ] Stopword filtering with domain-specific lists
189+ - [ ] Unicode normalization and diacritic folding
190+ - [ ] Configurable token filter pipeline
191+- [ ] Multi-language support
192+ - [ ] Language detection
193+ - [ ] Language-specific stemmers
194+ - [ ] CJK tokenization improvements
195+196+#### Advanced Scoring
197+198+- [ ] Learning to Rank
199+ - [ ] Feature extraction (TF-IDF/BM25 scores, term coverage, recency)
200+ - [ ] Click-through rate tracking for relevance feedback
201+ - [ ] Gradient-boosted tree models for re-ranking
202+ - [ ] Evaluation metrics (NDCG, MAP)
203+- [ ] Non-text signals
204+ - [ ] Document recency scoring
205+ - [ ] Tag-based relevance
206+ - [ ] User interaction signals
207+208+#### Index Management
209+210+- [ ] Persistence and optimization
211+ - [ ] On-disk index snapshots (gob serialization)
212+ - [ ] Segmented indexing with periodic merging (Lucene-style)
213+ - [ ] Incremental updates (add/update/delete without full rebuild)
214+ - [ ] Index versioning and rollback
215+ - [ ] Compression for large corpora
216+- [ ] Performance
217+ - [ ] Index build benchmarks vs corpus size
218+ - [ ] Query latency monitoring
219+ - [ ] Memory usage profiling
220+ - [ ] Concurrent search support
221+222+#### User Experience
223+224+- [ ] Interactive search interface
225+ - [ ] TUI with real-time search-as-you-type
226+ - [ ] Result navigation with vim keybindings
227+ - [ ] Preview pane showing full note content
228+ - [ ] Filtering by tags, date ranges, doc kind
229+ - [ ] Sort options (relevance, date, alphabetical)
230+ - [ ] Quick actions (open in editor, copy ID, tag)
231+- [ ] Search result display
232+ - [ ] Snippet generation with matched term highlighting
233+ - [ ] Configurable result limit and pagination
234+ - [ ] Score explanation mode (`--explain` flag)
235+ - [ ] Export results to JSON/CSV
236+- [ ] CLI
237+ - [ ] Saved search queries and aliases
238+ - [ ] Search history
239+ - [ ] Query latency and result count in output
240+ - [ ] Color-coded relevance scores
241+242### Media
243244- [ ] Articles/papers/blogs
···279- [ ] External imports (Goodreads, IMDB, Letterboxd)
280- [ ] Cross-referencing across media types
281- [ ] Analytics: velocity, completion rates
282+- [ ] Books (Open Library integration enhancements)
283+ - [ ] Author detail fetching (full names, bio)
284+ - [ ] Edition-specific metadata
285+ - [ ] Cover image download and caching
286+ - [ ] Reading progress tracking
287+ - [ ] Personal reading lists sync
288+- [ ] Movies/TV (external API integration)
289+ - [ ] Movie databases (TMDb, OMDb)
290+ - [ ] Rotten Tomatoes integration
291+- [ ] Music
292+ - [ ] Music services (MusicBrainz, Album of the Year)
293294### Articles
295···297- [ ] Export to multiple formats
298- [ ] Linking with tasks and notes
299300+### Publications & Authentication
301+302+- [ ] OAuth2 authentication for AT Protocol
303+ - [ ] Client metadata server for publishing application details
304+ - [ ] DPoP (Demonstrating Proof of Possession) implementation
305+ - [ ] ES256 JWT generation with unique JTI nonces
306+ - [ ] Server-issued nonce management with 5-minute rotation
307+ - [ ] Separate nonce tracking for authorization and resource servers
308+ - [ ] PAR (Pushed Authorization Requests) flow
309+ - [ ] PKCE code challenge generation
310+ - [ ] State token management
311+ - [ ] Request URI handling
312+ - [ ] Identity resolution and verification
313+ - [ ] Bidirectional handle verification
314+ - [ ] DID resolution from handles
315+ - [ ] Authorization server discovery via .well-known endpoints
316+ - [ ] Token lifecycle management
317+ - [ ] Access token refresh (5-15 min lifetime recommended)
318+ - [ ] Refresh token rotation (180 day max for confidential clients)
319+ - [ ] Concurrent request handling to prevent duplicate refreshes
320+ - [ ] Secure token storage (encrypted at rest)
321+ - [ ] Local callback server for OAuth redirects
322+ - [ ] Ephemeral HTTP server on localhost
323+ - [ ] Browser launch integration
324+ - [ ] Timeout handling for abandoned flows
325+ - [ ] Support both OAuth & App Passwords but recommend OAuth
326+- [ ] Leaflet.pub enhancements
327+ - [ ] Multiple Publications: Manage separate publications for different topics
328+ - [ ] Image Upload: Automatically upload images to blob storage and embed in documents
329+ - [ ] Status Management: Publish drafts and unpublish documents from CLI
330+ - [ ] Metadata Editing: Update document titles, summaries, and tags
331+ - [ ] Backlink Support: Parse and resolve cross-references between documents
332+ - [ ] Offline Mode: Queue posts and patches for later upload
333+334### User Experience
335336- [ ] Shell completions
337- [ ] Manpages and docs generator
338- [ ] Theming and customizable output
339- [ ] Calendar integration
340+- [ ] Task synchronization services
341+- [ ] Git repository linking
342+- [ ] Note export to other platforms
343344### Tasks
345···371372### Local API Server
373374+A local HTTP server daemon that exposes Noteleaf data for web UIs and extensions.
375+Runs on the user's machine and provides programmatic access to tasks, notes, and media.
376377#### Architecture
378···500#### Post v1
501502- Backup/restore
503+ - [ ] Automated backups
504+ - [ ] Backup scheduling and rotation
505- Multiple profiles
506- Optional synchronization
507+ - [ ] Sync service
508+- Import/Export
509+ - [ ] CSV export for tasks
510+ - [ ] Markdown export for tasks
511+ - [ ] Bulk export commands
512+ - [ ] Migration utilities (TaskWarrior, todo.txt, etc.)
513+ - [ ] Git integration for notes/data versioning
514515## v1 Feature Matrix
516517+| Domain | Feature | Status |
518+|--------------|----------------------------|-----------|
519+| Tasks | CRUD | Complete |
520+| Tasks | Projects/tags | Complete |
521+| Tasks | Time tracking | Complete |
522+| Tasks | Dependencies | Complete |
523+| Tasks | Recurrence | Complete |
524+| Tasks | Wait/scheduled | Complete |
525+| Tasks | Urgency scoring | Complete |
526+| Tasks | Reports and views | Complete |
527+| Notes | CRUD | Complete |
528+| Notes | Search (TF-IDF) | Complete |
529+| Notes | Advanced search | Planned |
530+| Notes | Tagging | Planned |
531+| Publications | AT Protocol sync | Complete |
532+| Publications | Post/patch/push | Complete |
533+| Publications | Markdown conversion | Complete |
534+| Publications | OAuth2 | Future |
535+| Media | Books/movies/TV | Complete |
536+| Media | Articles | Complete |
537+| Media | Source/ratings | Planned |
538+| Articles | Parser + storage | Complete |
539+| System | SQLite persistence | Complete |
540+| System | Configuration management | Complete |
541+| System | Synchronization | Future |
542+| System | Import/export formats | Future |
543+544+## Parking Lot
545+546+- [ ] Test cross-platform behavior (Linux/macOS/Windows).
547+- [ ] `$EDITOR` integration
···1+<!DOCTYPE html><html lang="en" dir="ltr" xmlns="http://www.w3.org/1999/xhtml" prefix="fb: http://www.facebook.com/2008/fbml og: http://opengraphprotocol.org/schema/"><head prefix="og: http://ogp.me/ns# flixstertomatoes: http://ogp.me/ns/apps/flixstertomatoes#"><script charset="UTF-8" crossorigin="anonymous" data-domain-script="7e979733-6841-4fce-9182-515fac69187f" integrity="sha384-TKdmlzVmoD70HzftTw4WtOzIBL5mNx8mXSRzEvwrWjpIJ7FZ/EuX758yMDWXtRUN" src="https://cdn.cookielaw.org/consent/7e979733-6841-4fce-9182-515fac69187f/otSDKStub.js" type="text/javascript"></script><script type="text/javascript">function OptanonWrapper(){ if (OnetrustActiveGroups.includes('7')){ document.querySelector('search-results-nav-manager')?.setAlgoliaInsightUserToken?.()}} </script><script ccpa-opt-out-ids="USP" ccpa-opt-out-geo="US" ccpa-opt-out-lspa="false" charset="UTF-8" src="https://cdn.cookielaw.org/opt-out/otCCPAiab.js" type="text/javascript"></script><script src="/assets/pizza-pie/javascripts/bundles/roma/rt-common.js?single"></script><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><meta http-equiv="x-ua-compatible" content="ie=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="shortcut icon" sizes="76x76" type="image/x-icon" href="https://www.rottentomatoes.com/assets/pizza-pie/images/favicon.ico" /><title>The Fantastic Four: First Steps | Rotten Tomatoes</title><meta name="description" content="Discover reviews, ratings, and trailers for The Fantastic Four: First Steps on Rotten Tomatoes. Stay updated with critic and audience scores today!" /><meta name="twitter:card" content="summary" /><meta name="twitter:image" content="https://resizing.flixster.com/GRRDF-MY6_iS5Em5vNBg-Jd-uL0=/206x305/v2/https://resizing.flixster.com/WEfe-vTCqjHioD77J7f-qeoZZdY=/ems.cHJkLWVtcy1hc3NldHMvbW92aWVzL2FjN2M2NzA0LWNiMTctNDhjMy05N2VlLTk3YWI3N2JhZDZmMS5qcGc=" /><meta name="twitter:title" content="The Fantastic Four: First Steps | Rotten Tomatoes" /><meta name="twitter:text:title" content="The Fantastic Four: First Steps | Rotten Tomatoes" /><meta name="twitter:description" content="Discover reviews, ratings, and trailers for The Fantastic Four: First Steps on Rotten Tomatoes. Stay updated with critic and audience scores today!" /><meta property="og:site_name" content="Rotten Tomatoes" /><meta property="og:title" content="The Fantastic Four: First Steps | Rotten Tomatoes" /><meta property="og:description" content="Discover reviews, ratings, and trailers for The Fantastic Four: First Steps on Rotten Tomatoes. Stay updated with critic and audience scores today!" /><meta property="og:type" content="video.movie" /><meta property="og:url" content="https://www.rottentomatoes.com/m/the_fantastic_four_first_steps" /><meta property="og:image" content="https://resizing.flixster.com/GRRDF-MY6_iS5Em5vNBg-Jd-uL0=/206x305/v2/https://resizing.flixster.com/WEfe-vTCqjHioD77J7f-qeoZZdY=/ems.cHJkLWVtcy1hc3NldHMvbW92aWVzL2FjN2M2NzA0LWNiMTctNDhjMy05N2VlLTk3YWI3N2JhZDZmMS5qcGc=" /><meta property="og:locale" content="en_US" /><link rel="canonical" href="https://www.rottentomatoes.com/m/the_fantastic_four_first_steps" /><script type="application/ld+json">{"@context":"http://schema.org","@type":"Movie","actor":[{"@type":"Person","name":"Pedro Pascal","sameAs":"https://www.rottentomatoes.com/celebrity/pedro_pascal","image":"https://resizing.flixster.com/gHGci208eTBBe6s555qqrVvMAlg=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/494807_v9_bd.jpg"},{"@type":"Person","name":"Vanessa Kirby","sameAs":"https://www.rottentomatoes.com/celebrity/vanessa_kirby","image":"https://resizing.flixster.com/hYfFokzVjtDj7QBvMrYIJ5uAhmY=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/631337_v9_bb.jpg"},{"@type":"Person","name":"Ebon Moss-Bachrach","sameAs":"https://www.rottentomatoes.com/celebrity/ebon_moss_bachrach","image":"https://resizing.flixster.com/cEb3kX_Yn_L4trv76D6rNON5nLA=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/252022_v9_bc.jpg"},{"@type":"Person","name":"Joseph Quinn","sameAs":"https://www.rottentomatoes.com/celebrity/joseph_quinn","image":"https://resizing.flixster.com/mwGK9WCbDyzD9FKvC81OyaWTfjc=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/1102755_v9_bb.jpg"},{"@type":"Person","name":"Ralph Ineson","sameAs":"https://www.rottentomatoes.com/celebrity/ralph-ineson","image":"https://resizing.flixster.com/-UyEiZ3UKHhGzdQU4wDV10Z6wO0=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/268419_v9_bc.jpg"}],"aggregateRating":{"@type":"AggregateRating","bestRating":"100","description":"The Tomatometer rating โ based on the published opinions of hundreds of film and television critics โ is a trusted measurement of movie and TV programming quality for millions of moviegoers. It represents the percentage of professional critic reviews that are positive for a given film or television show.","name":"Tomatometer","ratingCount":390,"ratingValue":"87","reviewCount":390,"worstRating":"0"},"contentRating":"PG-13","dateCreated":"2025-07-25","director":[{"@type":"Person","name":"Matt Shakman","sameAs":"https://www.rottentomatoes.com/celebrity/matt-shakman","image":"https://images.fandango.com/cms/assets/b0cefeb0-b6a8-11ed-81d8-51a487a38835--poster-default-thumbnail.jpg"}],"description":"Discover reviews, ratings, and trailers for The Fantastic Four: First Steps on Rotten Tomatoes. Stay updated with critic and audience scores today!","genre":["Action","Adventure","Sci-Fi","Fantasy"],"image":"https://resizing.flixster.com/WEfe-vTCqjHioD77J7f-qeoZZdY=/ems.cHJkLWVtcy1hc3NldHMvbW92aWVzL2FjN2M2NzA0LWNiMTctNDhjMy05N2VlLTk3YWI3N2JhZDZmMS5qcGc=","name":"The Fantastic Four: First Steps","url":"https://www.rottentomatoes.com/m/the_fantastic_four_first_steps","video":{"@type":"VideoObject","thumbnailUrl":"https://statcdn.fandango.com/MPX/image/NBCU_Fandango/663/931/thumb_4ca6d6c5-6a62-11f0-94b5-022bbbb30d69.jpg","name":"The Fantastic Four: First Steps: 4 Us All","duration":"0:59","sourceOrganization":"MPX","uploadDate":"2025-07-26T20:55:44","description":"","contentUrl":"https://www.rottentomatoes.com/m/the_fantastic_four_first_steps/videos/BBgYzBvAIQDN"}}</script></head><body class="body no-touch js-mptd-layout" data-AdsGlobalSkinTakeoverManager="body" data-SearchResultsNavManager="body"><div id="main" class="container rt-layout__body"><main id="main_container" class="container rt-layout__content"></main></div><script type="text/javascript"></script></body></html>
···1+<!DOCTYPE html><html lang="en" dir="ltr" xmlns="http://www.w3.org/1999/xhtml" prefix="fb: http://www.facebook.com/2008/fbml og: http://opengraphprotocol.org/schema/"><head prefix="og: http://ogp.me/ns# flixstertomatoes: http://ogp.me/ns/apps/flixstertomatoes#"><script charset="UTF-8" crossorigin="anonymous" data-domain-script="7e979733-6841-4fce-9182-515fac69187f" integrity="sha384-TKdmlzVmoD70HzftTw4WtOzIBL5mNx8mXSRzEvwrWjpIJ7FZ/EuX758yMDWXtRUN" src="https://cdn.cookielaw.org/consent/7e979733-6841-4fce-9182-515fac69187f/otSDKStub.js" type="text/javascript"></script><script type="text/javascript">function OptanonWrapper(){ if (OnetrustActiveGroups.includes('7')){ document.querySelector('search-results-nav-manager')?.setAlgoliaInsightUserToken?.()}} </script><script ccpa-opt-out-ids="USP" ccpa-opt-out-geo="US" ccpa-opt-out-lspa="false" charset="UTF-8" src="https://cdn.cookielaw.org/opt-out/otCCPAiab.js" type="text/javascript"></script><script src="/assets/pizza-pie/javascripts/bundles/roma/rt-common.js?single"></script><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><meta http-equiv="x-ua-compatible" content="ie=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="shortcut icon" sizes="76x76" type="image/x-icon" href="https://www.rottentomatoes.com/assets/pizza-pie/images/favicon.ico" /><title>Peacemaker (2022) | Rotten Tomatoes</title><meta name="description" content="Discover reviews, ratings, and trailers for Peacemaker (2022) on Rotten Tomatoes. Stay updated with critic and audience scores today!" /><meta name="twitter:card" content="summary" /><meta name="twitter:image" content="https://resizing.flixster.com/UHglta_RX5_h8fsHS2BljZkvfZk=/206x305/v2/https://resizing.flixster.com/mEY3rZ4CClCMjpOT2WJSWBvf_p8=/ems.cHJkLWVtcy1hc3NldHMvdHZzZXJpZXMvOTY5OTU0MzYtZmM5MC00MmI4LWI1YTEtYjQ4NDU2MWRmZWMzLmpwZw==" /><meta name="twitter:title" content="Peacemaker (2022) | Rotten Tomatoes" /><meta name="twitter:text:title" content="Peacemaker (2022) | Rotten Tomatoes" /><meta name="twitter:description" content="Discover reviews, ratings, and trailers for Peacemaker (2022) on Rotten Tomatoes. Stay updated with critic and audience scores today!" /><meta property="og:site_name" content="Rotten Tomatoes" /><meta property="og:title" content="Peacemaker (2022) | Rotten Tomatoes" /><meta property="og:description" content="Discover reviews, ratings, and trailers for Peacemaker (2022) on Rotten Tomatoes. Stay updated with critic and audience scores today!" /><meta property="og:type" content="video.tv_show" /><meta property="og:url" content="https://www.rottentomatoes.com/tv/peacemaker_2022" /><meta property="og:image" content="https://resizing.flixster.com/UHglta_RX5_h8fsHS2BljZkvfZk=/206x305/v2/https://resizing.flixster.com/mEY3rZ4CClCMjpOT2WJSWBvf_p8=/ems.cHJkLWVtcy1hc3NldHMvdHZzZXJpZXMvOTY5OTU0MzYtZmM5MC00MmI4LWI1YTEtYjQ4NDU2MWRmZWMzLmpwZw==" /><meta property="og:locale" content="en_US" /><link rel="canonical" href="https://www.rottentomatoes.com/tv/peacemaker_2022" /><script type="application/ld+json">{"@context":"http://schema.org","@type":"TVSeries","actor":[{"@type":"Person","name":"John Cena","sameAs":"https://www.rottentomatoes.com/celebrity/john_cena","image":"https://resizing.flixster.com/qFr2ZK1qYDkqSmM5eT3nz_n6E_g=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/487578_v9_ba.jpg"},{"@type":"Person","name":"Danielle Brooks","sameAs":"https://www.rottentomatoes.com/celebrity/danielle_brooks","image":"https://resizing.flixster.com/KhnY5vsfjM0vtw0cZL3aNxXbeUE=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/765589_v9_bc.jpg"},{"@type":"Person","name":"Freddie Stroma","sameAs":"https://www.rottentomatoes.com/celebrity/freddie_stroma","image":"https://resizing.flixster.com/Yk2eiDCtamfmNlK-xMa7nmEw_Po=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/GNLZZGG00283ZZD.jpg"},{"@type":"Person","name":"Chukwudi Iwuji","sameAs":"https://www.rottentomatoes.com/celebrity/chukwudi_iwuji","image":"https://resizing.flixster.com/uNAFlG9dNMjJwyMbPDiCsbjkX8I=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/565157_v9_ba.jpg"},{"@type":"Person","name":"Jennifer Holland","sameAs":"https://www.rottentomatoes.com/celebrity/jennifer_holland","image":"https://resizing.flixster.com/-xeYAf0O7fGIQHRx_YkL7vnaMMg=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/331642_v9_bb.jpg"},{"@type":"Person","name":"Steve Agee","sameAs":"https://www.rottentomatoes.com/celebrity/steve_agee","image":"https://resizing.flixster.com/YprPSg0SXNIqq-Wy4UEz4ovBnOw=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/223358_v9_bd.jpg"}],"aggregateRating":{"@type":"AggregateRating","bestRating":"100","description":"The Tomatometer rating โ based on the published opinions of hundreds of film and television critics โ is a trusted measurement of movie and TV programming quality for millions of moviegoers. It represents the percentage of professional critic reviews that are positive for a given film or television show.","name":"Tomatometer","ratingCount":150,"ratingValue":"96","reviewCount":150,"worstRating":"0"},"containsSeason":[{"@type":"TVSeason","name":"Season 2","url":"https://www.rottentomatoes.com/tv/peacemaker_2022/s02"},{"@type":"TVSeason","name":"Season 1","url":"https://www.rottentomatoes.com/tv/peacemaker_2022/s01"}],"contentRating":"TV-MA","dateCreated":"2022-01-13","description":"Discover reviews, ratings, and trailers for Peacemaker (2022) on Rotten Tomatoes. Stay updated with critic and audience scores today!","genre":["Comedy","Action"],"image":"https://resizing.flixster.com/mEY3rZ4CClCMjpOT2WJSWBvf_p8=/ems.cHJkLWVtcy1hc3NldHMvdHZzZXJpZXMvOTY5OTU0MzYtZmM5MC00MmI4LWI1YTEtYjQ4NDU2MWRmZWMzLmpwZw==","name":"Peacemaker (2022)","numberOfSeasons":2,"partOfSeries":{"@type":"TVSeries","name":"Peacemaker (2022)","startDate":"2022-01-13","url":"https://www.rottentomatoes.com/tv/peacemaker_2022"},"producer":[{"@type":"Person","name":"James Gunn","sameAs":"https://www.rottentomatoes.com/celebrity/james_gunn","image":"https://images.fandango.com/cms/assets/b0cefeb0-b6a8-11ed-81d8-51a487a38835--poster-default-thumbnail.jpg"},{"@type":"Person","name":"Peter Safran","sameAs":"https://www.rottentomatoes.com/celebrity/peter_safran","image":"https://images.fandango.com/cms/assets/b0cefeb0-b6a8-11ed-81d8-51a487a38835--poster-default-thumbnail.jpg"}],"url":"https://www.rottentomatoes.com/tv/peacemaker_2022","video":{"@type":"VideoObject","thumbnailUrl":"https://statcdn.fandango.com/MPX/image/NBCU_Fandango/166/403/thumb_47CFBBB8-95A3-4634-8B02-581F2C757D98.jpg","name":"Peacemaker: Season 2 Trailer - Weeks Ahead","duration":"1:39","sourceOrganization":"MPX","uploadDate":"2025-08-28T16:36:57","description":"","contentUrl":"https://www.rottentomatoes.com/tv/peacemaker_2022/videos/nTePljVEct61"}}</script></head><body class="body no-touch js-mptd-layout" data-AdsGlobalSkinTakeoverManager="body" data-SearchResultsNavManager="body"><div id="main" class="container rt-layout__body"><main id="main_container" class="container rt-layout__content"></main></div></body></html>
···1+<!DOCTYPE html><html lang="en" dir="ltr" xmlns="http://www.w3.org/1999/xhtml" prefix="fb: http://www.facebook.com/2008/fbml og: http://opengraphprotocol.org/schema/"><head prefix="og: http://ogp.me/ns# flixstertomatoes: http://ogp.me/ns/apps/flixstertomatoes#"><script charset="UTF-8" crossorigin="anonymous" data-domain-script="7e979733-6841-4fce-9182-515fac69187f" integrity="sha384-TKdmlzVmoD70HzftTw4WtOzIBL5mNx8mXSRzEvwrWjpIJ7FZ/EuX758yMDWXtRUN" src="https://cdn.cookielaw.org/consent/7e979733-6841-4fce-9182-515fac69187f/otSDKStub.js" type="text/javascript"></script><script type="text/javascript">function OptanonWrapper(){ if (OnetrustActiveGroups.includes('7')){ document.querySelector('search-results-nav-manager')?.setAlgoliaInsightUserToken?.()}} </script><script ccpa-opt-out-ids="USP" ccpa-opt-out-geo="US" ccpa-opt-out-lspa="false" charset="UTF-8" src="https://cdn.cookielaw.org/opt-out/otCCPAiab.js" type="text/javascript"></script><script src="/assets/pizza-pie/javascripts/bundles/roma/rt-common.js?single"></script><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><meta http-equiv="x-ua-compatible" content="ie=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="shortcut icon" sizes="76x76" type="image/x-icon" href="https://www.rottentomatoes.com/assets/pizza-pie/images/favicon.ico" /><title>Peacemaker: Season 2 | Rotten Tomatoes</title><meta name="description" content="Discover reviews, ratings, and trailers for Peacemaker: Season 2 on Rotten Tomatoes. Stay updated with critic and audience scores today!" /><meta name="twitter:card" content="summary" /><meta name="twitter:image" content="https://resizing.flixster.com/icqaMuFdXKqmN8qur-dfG4I-hWs=/206x305/v2/https://resizing.flixster.com/J-WXxwHSdv6w7VHxcCrPdebOvUA=/ems.cHJkLWVtcy1hc3NldHMvdHZzZWFzb24vNmE4MmUxOWItNGY5Yy00YzY0LTk5ODktZDY1MGEzZjdmZDFhLmpwZw==" /><meta name="twitter:title" content="Peacemaker: Season 2 | Rotten Tomatoes" /><meta name="twitter:text:title" content="Peacemaker: Season 2 | Rotten Tomatoes" /><meta name="twitter:description" content="Discover reviews, ratings, and trailers for Peacemaker: Season 2 on Rotten Tomatoes. Stay updated with critic and audience scores today!" /><meta property="og:site_name" content="Rotten Tomatoes" /><meta property="og:title" content="Peacemaker: Season 2 | Rotten Tomatoes" /><meta property="og:description" content="Discover reviews, ratings, and trailers for Peacemaker: Season 2 on Rotten Tomatoes. Stay updated with critic and audience scores today!" /><meta property="og:type" content="video.tv_show" /><meta property="og:url" content="https://www.rottentomatoes.com/tv/peacemaker_2022/s02" /><meta property="og:image" content="https://resizing.flixster.com/icqaMuFdXKqmN8qur-dfG4I-hWs=/206x305/v2/https://resizing.flixster.com/J-WXxwHSdv6w7VHxcCrPdebOvUA=/ems.cHJkLWVtcy1hc3NldHMvdHZzZWFzb24vNmE4MmUxOWItNGY5Yy00YzY0LTk5ODktZDY1MGEzZjdmZDFhLmpwZw==" /><meta property="og:locale" content="en_US" /><link rel="canonical" href="https://www.rottentomatoes.com/tv/peacemaker_2022/s02" /><script type="application/ld+json">{"@context":"http://schema.org","@type":"TVSeason","actor":[{"@type":"Person","name":"John Cena","sameAs":"https://www.rottentomatoes.com/celebrity/john_cena","image":"https://resizing.flixster.com/qFr2ZK1qYDkqSmM5eT3nz_n6E_g=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/487578_v9_ba.jpg"},{"@type":"Person","name":"Danielle Brooks","sameAs":"https://www.rottentomatoes.com/celebrity/danielle_brooks","image":"https://resizing.flixster.com/KhnY5vsfjM0vtw0cZL3aNxXbeUE=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/765589_v9_bc.jpg"},{"@type":"Person","name":"Freddie Stroma","sameAs":"https://www.rottentomatoes.com/celebrity/freddie_stroma","image":"https://resizing.flixster.com/Yk2eiDCtamfmNlK-xMa7nmEw_Po=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/GNLZZGG00283ZZD.jpg"},{"@type":"Person","name":"Chukwudi Iwuji","sameAs":"https://www.rottentomatoes.com/celebrity/chukwudi_iwuji","image":"https://resizing.flixster.com/uNAFlG9dNMjJwyMbPDiCsbjkX8I=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/565157_v9_ba.jpg"},{"@type":"Person","name":"Jennifer Holland","sameAs":"https://www.rottentomatoes.com/celebrity/jennifer_holland","image":"https://resizing.flixster.com/-xeYAf0O7fGIQHRx_YkL7vnaMMg=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/331642_v9_bb.jpg"},{"@type":"Person","name":"Steve Agee","sameAs":"https://www.rottentomatoes.com/celebrity/steve_agee","image":"https://resizing.flixster.com/YprPSg0SXNIqq-Wy4UEz4ovBnOw=/100x120/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/223358_v9_bd.jpg"}],"aggregateRating":{"@type":"AggregateRating","bestRating":"100","description":"The Tomatometer rating โ based on the published opinions of hundreds of film and television critics โ is a trusted measurement of movie and TV programming quality for millions of moviegoers. It represents the percentage of professional critic reviews that are positive for a given film or television show.","name":"Tomatometer","ratingCount":82,"ratingValue":"99","reviewCount":82,"worstRating":"0"},"dateCreated":"2025-08-21","description":"Discover reviews, ratings, and trailers for Peacemaker: Season 2 on Rotten Tomatoes. Stay updated with critic and audience scores today!","episode":[{"@type":"TVEpisode","episodeNumber":"1","url":"https://www.rottentomatoes.com/tv/peacemaker_2022/s02/e01","name":"The Ties That Grind","description":"While Peacemaker attempts to join the Justice Gang, Harcourt struggles to find work, and Economos takes on a challenging new assignment.","dateCreated":"2025-08-21"},{"@type":"TVEpisode","episodeNumber":"2","url":"https://www.rottentomatoes.com/tv/peacemaker_2022/s02/e02","name":"A Man Is Only as Good as His Bird","description":"As Economos clashes with his new handler, Peacemaker must deal with the consequences of his actions in the alternate dimension.","dateCreated":"2025-08-28"},{"@type":"TVEpisode","episodeNumber":"3","url":"https://www.rottentomatoes.com/tv/peacemaker_2022/s02/e03","name":"Another Rick Up My Sleeve","description":"A man fights for peace at any cost, no matter how many people he has to kill to get it.","dateCreated":"2025-09-04"},{"@type":"TVEpisode","episodeNumber":"4","url":"https://www.rottentomatoes.com/tv/peacemaker_2022/s02/e04","name":"Need I Say Door","description":"A man fights for peace at any cost, no matter how many people he has to kill to get it.","dateCreated":"2025-09-11"},{"@type":"TVEpisode","episodeNumber":"5","url":"https://www.rottentomatoes.com/tv/peacemaker_2022/s02/e05","name":"Back to the Suture","description":"A man fights for peace at any cost, no matter how many people he has to kill to get it.","dateCreated":"2025-09-18"},{"@type":"TVEpisode","episodeNumber":"6","url":"https://www.rottentomatoes.com/tv/peacemaker_2022/s02/e06","name":"Ignorance is Chris","description":"A man fights for peace at any cost, no matter how many people he has to kill to get it.","dateCreated":"2025-09-25"},{"@type":"TVEpisode","episodeNumber":"7","url":"https://www.rottentomatoes.com/tv/peacemaker_2022/s02/e07","description":"A man fights for peace at any cost, no matter how many people he has to kill to get it.","dateCreated":"2025-10-02"},{"@type":"TVEpisode","episodeNumber":"8","url":"https://www.rottentomatoes.com/tv/peacemaker_2022/s02/e08","description":"A man fights for peace at any cost, no matter how many people he has to kill to get it.","dateCreated":"2025-10-09"}],"genre":["Comedy","Action"],"image":"https://resizing.flixster.com/J-WXxwHSdv6w7VHxcCrPdebOvUA=/ems.cHJkLWVtcy1hc3NldHMvdHZzZWFzb24vNmE4MmUxOWItNGY5Yy00YzY0LTk5ODktZDY1MGEzZjdmZDFhLmpwZw==","name":"Season 2","partOfSeries":{"@type":"TVSeries","name":"Peacemaker","startDate":"2022-01-13","url":"https://www.rottentomatoes.com/tv/peacemaker_2022"},"producer":[{"@type":"Person","name":"James Gunn","sameAs":"https://www.rottentomatoes.com/celebrity/james_gunn","image":"https://images.fandango.com/cms/assets/b0cefeb0-b6a8-11ed-81d8-51a487a38835--poster-default-thumbnail.jpg"},{"@type":"Person","name":"Peter Safran","sameAs":"https://www.rottentomatoes.com/celebrity/peter_safran","image":"https://images.fandango.com/cms/assets/b0cefeb0-b6a8-11ed-81d8-51a487a38835--poster-default-thumbnail.jpg"}],"url":"https://www.rottentomatoes.com/tv/peacemaker_2022/s02","video":{"@type":"VideoObject","thumbnailUrl":"https://statcdn.fandango.com/MPX/image/NBCU_Fandango/166/403/thumb_47CFBBB8-95A3-4634-8B02-581F2C757D98.jpg","name":"Peacemaker: Season 2 Trailer - Weeks Ahead","duration":"1:39","sourceOrganization":"MPX","uploadDate":"2025-08-28T16:36:57","description":"","contentUrl":"https://www.rottentomatoes.com/tv/peacemaker_2022/s02/videos/nTePljVEct61"}}</script></head><body class="body no-touch js-mptd-layout" data-AdsGlobalSkinTakeoverManager="body" data-SearchResultsNavManager="body"><div id="main" class="container rt-layout__body"><main id="main_container" class="container rt-layout__content"></main><footer class="footer container" data-PagePicturesManager="footer"></footer></div></body></html>
+25-11
internal/services/test_utilities.go
···264265// MockATProtoService is a mock implementation of ATProtoService for testing
266type MockATProtoService struct {
267- AuthenticateFunc func(ctx context.Context, handle, password string) error
268- GetSessionFunc func() (*Session, error)
269- IsAuthenticatedVal bool
270- RestoreSessionFunc func(session *Session) error
271- PullDocumentsFunc func(ctx context.Context) ([]DocumentWithMeta, error)
272- PostDocumentFunc func(ctx context.Context, doc public.Document, isDraft bool) (*DocumentWithMeta, error)
273- PatchDocumentFunc func(ctx context.Context, rkey string, doc public.Document, isDraft bool) (*DocumentWithMeta, error)
274- DeleteDocumentFunc func(ctx context.Context, rkey string, isDraft bool) error
275- UploadBlobFunc func(ctx context.Context, data []byte, mimeType string) (public.Blob, error)
276- CloseFunc func() error
277- Session *Session // Exported for test access
0278}
279280// NewMockATProtoService creates a new mock AT Proto service
···395 MimeType: mimeType,
396 Size: len(data),
397 }, nil
0000000000000398}
399400// Close mocks cleanup
···264265// MockATProtoService is a mock implementation of ATProtoService for testing
266type MockATProtoService struct {
267+ AuthenticateFunc func(ctx context.Context, handle, password string) error
268+ GetSessionFunc func() (*Session, error)
269+ IsAuthenticatedVal bool
270+ RestoreSessionFunc func(session *Session) error
271+ PullDocumentsFunc func(ctx context.Context) ([]DocumentWithMeta, error)
272+ PostDocumentFunc func(ctx context.Context, doc public.Document, isDraft bool) (*DocumentWithMeta, error)
273+ PatchDocumentFunc func(ctx context.Context, rkey string, doc public.Document, isDraft bool) (*DocumentWithMeta, error)
274+ DeleteDocumentFunc func(ctx context.Context, rkey string, isDraft bool) error
275+ UploadBlobFunc func(ctx context.Context, data []byte, mimeType string) (public.Blob, error)
276+ GetDefaultPublicationFunc func(ctx context.Context) (string, error)
277+ CloseFunc func() error
278+ Session *Session // Exported for test access
279}
280281// NewMockATProtoService creates a new mock AT Proto service
···396 MimeType: mimeType,
397 Size: len(data),
398 }, nil
399+}
400+401+// GetDefaultPublication mocks getting the default publication
402+func (m *MockATProtoService) GetDefaultPublication(ctx context.Context) (string, error) {
403+ if m.GetDefaultPublicationFunc != nil {
404+ return m.GetDefaultPublicationFunc(ctx)
405+ }
406+407+ // Default returns a mock publication URI
408+ if !m.IsAuthenticatedVal {
409+ return "", errors.New("not authenticated")
410+ }
411+ return "at://did:plc:test123/pub.leaflet.publication/mock_pub_rkey", nil
412}
413414// Close mocks cleanup
···1+CREATE TABLE IF NOT EXISTS documents (
2+ id INTEGER PRIMARY KEY AUTOINCREMENT,
3+ title TEXT NOT NULL,
4+ body TEXT NOT NULL,
5+ created_at DATETIME NOT NULL,
6+ doc_kind INTEGER NOT NULL
7+);
8+9+CREATE INDEX IF NOT EXISTS idx_documents_doc_kind ON documents(doc_kind);
10+CREATE INDEX IF NOT EXISTS idx_documents_created_at ON documents(created_at);
···1+-- Task history table for undo functionality
2+CREATE TABLE IF NOT EXISTS task_history (
3+ id INTEGER PRIMARY KEY AUTOINCREMENT,
4+ task_id INTEGER NOT NULL,
5+ operation TEXT NOT NULL, -- 'update', 'delete'
6+ snapshot TEXT NOT NULL, -- JSON snapshot of task before operation
7+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
8+);
9+10+CREATE INDEX IF NOT EXISTS idx_task_history_task_id ON task_history(task_id);
11+CREATE INDEX IF NOT EXISTS idx_task_history_created_at ON task_history(created_at);
···5 "fmt"
6 "io"
7 "os"
8+ "unicode/utf8"
910 "github.com/charmbracelet/bubbles/help"
11 "github.com/charmbracelet/bubbles/key"
···162 status = "draft"
163 }
164165+ title := TableTitleStyle.Render(fmt.Sprintf("%s (%s)", m.note.Title, status))
166 content := m.viewport.View()
167+ help := MutedStyle.Render(m.help.View(m.keys))
168169 if !m.ready {
170 return "\n Initializing..."
···173 return lipgloss.JoinVertical(lipgloss.Left, title, "", content, "", help)
174}
17500000000000000000000000000000000000000000176// formatPublicationContent renders markdown with glamour for viewport display
177func formatPublicationContent(note *models.Note) (string, error) {
178 markdown := buildPublicationMarkdown(note)
179180 renderer, err := glamour.NewTermRenderer(
181 glamour.WithAutoStyle(),
182+ glamour.WithStandardStyle("tokyo-night"),
183+ glamour.WithPreservedNewLines(),
184+ glamour.WithWordWrap(79),
185 )
186 if err != nil {
187 return markdown, fmt.Errorf("failed to create renderer: %w", err)
···238 fmt.Fprint(pv.opts.Output, content)
239 return nil
240}
241+242+// ObfuscateMiddle returns a string where the middle portion is replaced by "..."
243+// TODO: move to package utils or shared
244+func ObfuscateMiddle(s string, left, right int) string {
245+ if s == "" {
246+ return s
247+ }
248+ if left < 0 {
249+ left = 0
250+ }
251+ if right < 0 {
252+ right = 0
253+ }
254+255+ n := utf8.RuneCountInString(s)
256+ if left+right >= n {
257+ return s
258+ }
259+260+ var (
261+ prefixRunes = make([]rune, 0, left)
262+ suffixRunes = make([]rune, 0, right)
263+ )
264+ i := 0
265+ for _, r := range s {
266+ if i >= left {
267+ break
268+ }
269+ prefixRunes = append(prefixRunes, r)
270+ i++
271+ }
272+273+ if right > 0 {
274+ allRunes := []rune(s)
275+ start := max(n-right, 0)
276+ suffixRunes = append(suffixRunes, allRunes[start:]...)
277+ }
278+279+ const repl = "..."
280+ if right == 0 {
281+ return string(prefixRunes) + repl
282+ }
283+ return string(prefixRunes) + repl + string(suffixRunes)
284+}
+11-11
internal/ui/publication_view_test.go
···138139 output := buf.String()
140141- if !strings.Contains(output, "Test Publication") {
142 t.Error("Note title not displayed")
143 }
144 if !strings.Contains(output, "published") {
···153 if !strings.Contains(output, "RKey:") {
154 t.Error("RKey not displayed")
155 }
156- if !strings.Contains(output, "test-rkey-123") {
157 t.Error("RKey value not displayed")
158 }
159 if !strings.Contains(output, "CID:") {
160 t.Error("CID not displayed")
161 }
162- if !strings.Contains(output, "test-cid-456") {
163 t.Error("CID value not displayed")
164 }
165- if !strings.Contains(output, "This is the content") {
166 t.Error("Note content not displayed")
167 }
168 })
···213214 output := buf.String()
215216- if !strings.Contains(output, "Minimal Note") {
217 t.Error("Note title not displayed")
218 }
219- if !strings.Contains(output, "Simple content") {
220 t.Error("Note content not displayed")
221 }
222 if !strings.Contains(output, "Modified:") {
···235 "**Status:** published",
236 "**Published:**",
237 "**Modified:**",
238- "**RKey:** `test-rkey-123`",
239- "**CID:** `test-cid-456`",
240 "---",
241 "This is the content",
242 }
···308 t.Fatalf("formatPublicationContent failed: %v", err)
309 }
310311- if !strings.Contains(content, "Test Publication") {
312 t.Error("Formatted content should include note title")
313 }
314 })
···634 t.Error("No output generated")
635 }
636637- if !strings.Contains(output, note.Title) {
638 t.Error("Note title not displayed")
639 }
640- if !strings.Contains(output, "This is the content") {
641 t.Error("Note content not displayed")
642 }
643 })
···138139 output := buf.String()
140141+ if !strings.Contains(output, "Test") || !strings.Contains(output, "Publication") {
142 t.Error("Note title not displayed")
143 }
144 if !strings.Contains(output, "published") {
···153 if !strings.Contains(output, "RKey:") {
154 t.Error("RKey not displayed")
155 }
156+ if !strings.Contains(output, "tes") || !strings.Contains(output, "123") {
157 t.Error("RKey value not displayed")
158 }
159 if !strings.Contains(output, "CID:") {
160 t.Error("CID not displayed")
161 }
162+ if !strings.Contains(output, "tes") || !strings.Contains(output, "456") {
163 t.Error("CID value not displayed")
164 }
165+ if !strings.Contains(output, "This") || !strings.Contains(output, "content") {
166 t.Error("Note content not displayed")
167 }
168 })
···213214 output := buf.String()
215216+ if !strings.Contains(output, "Minimal") || !strings.Contains(output, "Note") {
217 t.Error("Note title not displayed")
218 }
219+ if !strings.Contains(output, "Simple") || !strings.Contains(output, "content") {
220 t.Error("Note content not displayed")
221 }
222 if !strings.Contains(output, "Modified:") {
···235 "**Status:** published",
236 "**Published:**",
237 "**Modified:**",
238+ "**RKey:**",
239+ "**CID:**",
240 "---",
241 "This is the content",
242 }
···308 t.Fatalf("formatPublicationContent failed: %v", err)
309 }
310311+ if !strings.Contains(content, "Test") || !strings.Contains(content, "Publication") {
312 t.Error("Formatted content should include note title")
313 }
314 })
···634 t.Error("No output generated")
635 }
636637+ if !strings.Contains(output, "Test") || !strings.Contains(output, "Publication") {
638 t.Error("Note title not displayed")
639 }
640+ if !strings.Contains(output, "This") || !strings.Contains(output, "content") {
641 t.Error("Note content not displayed")
642 }
643 })
+4-4
internal/ui/task_edit.go
···350351 var content strings.Builder
352353- title := TitleColorStyle.Render("Edit Task")
354 content.WriteString(title + "\n\n")
355356 for i, field := range m.fields {
357 fieldStyle := lipgloss.NewStyle()
358 if i == m.currentField && m.mode == fieldNavigation {
359- fieldStyle = SelectedColorStyle
360 }
361362 switch field {
···427 for i, status := range statusOptions {
428 style := lipgloss.NewStyle()
429 if i == m.statusIndex {
430- style = SelectedColorStyle
431 }
432433 line := fmt.Sprintf("%s %s", FormatStatusIndicator(status), status)
···460 for i, priority := range options {
461 style := lipgloss.NewStyle()
462 if i == m.priorityIndex {
463- style = SelectedColorStyle
464 }
465466 var line string
···350351 var content strings.Builder
352353+ title := TableTitleStyle.Render("Edit Task")
354 content.WriteString(title + "\n\n")
355356 for i, field := range m.fields {
357 fieldStyle := lipgloss.NewStyle()
358 if i == m.currentField && m.mode == fieldNavigation {
359+ fieldStyle = TableSelectedStyle
360 }
361362 switch field {
···427 for i, status := range statusOptions {
428 style := lipgloss.NewStyle()
429 if i == m.statusIndex {
430+ style = TableSelectedStyle
431 }
432433 line := fmt.Sprintf("%s %s", FormatStatusIndicator(status), status)
···460 for i, priority := range options {
461 style := lipgloss.NewStyle()
462 if i == m.priorityIndex {
463+ style = TableSelectedStyle
464 }
465466 var line string
+14-26
internal/ui/task_information.go
···44 PriorityNonePattern = "โโโ"
45)
46047var (
48- // Gray
49- TodoStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
50- // Blue
51- InProgressStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("12"))
52- // Red
53- BlockedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("9"))
54- // Green
55- DoneStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("10"))
56- // Dark Gray
57- AbandonedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
58- // Light Gray
59- PendingStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("7"))
60- // Green
61- CompletedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("10"))
62- // Dark Red
63- DeletedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("1"))
64- // Bright Red - highest urgency
65- PriorityHighStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("196"))
66- // Yellow - medium urgency
67- PriorityMediumStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("11"))
68- // Cyan - low urgency
69- PriorityLowStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("14"))
70- // Gray - no priority
71- PriorityNoneStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
72- // For legacy A-Z and numeric priorities
73- PriorityLegacyStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("13")) // Magenta
74)
7576// GetStatusSymbol returns the unicode symbol for a given status
···44 PriorityNonePattern = "โโโ"
45)
4647+// Type aliases for status and priority styles (now defined in palette.go)
48var (
49+ TodoStyle = StatusTodo
50+ InProgressStyle = StatusInProgress
51+ BlockedStyle = StatusBlocked
52+ DoneStyle = StatusDone
53+ AbandonedStyle = StatusAbandoned
54+ PendingStyle = StatusPending
55+ CompletedStyle = StatusCompleted
56+ DeletedStyle = StatusDeleted
57+ PriorityHighStyle = PriorityHigh
58+ PriorityMediumStyle = PriorityMedium
59+ PriorityLowStyle = PriorityLow
60+ PriorityNoneStyle = PriorityNone
61+ PriorityLegacyStyle = PriorityLegacy
000000000000062)
6364// GetStatusSymbol returns the unicode symbol for a given status
···1+//go:build !prod
2+3+package tools
4+5+import (
6+ "context"
7+8+ "github.com/spf13/cobra"
9+)
10+11+// NewLexiconsCommand creates a command for fetching Leaflet lexicons
12+func NewLexiconsCommand() *cobra.Command {
13+ var sha string
14+ var output string
15+16+ cmd := &cobra.Command{
17+ Use: "lexicons",
18+ Short: "Fetch Leaflet lexicons from GitHub",
19+ Long: `Fetches Leaflet lexicons from the hyperlink-academy/leaflet repository.
20+21+This is a convenience wrapper around gh-repo with pre-configured defaults
22+for the Leaflet lexicon repository.`,
23+ Example: ` # Fetch latest lexicons
24+ noteleaf tools fetch lexicons
25+26+ # Fetch from a specific commit
27+ noteleaf tools fetch lexicons --sha abc123def
28+29+ # Fetch to a custom directory
30+ noteleaf tools fetch lexicons --output ./tmp/lexicons`,
31+ RunE: func(cmd *cobra.Command, args []string) error {
32+ config := ArchiveConfig{
33+ Repo: "hyperlink-academy/leaflet",
34+ Path: "lexicons/pub/leaflet/",
35+ Output: output,
36+ SHA: sha,
37+ FormatJSON: true,
38+ }
39+40+ ctx := cmd.Context()
41+ if ctx == nil {
42+ ctx = context.Background()
43+ }
44+45+ return fetchAndExtractArchive(ctx, config, cmd.OutOrStdout())
46+ },
47+ }
48+ cmd.Flags().StringVar(&sha, "sha", "", "Specific commit SHA (default: latest)")
49+ cmd.Flags().StringVar(&output, "output", "lexdocs/leaflet/", "Output directory for lexicons")
50+ return cmd
51+}
+19
tools/registry.go
···0000000000000000000
···1+//go:build !prod
2+3+package tools
4+5+import "github.com/spf13/cobra"
6+7+// NewToolsCommand creates a parent command for all development tools
8+func NewToolsCommand(root *cobra.Command) *cobra.Command {
9+ cmd := &cobra.Command{
10+ Use: "tools",
11+ Short: "Development and maintenance tools",
12+ Long: `Development tools for documentation generation, data synchronization,
13+and maintenance tasks. These commands are only available in dev builds.`,
14+ }
15+ cmd.AddCommand(NewDocGenCommand(root))
16+ cmd.AddCommand(NewFetchCommand())
17+18+ return cmd
19+}
···1+# Noteleaf Documentation TODO
2+3+This document tracks documentation coverage for the Noteleaf website. The goal is to provide comprehensive documentation for both the productivity system features and the leaflet.pub publishing capabilities.
4+5+## Integration and Workflows
6+7+- [x] External Integrations
8+ - [x] Open Library API
9+ - [x] Leaflet.pub API
10+ - [x] ATProto authentication
11+- [ ] Workflows and Examples
12+ - [ ] Daily task review workflow
13+ - [ ] Note-taking for research
14+ - [ ] Reading list management
15+ - [ ] Publishing a blog post to leaflet.pub
16+ - [ ] Linking tasks, notes, and media
17+- [x] Import/Export
18+ - [x] Exporting data
19+ - [x] Backup and restore
20+ - [x] Migration from other tools
21+22+## Development
23+24+- [x] Building Noteleaf
25+ - [x] Development vs production builds
26+ - [x] Build tags
27+ - [x] Task automation (Taskfile)
28+- [x] Testing
29+ - [x] Running tests
30+ - [x] Coverage reports
31+ - [x] Test patterns and scaffolding
32+- [ ] Contributing
33+ - [ ] Code organization
34+ - [ ] Adding new commands
35+ - [ ] UI components
36+ - [ ] Testing requirements
37+- [ ] Architecture Deep Dive
38+ - [ ] Repository pattern
39+ - [ ] Handler architecture
40+ - [ ] Service layer
41+ - [ ] Data models
42+ - [ ] UI component system
43+44+## Examples and Tutorials
45+46+- [ ] Getting Started Tutorial
47+ - [ ] First 15 minutes
48+ - [ ] Essential workflows
49+- [ ] Task Management Tutorials
50+ - [ ] GTD workflow
51+ - [ ] Time blocking
52+ - [ ] Project planning
53+- [ ] Note-Taking Tutorials
54+ - [ ] Zettelkasten method
55+ - [ ] Research notes
56+ - [ ] Meeting notes
57+58+## Appendices
59+60+- [ ] Glossary
61+- [ ] Keyboard Shortcuts Reference
62+- [ ] Configuration Options Reference
63+- [ ] API Reference (leaflet schema)
64+- [ ] Color Palette Reference
65+- [ ] Migration Guides
66+ - [ ] From TaskWarrior
67+ - [ ] From todo.txt
68+ - [ ] From other note-taking apps
+101-8
website/docs/Configuration.md
···000000001# Configuration
23Noteleaf stores its configuration in a TOML file. The configuration file location depends on your operating system and can be overridden with environment variables.
···31```sh
32export NOTELEAF_CONFIG=/path/to/custom/config.toml
33```
000000000003435## Configuration Options
36···318**Type:** String (ISO8601)
319**Default:** None
32000000000000000000000000000321## Managing Configuration
322323### View Current Configuration
···389390## Environment Variables
391392-Noteleaf respects the following environment variables:
393394-- `NOTELEAF_CONFIG` - Custom path to configuration file
395-- `NOTELEAF_DATA_DIR` - Custom path to data directory
396-- `EDITOR` - Default text editor (fallback if `editor` config not set)
00397398-Example:
399400```sh
401-export NOTELEAF_CONFIG=~/.config/noteleaf/config.toml
402-export NOTELEAF_DATA_DIR=~/Documents/noteleaf-data
403-export EDITOR=nvim
404```
0000000000000000000000000000000000000000000000
···1+---
2+id: configuration
3+title: Configuration
4+sidebar_label: Configuration
5+sidebar_position: 6
6+description: Reference for configuration locations, defaults, and options.
7+---
8+9# Configuration
1011Noteleaf stores its configuration in a TOML file. The configuration file location depends on your operating system and can be overridden with environment variables.
···39```sh
40export NOTELEAF_CONFIG=/path/to/custom/config.toml
41```
42+43+### File Structure
44+45+Configuration is stored as [TOML](https://toml.io). Each key maps 1:1 with the fields shown by `noteleaf config show`. A minimal file looks like:
46+47+```toml
48+date_format = "2006-01-02"
49+color_scheme = "default"
50+```
51+52+There is no required orderingโthe parser loads the file, applies defaults for missing keys, and writes a normalized version whenever you run `noteleaf config set ...`. This means you can edit the file manually or stick entirely to CLI helpers.
5354## Configuration Options
55···337**Type:** String (ISO8601)
338**Default:** None
339340+## Editor Integration
341+342+The `editor` key wires Noteleaf into your preferred text editor. Resolution order:
343+344+1. `editor` inside `.noteleaf.conf.toml`
345+2. `$EDITOR` environment variable
346+3. System default (usually `vi` on Unix)
347+348+Where it is used:
349+350+- `noteleaf note edit <id>` always opens the configured editor.
351+- `noteleaf note create -e` or `--editor` lets you capture inline text and immediately refine it in the editor.
352+- Interactive creation (`noteleaf note create -i`) respects the same setting when you choose to open the note.
353+354+Example configuration:
355+356+```toml
357+editor = "nvim"
358+```
359+360+If you frequently switch editors, leave the config empty and export `$EDITOR` before launching Noteleaf:
361+362+```sh
363+EDITOR="zed" noteleaf note edit 5
364+```
365+366## Managing Configuration
367368### View Current Configuration
···434435## Environment Variables
436437+Environment overrides are resolved before configuration values. Set them when you need temporary behavior (CI jobs, alternate workspaces, etc.).
438439+| Variable | Purpose | Notes |
440+|----------|---------|-------|
441+| `NOTELEAF_CONFIG` | Absolute path to the TOML file | Overrides platform defaults. Parent directories are created automatically. |
442+| `NOTELEAF_DATA_DIR` | Root directory for the SQLite DB, notes, articles, and attachments | Useful for portable installs (USB drive, synced folder). |
443+| `EDITOR` | Fallback editor when the `editor` config key is empty | Checked by all note-related commands. |
444445+Usage example:
446447```sh
448+export NOTELEAF_CONFIG=~/.config/noteleaf/work.conf.toml
449+export NOTELEAF_DATA_DIR=~/Sync/workspace-data
450+export EDITOR=helix
451```
452+453+Because `NOTELEAF_DATA_DIR` cascades to the article and note directories, a single export is all you need to relocate the entire knowledge base.
454+455+## Customization
456+457+### Themes and Colors
458+459+The `color_scheme` option controls how Fang (the underlying Cobra replacement) styles command help and certain UI components. Right now the only valid value is `"default"`, which maps to Noteleafโs Iceberg-inspired palette. Future releases will add explicit `light`/`dark` options; until then customization requires overriding your terminal theme or building Noteleaf from source with changes in `internal/ui/palette.go`.
460+461+```toml
462+color_scheme = "default" # leave blank to adopt upcoming auto-mode
463+```
464+465+### Keyboard Shortcuts
466+467+All interactive views share the same key map:
468+469+| Keys | Action |
470+|------|--------|
471+| `โ / k`, `โ / j` | Move selection |
472+| `enter` | Open the selected row |
473+| `v` | View details in a side panel (where supported) |
474+| `/` | Search/filter (live) |
475+| `r` | Reload data |
476+| `?` | Show full help, including custom actions for the current view |
477+| `q`, `ctrl+c` | Quit the view |
478+| `esc`, `backspace` | Exit search/help/detail panels |
479+| `1-9` | Jump directly to the corresponding row index |
480+481+Press `?` inside any list/table to confirm the bindingsโthis uses Bubble Teaโs built-in help component so it always reflects the current screen.
482+483+### Output Formats
484+485+- `export_format` sets the default for future export commands (currently `json`).
486+- Task commands support JSON today: `noteleaf todo view 12 --json` or `noteleaf todo list --static --json`.
487+- The `--format` flag on `noteleaf todo view` switches between `detailed` and `brief` layouts, which is handy when scripting.
488+489+Examples:
490+491+```sh
492+noteleaf todo view 12 --format brief --json | jq '.status'
493+noteleaf todo list --static --json > tasks.json
494+noteleaf config set export_format "csv" # prepare for upcoming exporters
495+```
496+497+Even when there is no dedicated exporter yet, the SQLite database lives in the open, so you can always run your own `SELECT ...` queries or use `sqlite-utils` to produce CSV/JSON.
+8
website/docs/Quickstart.md
···000000001# Quickstart Guide
23This guide will walk you through installing Noteleaf and getting productive with tasks, notes, and media tracking in under 15 minutes.
···1+---
2+id: quickstart
3+title: Quickstart Guide
4+sidebar_label: Quickstart
5+sidebar_position: 1
6+description: Install Noteleaf and learn the essentials in minutes.
7+---
8+9# Quickstart Guide
1011This guide will walk you through installing Noteleaf and getting productive with tasks, notes, and media tracking in under 15 minutes.
+9
website/docs/articles/_category_.json
···000000000
···1+{
2+ "label": "Articles",
3+ "position": 6,
4+ "link": {
5+ "type": "generated-index",
6+ "title": "Article Archive",
7+ "description": "Save, read, and organize web articles locally."
8+ }
9+}
···1+---
2+title: Article Management
3+sidebar_label: Management
4+description: Save URLs, inspect metadata, and read articles without leaving the CLI.
5+sidebar_position: 2
6+---
7+8+# Article Management
9+10+## Save Articles from URLs
11+12+```sh
13+noteleaf article add https://example.com/long-form-piece
14+```
15+16+What happens:
17+18+1. The CLI checks the database to ensure the URL was not imported already.
19+2. It fetches the page with a reader-friendly User-Agent (`curl/8.4.0`) and English `Accept-Language` headers to avoid blocked responses.
20+3. Parsed content is written to Markdown and HTML files under `articles_dir`.
21+4. A database record is inserted with all metadata and file paths.
22+23+If parsing fails (unsupported domain, network issue, etc.) nothing is written to disk, so partial entries never appear in your archive.
24+25+## Parsing and Extraction
26+27+The parser uses a two-layer strategy:
28+29+1. **Domain-specific rules** check the XPath selectors defined in `internal/articles/rules`. These rules strip unwanted elements (cookie banners, nav bars), capture the main body, and record author/date fields accurately.
30+2. **Heuristic fallback** scores every DOM node, penalizes high link-density sections, and picks the most โarticle-likeโ block. It also pulls metadata from JSON-LD `Article` objects when available.
31+32+During saving, the Markdown file gets a generated header:
33+34+```markdown
35+# Article Title
36+37+**Author:** Jane Smith
38+39+**Date:** 2024-01-02
40+41+**Source:** https://example.com/long-form-piece
42+43+**Saved:** 2024-02-05 10:45:12
44+```
45+46+Everything after the `---` separator is the cleaned article content.
47+48+## Reading in the Terminal
49+50+There are two ways to inspect what you saved:
51+52+- `noteleaf article view <id>` shows metadata, verifies whether the files still exist, and prints the first ~20 lines as a preview.
53+- `noteleaf article read <id>` renders the full Markdown using [Charmโs Glamour](https://github.com/charmbracelet/glamour), giving you syntax highlighting, proper headings, and wrapped paragraphs directly in the terminal.
54+55+If you prefer your editor, open the Markdown path printed by `view`. Both Markdown and HTML copies belong to you, so feel free to annotate or reformat them.
56+57+## Article Metadata Reference
58+59+Use `noteleaf article list` to see titles and authors:
60+61+```sh
62+noteleaf article list # newest first
63+noteleaf article list "sqlite" # full-text filter on titles
64+noteleaf article list --author "Kim" # author filter
65+noteleaf article list -l 5 # top 5 results
66+```
67+68+Each entry includes the created timestamp. The `view` command provides the raw paths so you can script around them, for example:
69+70+```sh
71+md=$(noteleaf article view 12 | rg 'Markdown:' | awk '{print $3}')
72+$EDITOR "$md"
73+```
74+75+All metadata lives in the SQLite `articles` table, making it easy to run your own reports with `sqlite3` if needed.
···1+---
2+title: Article Organization
3+sidebar_label: Organization
4+description: Filter your archive, add lightweight tags, and keep backups tidy.
5+sidebar_position: 3
6+---
7+8+# Article Organization
9+10+## Filter by Author or Title
11+12+`noteleaf article list` accepts both a free-form query (matches the title) and dedicated flags:
13+14+```sh
15+# Anything with "SQLite" in the title
16+noteleaf article list SQLite
17+18+# Limit to a single author
19+noteleaf article list --author "Ada Palmer"
20+21+# Cap the output for quick reviews
22+noteleaf article list --author "Ada Palmer" --limit 3
23+```
24+25+Because the database stores created timestamps, results come back with the newest article first, making it easy to run weekly reviews.
26+27+## Tagging Articles
28+29+There is no first-class tagging UI yet, but Markdown files are yours to edit. Common patterns:
30+31+```markdown
32+---
33+tags: [distributed-systems, reference]
34+project: moonshot
35+---
36+```
37+38+Drop that block right after the generated metadata and tools like `rg` or `ripgrep --json` can surface tagged snippets instantly. You can also maintain a separate note that lists article IDs per topic if you prefer not to edit the captured files.
39+40+## Read vs Unread
41+42+Opening an article in the terminal does not flip a status flag. Use one of these lightweight conventions instead:
43+44+- Prefix the Markdown filename with `read-` once you are done.
45+- Keep a running checklist note (e.g., โArticles Inboxโ) that references IDs and mark them off as you read them.
46+- Create a task linked to the article ID (`todo add "Summarize article #14"`), then close the task when you finish.
47+48+All three approaches work today and will map cleanly to future built-in read/unread tracking.
49+50+## Archiving and Backups
51+52+The archive lives under `articles_dir`. By default that is `<data_dir>/articles`, where `<data_dir>` depends on your OS:
53+54+| Platform | Default |
55+|----------|---------|
56+| Linux | `~/.local/share/noteleaf/articles` |
57+| macOS | `~/Library/Application Support/noteleaf/articles` |
58+| Windows | `%LOCALAPPDATA%\noteleaf\articles` |
59+60+You can override the location via the `articles_dir` setting in `~/.config/noteleaf/.noteleaf.conf.toml` (or by pointing `NOTELEAF_DATA_DIR` to a different root before launching the CLI).
61+62+Because every import produces Markdown + HTML, the directory is perfect for version control:
63+64+```sh
65+cd ~/.local/share/noteleaf/articles
66+git init
67+git add .
68+git commit -m "Initial snapshot of article archive"
69+```
70+71+Pair that with your cloud backup tool of choice and you have a durable, fully-offline knowledge base that still integrates seamlessly with Noteleafโs search commands.
···1+---
2+title: Article Overview
3+sidebar_label: Overview
4+description: How the article parser saves content for offline reading.
5+sidebar_position: 1
6+---
7+8+# Article Overview
9+10+The `noteleaf article` command turns any supported URL into two files on disk:
11+12+- A clean Markdown document (great for terminal reading).
13+- A rendered HTML copy (handy for rich export or sharing).
14+15+Both files live inside your configured `articles_dir` (defaults to `<data_dir>/articles`). The SQLite database stores the metadata and file paths so you can query, list, and delete articles without worrying about directories.
16+17+## How Parsing Works
18+19+1. **Domain rules first**: Each supported site has a small XPath rule file (`internal/articles/rules/*.txt`).
20+2. **Heuristic fallback**: When no rule exists, the parser falls back to the readability-style heuristic extractor that scores DOM nodes, removes nav bars, and preserves headings/links.
21+3. **Metadata extraction**: The parser also looks for OpenGraph/JSON-LD tags to capture author names and publish dates.
22+23+You can see the currently loaded rule set by running:
24+25+```sh
26+noteleaf article --help
27+```
28+29+The help output prints the supported domains and the storage directory that is currently in use.
30+31+## Saved Metadata
32+33+Every article record contains:
34+35+- URL and canonical title
36+- Author (if present in metadata)
37+- Publication date (stored as plain text, e.g., `2024-01-02`)
38+- Markdown file path
39+- HTML file path
40+- Created/modified timestamps
41+42+These fields make it easy to build reading logs, cite sources in notes, or reference articles from tasks.
43+44+## Commands at a Glance
45+46+| Command | Purpose |
47+|----------------------------------|---------|
48+| `noteleaf article add <url>` | Parse, save, and index a URL |
49+| `noteleaf article list [query]` | Show saved items; filter with `--author` or `--limit` |
50+| `noteleaf article view <id>` | Inspect metadata + a short preview |
51+| `noteleaf article read <id>` | Render the Markdown nicely in your terminal |
52+| `noteleaf article remove <id>` | Delete the DB entry and the files |
53+54+The CLI automatically prevents duplicate imports by checking the URL before parsing.
···1+---
2+title: Architecture Overview
3+sidebar_label: Architecture
4+description: Application structure, storage, and UI layers.
5+sidebar_position: 3
6+---
7+8+# Architecture Overview
9+10+## Architecture Overview
11+12+### Application Structure
13+14+Noteleaf follows a clean architecture pattern with clear separation of concerns:
15+16+```
17+cmd/ - CLI commands and user interface
18+internal/
19+ handlers/ - Business logic and orchestration
20+ repo/ - Database access layer
21+ ui/ - Terminal UI components (Bubble Tea)
22+ models/ - Domain models
23+ public/ - Leaflet.pub integration
24+```
25+26+Each layer has defined responsibilities with minimal coupling between them.
27+28+### Storage and Database
29+30+**SQLite Database**: All structured data (tasks, metadata, relationships) lives in a single SQLite file at `~/.local/share/noteleaf/noteleaf.db` (Linux) or `~/Library/Application Support/noteleaf/noteleaf.db` (macOS).
31+32+**Markdown Files**: Note content is stored as individual markdown files on disk. The database tracks metadata while keeping your notes in a portable, human-readable format.
33+34+**Database Schema**: Tables for tasks, notes, articles, books, movies, TV shows, publications, and linking tables for tags and relationships. Migrations handle schema evolution.
35+36+### TUI Framework (Bubble Tea)
37+38+The interactive interface is built with [Bubble Tea](https://github.com/charmbracelet/bubbletea), a Go framework for terminal user interfaces based on The Elm Architecture:
39+40+- **Model**: Application state (current view, selected item, filters)
41+- **Update**: State transitions based on user input
42+- **View**: Render the current state to the terminal
43+44+This architecture makes the UI predictable, testable, and composable. Each screen is an independent component that can be developed and tested in isolation.
···1+---
2+title: CLI Reference
3+sidebar_label: CLI Reference
4+description: Overview of Noteleafโs command hierarchy, flags, and developer utilities.
5+sidebar_position: 7
6+---
7+8+# CLI Reference
9+10+This reference is a map of the top-level commands exposed by `noteleaf`. For flag-by-flag detail run `noteleaf <command> --help`โthe human-friendly Fang help screens are always the source of truth.
11+12+## Command Structure
13+14+### Global flags
15+16+| Flag | Description |
17+| ------------------------- | ----------------------------------------------------------------- |
18+| `--help`, `-h` | Show help for any command or subcommand |
19+| `--version` | Print the Noteleaf build string (includes git SHA when available) |
20+| `--color <auto\|on\|off>` | Optional Fang flag to control ANSI colors |
21+22+Environment variables such as `NOTELEAF_CONFIG`, `NOTELEAF_DATA_DIR`, and `EDITOR` affect how commands behave but are not flags.
23+24+### Command hierarchy
25+26+- Root command: `noteleaf`
27+- Task commands live under the `todo` alias (e.g., `noteleaf todo add`).
28+- Media commands are grouped and require a subtype: `noteleaf media book`, `noteleaf media movie`, `noteleaf media tv`.
29+- Publishing flows live under `noteleaf pub`.
30+- Management helpers (`config`, `setup`, `status`, `reset`) sit at the top level.
31+32+### Help system
33+34+Every command inherits Fangโs colorized help plus Noteleaf-specific additions:
35+36+- `noteleaf article --help` prints the supported parser domains and storage directory by calling into the handler.
37+- Interactive commands show the keyboard shortcuts inside their help output.
38+- You can always drill down: `noteleaf todo add --help`, `noteleaf media book list --help`, etc.
39+40+## Commands by Category
41+42+### `todo` / `task`
43+44+Add, list, view, update, complete, and annotate tasks. Supports priorities, contexts, tags, dependencies, recurrence, and JSON output for scripting. Related metadata commands (`projects`, `tags`, `contexts`) summarize usage counts.
45+46+### `note`
47+48+Create Markdown notes (inline, from files, or via the interactive editor), list them with the TUI, search, view, edit in `$EDITOR`, archive/unarchive, and delete. Notes share IDs with leaflet publishing so they can be synced later.
49+50+### `media`
51+52+Umbrella group for personal queues:
53+54+- `noteleaf media book` โ Search Open Library, add books, update status (`queued`/`reading`/`finished`), edit progress percentages, and remove titles.
55+- `noteleaf media movie` โ Search Rotten Tomatoes, queue movies, mark them watched, or remove them.
56+- `noteleaf media tv` โ Same as movies but with watching/watched states and optional season/episode tracking.
57+58+Each subtype has its own `list`, status-changing verbs, and removal commands. Use `-i/--interactive` on `add` to open the TUI selector (books today, other media soon).
59+60+### `article`
61+62+Parse and save web articles with `add <url>`, inspect them via `list`, `view`, or `read`, and delete them with `remove`. All commands operate on the local Markdown/HTML archive referenced in the handler output.
63+64+### `pub`
65+66+Leaflet.pub commands for AT Protocol publishing:
67+68+- `pull` / `push` to sync notes with the remote publication.
69+- `status`, `list`, and `diff` to inspect what is linked.
70+- Support for working drafts, batch pushes, and file-based imports (`--file`) when publishing is combined with local markdown.
71+72+### `config`
73+74+Inspect and mutate `~/.noteleaf.conf.toml`:
75+76+- `noteleaf config show` (or `get <key>`) prints values.
77+- `noteleaf config set <key> <value>` writes back to disk.
78+- `noteleaf config path` reveals the file location.
79+- `noteleaf config reset` rewinds to defaults.
80+81+### `setup`
82+83+`noteleaf setup` initializes the database, config file, and data directories if they do not exist. `noteleaf setup seed` can load sample data (pass `--force` to wipe existing rows first).
84+85+### `status`
86+87+`noteleaf status` prints absolute paths for the config file, data directory, database, and media folders along with environment overridesโhandy for debugging or verifying a portable install.
88+89+## Development Tools
90+91+`noteleaf tools ...` is available in development builds (`task build:dev`, `go run ./cmd`). It bundles maintenance utilities:
92+93+### Documentation generation
94+95+```
96+noteleaf tools docgen --format docusaurus --out website/docs/manual
97+noteleaf tools docgen --format man --out docs/manual
98+```
99+100+Generates reference docs straight from the command definitions, keeping terminal help and published docs in sync.
101+102+### Lexicon fetching
103+104+```
105+noteleaf tools fetch lexicons
106+noteleaf tools fetch lexicons --sha <commit>
107+```
108+109+Pulls the latest `leaflet.pub` lexicons from GitHub so the AT Protocol client stays current. You can point it at a specific commit for reproducible builds.
110+111+### Database utilities
112+113+```
114+noteleaf tools fetch gh-repo --repo owner/repo --path schemas --output tmp/schemas
115+```
116+117+Provides generic fetchers plus helpers used by CI and local testing to refresh schema files, warm caches, or introspect the SQLite database.
118+119+These tools intentionally live behind the dev build tag so production binaries stay lean. Use them when contributing documentation or publishing features.
+19
website/docs/concepts/data-model.md
···0000000000000000000
···1+---
2+title: Unified Data Model
3+sidebar_label: Data Model
4+description: How tasks, notes, and media connect inside Noteleaf.
5+sidebar_position: 2
6+---
7+8+# Unified Data Model
9+10+## Philosophy
11+12+Noteleaf treats all personal information as interconnected. Tasks, notes, articles, books, movies, and TV shows exist in a single database where relationships between items are first-class citizens:
13+14+- Link notes to tasks to document your work
15+- Tag books and articles with the same taxonomy as your tasks
16+- Track reading lists alongside project work
17+- Connect media items to research notes
18+19+This unified approach mirrors how knowledge work actually happensโprojects involve research, reading generates ideas, and ideas spawn tasks.
+33
website/docs/concepts/design-system.md
···000000000000000000000000000000000
···1+---
2+title: Design System
3+sidebar_label: Design System
4+description: Color palette guidance that keeps the terminal UI cohesive.
5+sidebar_position: 4
6+---
7+8+# Design System
9+10+## Color Palette and Design System
11+12+Noteleaf uses a carefully chosen color palette defined in `internal/ui/palette.go`:
13+14+**Brand Colors**:
15+16+- **Malibu** (`#00A4FF`): Primary blue for accents and highlights
17+- **Julep** (`#00FFB2`): Success green for completed items
18+- **Sriracha** (`#EB4268`): Warning red for urgent/error states
19+- **Tang** (`#FF985A`): Orange for warnings and attention
20+- **Lichen** (`#5CDFEA`): Teal for informational elements
21+22+**Neutral Palette** (Dark to Light):
23+24+- **Pepper** (`#201F26`): Dark background
25+- **BBQ** (`#2d2c35`): Secondary background
26+- **Charcoal** (`#3A3943`): Tertiary background
27+- **Iron** (`#4D4C57`): Borders and subtle elements
28+- **Oyster** (`#605F6B`): Muted text
29+- **Smoke** (`#BFBCC8`): Secondary text
30+- **Salt** (`#F1EFEF`): Primary text in dark mode
31+- **Butter** (`#FFFAF1`): Light background
32+33+This palette ensures consistency across all UI components and provides excellent contrast for readability in terminal environments.
···1+---
2+title: Getting Started
3+sidebar_label: Getting Started
4+description: Installation steps, configuration overview, and ways to find help.
5+sidebar_position: 5
6+---
7+8+# Getting Started
9+10+## Installation and Setup
11+12+### System Requirements
13+14+- Go 1.24 or higher
15+- SQLite 3.35 or higher (usually bundled)
16+- Terminal with 256-color support
17+- Unix-like OS (Linux, macOS, WSL)
18+19+### Building from Source
20+21+Clone the repository and build:
22+23+```sh
24+git clone https://github.com/stormlightlabs/noteleaf
25+cd noteleaf
26+go build -o ./tmp/noteleaf ./cmd
27+```
28+29+Install to your GOPATH:
30+31+```sh
32+go install
33+```
34+35+### Database Initialization
36+37+Run setup to create the database and configuration file:
38+39+```sh
40+noteleaf setup
41+```
42+43+This creates:
44+45+- Database at platform-specific application data directory
46+- Configuration file at platform-specific config directory
47+- Default settings for editor, priorities, and display options
48+49+### Seeding Sample Data
50+51+For exploration and testing, populate the database with example data:
52+53+```sh
54+noteleaf setup seed
55+```
56+57+This creates sample tasks, notes, books, and other items to help you understand the system's capabilities.
58+59+## Configuration Overview
60+61+Configuration lives in `config.toml` at the platform-specific config directory.
62+63+**Editor Settings**:
64+65+```toml
66+[editor]
67+command = "nvim"
68+args = []
69+```
70+71+**Task Defaults**:
72+73+```toml
74+[task]
75+default_priority = "medium"
76+default_status = "pending"
77+```
78+79+**Display Options**:
80+81+```toml
82+[display]
83+date_format = "2006-01-02"
84+time_format = "15:04"
85+```
86+87+View current configuration:
88+89+```sh
90+noteleaf config show
91+```
92+93+Update settings:
94+95+```sh
96+noteleaf config set editor vim
97+```
98+99+See the [Configuration](../Configuration.md) guide for complete options.
100+101+## Getting Help
102+103+Every command includes help text:
104+105+```sh
106+noteleaf --help
107+noteleaf task --help
108+noteleaf task add --help
109+```
110+111+For detailed command reference, run `noteleaf --help` and drill into the subcommand-specific help pages.
+26
website/docs/concepts/overview.md
···00000000000000000000000000
···1+---
2+title: Overview
3+sidebar_label: Overview
4+description: Noteleaf philosophy and reasons for a terminal-first approach.
5+sidebar_position: 1
6+---
7+8+# Overview
9+10+## What is Noteleaf?
11+12+Noteleaf is a terminal-based personal information manager that combines task management, note-taking, media tracking, and decentralized publishing into a unified system. Built for developers and power users who prefer keyboard-driven workflows, Noteleaf brings TaskWarrior-inspired task management together with a personal knowledge base and reading list tracker.
13+14+## Why the Terminal?
15+16+Terminal applications offer several advantages for focused productivity work:
17+18+**Keyboard-First Interface**: Navigate and manage information without context-switching to a mouse. Every action is a keystroke away, making workflows faster once learned.
19+20+**Scriptability**: Command-line tools integrate seamlessly with shell scripts, automation tools, and other CLI utilities. Noteleaf can be incorporated into your existing terminal-based workflow.
21+22+**Distraction-Free**: Terminal UIs remove visual clutter and web-based distractions, keeping you focused on the task at hand.
23+24+**Performance**: Native applications built with Go start instantly and consume minimal resources compared to Electron-based alternatives.
25+26+**Data Ownership**: Your data lives in a local SQLite database and markdown files. No cloud dependencies, no vendor lock-in, no privacy concerns.
···1+---
2+title: Terminal UI
3+sidebar_label: Terminal UI
4+description: Navigate Noteleafโs Bubble Tea interfaces and their script-friendly counterparts.
5+sidebar_position: 6
6+---
7+8+# Terminal UI
9+10+Most list-style commands (tasks, notes, books) have two personalities: an interactive Bubble Tea view for exploration and a static text output for piping into other tools. This page explains how both modes behave.
11+12+## Interactive Mode
13+14+### Navigation
15+16+- Launch the TUI with the default command (`noteleaf todo list`, `noteleaf note list`, `noteleaf media book add -i`, etc.).
17+- Use `j`/`k` or the arrow keys to move the selection. Page Up/Down jump faster, while `g`/`G` (or Home/End) snap to the top or bottom depending on the view.
18+- Search is always availableโpress `/` and start typing to filter titles, tags, projects, or notes in real time.
19+20+### Keyboard shortcuts
21+22+All interactive components reuse the same key map defined in `internal/ui/data_list.go` and `internal/ui/data_table.go`:
23+24+| Keys | Action |
25+|------|--------|
26+| `j` / `โ` | Move down |
27+| `k` / `โ` | Move up |
28+| `enter` | Select the highlighted row |
29+| `v` | Open the detail preview (when supported) |
30+| `/` | Start search |
31+| `r` | Refresh data from the database |
32+| `1-9` | Jump directly to a row index |
33+| `q`, `ctrl+c` | Quit the view |
34+35+The shortcuts appear in the on-screen help so you never have to memorize them all.
36+37+### Selection and actions
38+39+- Press `enter` to activate the primary action (open a note, view a task, confirm a media selection, etc.).
40+- Some screens expose extra actions on letter keys (e.g., `a` to archive, `e` to edit). They are listed alongside the contextual help (`?`).
41+- Interactive prompts such as `noteleaf media movie add` use the same selection model, so keyboard muscle memory carries over.
42+43+### Help screens
44+45+Hit `?` at any time to open the inline help overlay. It mirrors the bindings configured for the active component and also hints at hidden actions. Press `esc`, `backspace`, or `?` again to exit.
46+47+## Static Mode
48+49+### Command-line output
50+51+Add `--static` (or remove `-i`) to force plain text output. Examples:
52+53+```sh
54+noteleaf todo list --static
55+noteleaf note list --static --tag meeting
56+noteleaf media book list --all --static
57+```
58+59+Static mode prints tables with headings so they are easy to read or parse. Commands that default to prompts (like `noteleaf media movie add`) fall back to a numbered list when you omit `-i`.
60+61+### Scripting with Noteleaf
62+63+Static output is predictable, making it straightforward to combine with familiar utilities:
64+65+```sh
66+noteleaf todo list --static --project docs | rg "pending"
67+noteleaf note list --static | fzf
68+```
69+70+Because each row includes the record ID, you can feed the result back into follow-up commands (`noteleaf note view 42`, `noteleaf todo done 128`, etc.).
71+72+### Output formatting
73+74+The task viewer supports the `--format` flag for quick summaries:
75+76+```sh
77+noteleaf todo view 12 --format brief
78+noteleaf todo view 12 --format detailed # default
79+```
80+81+Brief mode hides timestamps and auxiliary metadata, which keeps CI logs or chat snippets short. Future commands will inherit the same pattern.
82+83+### JSON output
84+85+Use `--json` wherever it exists (currently on task views/lists) for structured output:
86+87+```sh
88+noteleaf todo view 12 --json | jq '.status'
89+noteleaf todo list --static --json | jq '.[] | select(.status=="pending")'
90+```
91+92+JSON mode ignores terminal colors and uses machine-friendly field names so you can script exports without touching the SQLite file directly.
-99
website/docs/development/ARCHITECTURE.md
···1-# System Architecture
2-3-Noteleaf is a CLI/TUI application for task and content management built on Go with SQLite persistence and terminal-based interfaces.
4-5-## Core Architecture
6-7-### Application Structure
8-9-The application follows a layered architecture with clear separation between presentation, business logic, and data access layers.
10-11-**Entry Point** - `cmd/main.go` initializes the application with dependency injection, creates handlers, and configures the Cobra command tree using the CommandGroup pattern.
12-13-**CLI Framework** - Built on `spf13/cobra` with `charmbracelet/fang` providing enhanced CLI features including color schemes, versioning, and improved help formatting.
14-15-**TUI Components** - Interactive interfaces use `charmbracelet/bubbletea` for state management and `charmbracelet/lipgloss` for styling with a consistent color palette system in `internal/ui/colors.go`.
16-17-### Data Layer
18-19-**Database** - SQLite with schema migrations in `internal/store/sql/migrations/`. The `internal/store` package manages database connections and configuration.
20-21-**Repository Pattern** - Data access abstracts through repository interfaces in `internal/repo/` with validation logic ensuring data integrity at the persistence boundary.
22-23-**Models** - Entity definitions in `internal/models/` implement standardized Model interfaces with common fields (ID, Created, Modified).
24-25-### Business Logic
26-27-**Handlers** - Business logic resides in `internal/handlers/` with one handler per domain (TaskHandler, NoteHandler, ArticleHandler, etc.).
28-Handlers receive repository dependencies through constructor injection.
29-30-**Services** - Domain-specific operations in `internal/services/` handle complex business workflows and external integrations.
31-32-**Validation** - Schema-based validation at repository level with custom ValidationError types providing detailed field-level error messages.
33-34-## Domain Features
35-36-### Content Management
37-38-**Articles** - Web scraping using `gocolly/colly` with domain-specific extraction rules stored in `internal/articles/rules/`.
39-Articles are parsed to markdown and stored with dual file references (markdown + HTML).
40-41-**Tasks** - Todo/task management inspired by TaskWarrior with filtering, status tracking, and interactive TUI views.
42-43-**Notes** - Simple note management with markdown support and glamour-based terminal rendering.
44-45-**Media Queues** - Separate queues for books, movies, and TV shows with status tracking and metadata management.
46-47-### User Interface
48-49-**Command Groups** - Commands organized into core functionality (task, note, article, media) and management operations (setup, config, status) using the CommandGroup interface pattern.
50-51-**Interactive Views** - Bubbletea-based TUI components for list navigation, item selection, and data entry with consistent styling through the lipgloss color system.
52-53-**Terminal Output** - Markdown rendering through `charmbracelet/glamour` for rich text display in terminal environments.
54-55-## Dependencies
56-57-**CLI/TUI** - Cobra command framework, Bubbletea state management, Lipgloss styling, Fang CLI enhancements.
58-59-**Data** - SQLite driver (`mattn/go-sqlite3`), TOML configuration parsing.
60-61-**Content Processing** - Colly web scraping, HTML/XML query libraries, Glamour markdown rendering, text processing utilities.
62-63-**Utilities** - UUID generation, time handling, logging through `charmbracelet/log`.
64-65-## Design Decisions and Tradeoffs
66-67-### Technology Choices
68-69-**Go over Rust** - Go was selected for its simplicity, excellent CLI ecosystem (Cobra, Charm libraries), and faster development velocity.
70-While Rust + Ratatui would provide better memory safety and potentially superior performance, Go's straightforward concurrency model and mature tooling ecosystem made it the pragmatic choice for rapid prototyping and iteration.
71-72-**SQLite over PostgreSQL** - SQLite provides zero-configuration deployment and sufficient performance for single-user CLI applications.
73-The embedded database eliminates setup complexity while supporting full SQL features needed for filtering and querying.
74-PostgreSQL would add deployment overhead without meaningful benefits for this use case.
75-76-**Repository Pattern over Active Record** - Repository interfaces enable clean separation between business logic and data access, facilitating testing through dependency injection.
77-This pattern scales better than Active Record for complex domain logic while maintaining clear boundaries between layers.
78-79-### Architectural Tradeoffs
80-81-**CommandGroup Interface** - Centralizes command registration while enabling modular command organization.
82-The pattern requires additional abstraction but provides consistent dependency injection and testing capabilities across all command groups.
83-84-**Handler-based Business Logic** - Business logic in handlers rather than rich domain models keeps the codebase simple and avoids over-engineering.
85-While this approach may not scale to complex business rules, it provides clear separation of concerns for the current feature set.
86-87-**Dual Storage for Articles** - Articles store both markdown and HTML versions to balance processing speed with format flexibility.
88-This doubles storage requirements but eliminates runtime conversion overhead and preserves original formatting.
89-90-### Component Interactions
91-92-**Handler โ Repository โ Database** - Request flow follows a linear path from CLI commands through business logic to data persistence.
93-This pattern ensures consistent validation and error handling while maintaining clear separation of concerns.
94-95-**TUI State Management** - Bubbletea's unidirectional data flow provides predictable state updates for interactive components.
96-The model-view-update pattern ensures consistent UI behavior across different terminal environments.
97-98-**Configuration and Migration** - Application startup validates configuration and runs database migrations before initializing handlers.
99-This fail-fast approach prevents runtime errors and ensures consistent database schema across deployments.
···1-# Testing Documentation
2-3-This document outlines the testing patterns and practices used in the `noteleaf` application.
4-5-## Overview
6-7-The codebase follows Go's standard testing practices with specialized testing utilities for complex scenarios.
8-Tests use the standard library along with carefully selected dependencies like faker for data generation and BubbleTea for TUI testing.
9-This approach keeps dependencies minimal while providing robust testing infrastructure for interactive components and complex integrations.
10-11-### Organization
12-13-Each package contains its own test files alongside the source code. Test files are organized by functionality and mirror the structure of the source code they test.
14-The codebase includes four main test utility files that provide specialized testing infrastructure:
15-16-- `internal/services/test_utilities.go` - HTTP mocking and media service testing
17-- `internal/repo/test_utilities.go` - Database testing and data generation
18-- `internal/ui/test_utilities.go` - TUI testing framework and interactive component testing
19-- `internal/handlers/test_utilities.go` - Handler testing with database isolation and input simulation
20-21-## Patterns
22-23-### Handler Creation
24-25-Tests create real handler instances using temporary databases to ensure test isolation.
26-Factory functions handle both database setup and handler initialization, returning both the handler and a cleanup function.
27-28-### Database Isolation
29-30-Tests use temporary directories and environment variable manipulation to create isolated database instances.
31-Each test gets its own temporary SQLite database that is automatically cleaned up after the test completes.
32-33-The `setupCommandTest` function creates a temporary directory, sets `XDG_CONFIG_HOME` to point to it, and initializes the database schema.
34-This ensures tests don't interfere with each other or with development data.
35-36-### Resource Management
37-38-Tests properly manage resources using cleanup functions returned by factory methods.
39-The cleanup function handles both handler closure and temporary directory removal.
40-This pattern ensures complete resource cleanup even if tests fail.
41-42-### Error Handling
43-44-Tests use `t.Fatal` for setup errors that prevent test execution and `t.Error` for test assertion failures.
45-Fatal errors stop test execution while errors allow tests to continue checking other conditions.
46-47-### Context Cancellation
48-49-Error case testing frequently uses context cancellation to simulate database and network failures.
50-The pattern creates a context, immediately cancels it, then calls the function under test to verify error handling.
51-This provides a reliable way to test error paths without requiring complex mock setups or external failure injection.
52-53-### Command Structure
54-55-Command group tests verify cobra command structure including use strings, aliases, short descriptions, and subcommand presence.
56-Tests check that commands are properly configured without executing their logic.
57-58-### Interface Compliance
59-60-Tests verify interface compliance using compile-time checks with blank identifier assignments.
61-This ensures structs implement expected interfaces without runtime overhead.
62-63-## Test Infrastructure
64-65-### Test Utility Frameworks
66-67-The codebase provides comprehensive testing utilities organized by layer and functionality.
68-Each test utility file contains specialized helpers, mocks, and test infrastructure for its respective domain.
69-70-#### Database Testing Utilities
71-72-`internal/repo/test_utilities.go` provides comprehensive database testing infrastructure:
73-74-- **In-Memory Database Creation**: `CreateTestDB` creates isolated SQLite databases with full schema
75-- **Sample Data Factories**: Functions like `CreateSampleTask`, `CreateSampleBook` generate realistic test data
76-- **Faker Integration**: Uses jaswdr/faker for generating realistic fake data with `CreateFakeArticle`
77-- **Test Setup Helpers**: `SetupTestData` creates a full set of sample data across all models
78-- **Custom Assertions**: Generic assertion helpers like `AssertEqual`, `AssertContains`, `AssertNoError`
79-80-#### HTTP Service Testing
81-82-`internal/services/test_utilities.go` provides HTTP mocking and media service testing:
83-84-- **Mock Configuration**: `MockConfig` structure for configuring service behavior
85-- **Function Replacement**: `SetupMediaMocks` replaces service functions with controllable mocks
86-- **Sample Data Access**: Helper functions that use embedded HTML samples for realistic testing
87-- **Specialized Scenarios**: Pre-configured mock setups for success and failure scenarios
88-- **Assertion Helpers**: Domain-specific assertions for movies, TV shows, and error conditions
89-90-#### TUI Testing Framework
91-92-`internal/ui/test_utilities.go` provides a comprehensive BubbleTea testing framework:
93-94-- **TUITestSuite**: Complete testing infrastructure for interactive TUI components
95-- **Controlled I/O**: `ControlledOutput` and `ControlledInput` for deterministic testing
96-- **Message Simulation**: Key press simulation, message queuing, and timing control
97-- **State Verification**: Model state checking and view content assertions
98-- **Timeout Handling**: Configurable timeouts for async operations
99-- **Mock Repository**: Test doubles for repository interfaces
100-101-#### Handler Testing Infrastructure
102-103-`internal/handlers/test_utilities.go` provides end-to-end handler testing:
104-105-- **Environment Isolation**: `HandlerTestHelper` creates isolated test environments
106-- **Input Simulation**: `InputSimulator` for testing interactive components that use `fmt.Scanf`
107-- **HTTP Mocking**: Comprehensive HTTP server mocking for external API testing
108-- **Database Helpers**: Database corruption and error scenario testing
109-- **Editor Mocking**: `MockEditor` for testing file editing workflows
110-- **Assertion Helpers**: Handler-specific assertions and verification functions
111-112-### Advanced Testing Patterns
113-114-#### Input Simulation for Interactive Components
115-116-Interactive handlers that use `fmt.Scanf` require special testing infrastructure with an `io.Reader` implementation.
117-118-The `InputSimulator` provides controlled input sequences that prevent tests from hanging while maintaining coverage of interactive code paths.
119-120-#### TUI Testing with BubbleTea Framework
121-122-The TUI testing framework addresses the fundamental challenge of testing interactive terminal applications in a deterministic, concurrent environment.
123-BubbleTea's message-passing architecture creates unique testing requirements that standard Go testing patterns cannot adequately address.
124-125-The framework implements a controlled execution environment that replaces BubbleTea's typical program loop with a deterministic testing harness.
126-Rather than running an actual terminal program, the "testing suite" directly manages model state transitions by simulating the Update/View cycle.
127-This approach eliminates the non-deterministic behavior inherent in real terminal interactions while preserving the exact message flow patterns that production code experiences.
128-129-State verification relies on function composition patterns where test conditions are expressed as closures that capture specific model states.
130-The `WaitFor` mechanism uses polling with configurable timeouts, addressing the async nature of BubbleTea model updates without creating race conditions.
131-This pattern bridges imperative test assertions with BubbleTea's declarative update model.
132-This is inspired by front-end/TS/JS testing patterns.
133-134-The framework's I/O abstraction layer replaces terminal input/output with controlled buffers that implement standard Go interfaces.
135-This design maintains interface compatibility while providing complete control over timing and content.
136-The controlled I/O system captures all output for later verification and injects precise input sequences, enabling complex interaction testing without external dependencies.
137-138-Concurrency management uses channels and context propagation to coordinate between the testing framework and the model under test.
139-The suite manages goroutine lifecycle and ensures proper cleanup, preventing test interference and resource leaks.
140-This architecture supports testing of models that perform background operations or handle async events.
141-142-#### HTTP Service Mocking
143-144-Service testing uses HTTP mocking with request capture. A `MockServer` is instantiated, and its URL is used in test scoped services.
145-146-#### Database Schema Testing
147-148-Database tests use comprehensive schema setup with (automatic) cleanup
149-150-#### Environment Manipulation
151-152-Environment testing utilities provide controlled environment manipulation. Environment variables are restored after instantiation.
153-154-## Test Organization Patterns
155-156-### Single Root Test
157-158-The preferred test organization pattern uses a single root test function with nested subtests using `t.Run`.
159-This provides clear hierarchical organization and allows running specific test sections while maintaining shared setup and context.
160-This pattern offers several advantages: clear test hierarchy with logical grouping, ability to run specific test sections, consistent test structure across the codebase, and shared setup that can be inherited by subtests.
161-162-### Integration vs Unit Testing
163-164-The codebase emphasizes integration testing over heavy mocking by using real handlers and services to verify actual behavior rather than mocked interactions.
165-The goal is to catch integration issues while maintaining test reliability.
166-167-### Static Output
168-169-UI components support static output modes for testing. Tests capture output using bytes.Buffer and verify content using string contains checks rather than exact string matching for better test maintainability.
170-171-### Standard Output Redirection
172-173-For testing functions that write to stdout, tests use a pipe redirection pattern with goroutines to capture output.
174-The pattern saves the original stdout, redirects to a pipe, captures output in a separate goroutine, and restores stdout after the test.
175-This ensures clean output capture without interfering with the testing framework.
176-177-## Utilities
178-179-### Test Data Generation
180-181-The codebase uses sophisticated data generation strategies:
182-183-- **Factory Functions**: Each package provides factory functions for creating valid test data
184-- **Faker Integration**: Uses `jaswdr/faker` for generating realistic fake data with proper randomization
185-- **Sample Data Creators**: Functions like `CreateSampleTask`, `CreateSampleBook` provide consistent test data
186-- **Embedded Resources**: Services use embedded HTML samples from real API responses for realistic testing
187-188-### Assertion Helpers
189-190-Custom assertion functions provide clear error messages and reduce test code duplication:
191-192-- **Generic Assertions**: `AssertEqual`, `AssertNoError`, `AssertContains` for common checks
193-- **Domain-Specific Assertions**: `AssertMovieInResults`, `AssertNoteExists` for specialized verification
194-- **TUI Assertions**: `AssertViewContains`, `AssertModelState` for BubbleTea model testing
195-- **HTTP Assertions**: `AssertRequestMade` for verifying HTTP interactions
196-197-### Mock Infrastructure
198-199-Each layer provides specialized mocking capabilities:
200-201-- **Service Mocking**: Function replacement with configurable behavior and embedded test data
202-- **HTTP Mocking**: `HTTPMockServer` with request capture and response customization
203-- **Input Mocking**: `InputSimulator` for deterministic interactive component testing
204-- **Editor Mocking**: `MockEditor` for file editing workflow testing
205-- **Repository Mocking**: `MockTaskRepository` for TUI component testing
206-207-### Environment and Resource Management
208-209-Testing utilities provide comprehensive resource management:
210-211-- **Environment Isolation**: `EnvironmentTestHelper` for controlled environment variable manipulation
212-- **Database Isolation**: Temporary SQLite databases with automatic cleanup
213-- **File System Isolation**: Temporary directories with automatic cleanup
214-- **Process Isolation**: Handler helpers that create completely isolated test environments
215-216-## Testing CLI Commands
217-218-Command group tests focus on structure verification rather than execution testing.
219-Tests check command configuration, subcommand presence, and interface compliance. This approach ensures command trees are properly constructed without requiring complex execution mocking.
220-221-### CommandGroup Interface Testing
222-223-The CommandGroup interface enables testable CLI architecture. Tests verify that command groups implement the interface correctly and return properly configured cobra commands.
224-This pattern separates command structure from command execution.
225-226-Interface compliance is tested using compile-time checks within the "Interface Implementations" subtest, ensuring all command structs properly implement the CommandGroup interface without runtime overhead.
227-228-## Performance Considerations
229-230-Tests avoid expensive operations in setup functions. Handler creation uses real instances but tests focus on structure verification rather than full execution paths.
231-This keeps test suites fast while maintaining coverage of critical functionality.
232-233-The single root test pattern allows for efficient resource management where setup costs can be amortized across multiple related test cases.
234-235-## Interactive Component Testing
236-237-The codebase provides comprehensive testing infrastructure for interactive components, including both terminal UI applications and command-line interfaces that require user input.
238-239-### Input Simulation Framework
240-241-Interactive handlers that use `fmt.Scanf` require specialized testing infrastructure:
242-243-- **InputSimulator**: Provides controlled input sequences that implement `io.Reader`
244-- **Menu Selection Helpers**: `MenuSelection`, `MenuCancel`, `MenuSequence` for common interaction patterns
245-- **Handler Integration**: Handlers can accept `io.Reader` for input, enabling deterministic testing
246-- **Cleanup Management**: Automatic cleanup prevents resource leaks in test environments
247-248-### TUI Testing with BubbleTea
249-250-The TUI testing framework provides complete testing infrastructure for interactive terminal interfaces:
251-252-- **TUITestSuite**: Comprehensive testing framework for BubbleTea models
253-- **Message Simulation**: Key press simulation, window resize events, and custom message handling
254-- **State Verification**: Model state checking with custom condition functions
255-- **View Assertions**: Content verification and output capture
256-- **Timing Control**: Configurable timeouts and delay handling for async operations
257-- **Mock Integration**: Repository mocking for isolated component testing
258-259-### Interactive Test Scenarios
260-261-Interactive handlers should test comprehensive scenarios:
262-263-- **Valid user selections** - User chooses valid menu options and inputs
264-- **Cancellation flows** - User chooses to cancel operations (option 0 or escape keys)
265-- **Invalid choices** - User selects out-of-range options or provides invalid input
266-- **Navigation patterns** - Keyboard navigation, scrolling, and multi-step interactions
267-- **Error handling** - Network errors, service failures, and data validation errors
268-- **Empty states** - Search returns no results, empty lists, and missing data
269-- **Edge cases** - Boundary conditions, malformed input, and resource constraints
270-271-### TUI Component Testing Patterns
272-273-BubbleTea components use specialized testing patterns:
274-275-- **Key Sequence Testing**: Simulate complex user interactions with timing
276-- **State Transition Testing**: Verify model state changes through user actions
277-- **View Content Testing**: Assert specific content appears in rendered output
278-- **Async Operation Testing**: Handle loading states and network operations
279-- **Responsive Design Testing**: Test different terminal sizes and window resize handling
280-281-This comprehensive testing approach ensures interactive components work reliably in automated environments while maintaining full coverage of user interaction paths.
282-283-## Errors
284-285-Error coverage follows a systematic approach to identify and test failure scenarios:
286-287-1. **Context Cancellation** - Primary method for testing database and network timeout scenarios
288-2. **Invalid Input** - Malformed data, empty inputs, boundary conditions
289-3. **Resource Exhaustion** - Database connection failures, memory limits
290-4. **Constraint Violations** - Duplicate keys, foreign key failures
291-5. **State Validation** - Testing functions with invalid system states
292-6. **Interactive Input** - Invalid user choices, cancellation handling, input simulation errors
···1+---
2+title: Building Noteleaf
3+sidebar_label: Building
4+sidebar_position: 1
5+description: Build configurations and development workflows.
6+---
7+8+# Building Noteleaf
9+10+Noteleaf uses [Task](https://taskfile.dev) for build automation, providing consistent workflows across development, testing, and releases.
11+12+## Prerequisites
13+14+- Go 1.21 or later
15+- [Task](https://taskfile.dev) (install via `brew install go-task/tap/go-task` on macOS)
16+- Git (for version information)
17+18+## Build Types
19+20+### Development Build
21+22+Quick build without version injection for local development:
23+24+```sh
25+task build
26+```
27+28+Output: `./tmp/noteleaf`
29+30+### Development Build with Version
31+32+Build with git commit hash and development tools enabled:
33+34+```sh
35+task build:dev
36+```
37+38+Version format: `git describe` output (e.g., `v0.1.0-15-g1234abc`)
39+Output: `./tmp/noteleaf`
40+41+### Release Candidate Build
42+43+Build with `-rc` tag, excludes development tools:
44+45+```sh
46+git tag v1.0.0-rc1
47+task build:rc
48+```
49+50+Requirements:
51+52+- Clean git tag with `-rc` suffix
53+- Tag format: `v1.0.0-rc1`, `v2.1.0-rc2`, etc.
54+55+### Production Build
56+57+Build for release with strict validation:
58+59+```sh
60+git tag v1.0.0
61+task build:prod
62+```
63+64+Requirements:
65+66+- Clean semver git tag (e.g., `v1.0.0`, `v2.1.3`)
67+- No uncommitted changes
68+- No prerelease suffix
69+70+## Build Tags
71+72+Production builds use the `prod` build tag to exclude development and seed commands:
73+74+```go
75+//go:build !prod
76+```
77+78+Commands excluded from production:
79+80+- `noteleaf dev` - Development utilities
81+- `noteleaf seed` - Test data generation
82+83+## Version Information
84+85+Build process injects version metadata via ldflags:
86+87+```go
88+// internal/version/version.go
89+var (
90+ Version = "dev" // Git tag or "dev"
91+ Commit = "none" // Git commit hash
92+ BuildDate = "unknown" // Build timestamp
93+)
94+```
95+96+View version information:
97+98+```sh
99+task version:show
100+noteleaf version
101+```
102+103+## Build Artifacts
104+105+All binaries are built to `./tmp/` directory:
106+107+```
108+tmp/
109+โโโ noteleaf # Binary for current platform
110+```
111+112+## Development Workflow
113+114+Full development cycle with linting and testing:
115+116+```sh
117+task dev
118+```
119+120+Runs:
121+122+1. Clean build artifacts
123+2. Run linters (vet, fmt)
124+3. Execute all tests
125+4. Build binary
126+127+## Manual Build
128+129+Build directly with Go (bypasses Task automation):
130+131+```sh
132+go build -o ./tmp/noteleaf ./cmd
133+```
134+135+With version injection:
136+137+```sh
138+go build -ldflags "-X github.com/stormlightlabs/noteleaf/internal/version.Version=v1.0.0" -o ./tmp/noteleaf ./cmd
139+```
140+141+## Cross-Platform Builds
142+143+Build for specific platforms:
144+145+```sh
146+# Linux
147+GOOS=linux GOARCH=amd64 go build -o ./tmp/noteleaf-linux ./cmd
148+149+# Windows
150+GOOS=windows GOARCH=amd64 go build -o ./tmp/noteleaf.exe ./cmd
151+152+# macOS (ARM)
153+GOOS=darwin GOARCH=arm64 go build -o ./tmp/noteleaf-darwin-arm64 ./cmd
154+```
155+156+## Clean Build
157+158+Remove all build artifacts:
159+160+```sh
161+task clean
162+```
163+164+Removes:
165+166+- `./tmp/` directory
167+- `coverage.out` and `coverage.html`
···1-# Media Examples
2-3-Examples of managing your reading lists and watch queues using Noteleaf.
4-5-## Books
6-7-### Adding Books
8-9-Search and add from Open Library:
10-11-```sh
12-noteleaf media book add "The Name of the Wind"
13-noteleaf media book add "Project Hail Mary"
14-noteleaf media book add "Dune"
15-```
16-17-Add by author:
18-19-```sh
20-noteleaf media book add "Foundation by Isaac Asimov"
21-```
22-23-Add with specific year:
24-25-```sh
26-noteleaf media book add "1984 by George Orwell 1949"
27-```
28-29-### Viewing Books
30-31-List all books:
32-33-```sh
34-noteleaf media book list
35-```
36-37-Filter by status:
38-39-```sh
40-noteleaf media book list --status queued
41-noteleaf media book list --status reading
42-noteleaf media book list --status finished
43-```
44-45-### Managing Reading Status
46-47-Start reading:
48-49-```sh
50-noteleaf media book reading 1
51-```
52-53-Mark as finished:
54-55-```sh
56-noteleaf media book finished 1
57-```
58-59-### Tracking Progress
60-61-Update reading progress (percentage):
62-63-```sh
64-noteleaf media book progress 1 25
65-noteleaf media book progress 1 50
66-noteleaf media book progress 1 75
67-```
68-69-Update with page numbers:
70-71-```sh
72-noteleaf media book progress 1 150 --total 400
73-```
74-75-### Book Details
76-77-View book details:
78-79-```sh
80-noteleaf media book view 1
81-```
82-83-### Updating Book Information
84-85-Update book notes:
86-87-```sh
88-noteleaf media book update 1 --notes "Excellent worldbuilding and magic system"
89-```
90-91-Add rating:
92-93-```sh
94-noteleaf media book update 1 --rating 5
95-```
96-97-### Removing Books
98-99-Remove from list:
100-101-```sh
102-noteleaf media book remove 1
103-```
104-105-## Movies
106-107-### Adding Movies
108-109-Add movie:
110-111-```sh
112-noteleaf media movie add "The Matrix"
113-noteleaf media movie add "Inception"
114-noteleaf media movie add "Interstellar"
115-```
116-117-Add with year:
118-119-```sh
120-noteleaf media movie add "Blade Runner 1982"
121-```
122-123-### Viewing Movies
124-125-List all movies:
126-127-```sh
128-noteleaf media movie list
129-```
130-131-Filter by status:
132-133-```sh
134-noteleaf media movie list --status queued
135-noteleaf media movie list --status watched
136-```
137-138-### Managing Watch Status
139-140-Mark as watched:
141-142-```sh
143-noteleaf media movie watched 1
144-```
145-146-### Movie Details
147-148-View movie details:
149-150-```sh
151-noteleaf media movie view 1
152-```
153-154-### Updating Movie Information
155-156-Add notes and rating:
157-158-```sh
159-noteleaf media movie update 1 --notes "Mind-bending sci-fi" --rating 5
160-```
161-162-### Removing Movies
163-164-Remove from list:
165-166-```sh
167-noteleaf media movie remove 1
168-```
169-170-## TV Shows
171-172-### Adding TV Shows
173-174-Add TV show:
175-176-```sh
177-noteleaf media tv add "Breaking Bad"
178-noteleaf media tv add "The Wire"
179-noteleaf media tv add "Better Call Saul"
180-```
181-182-### Viewing TV Shows
183-184-List all shows:
185-186-```sh
187-noteleaf media tv list
188-```
189-190-Filter by status:
191-192-```sh
193-noteleaf media tv list --status queued
194-noteleaf media tv list --status watching
195-noteleaf media tv list --status watched
196-```
197-198-### Managing Watch Status
199-200-Start watching:
201-202-```sh
203-noteleaf media tv watching 1
204-```
205-206-Mark as finished:
207-208-```sh
209-noteleaf media tv watched 1
210-```
211-212-Put on hold:
213-214-```sh
215-noteleaf media tv update 1 --status on-hold
216-```
217-218-### TV Show Details
219-220-View show details:
221-222-```sh
223-noteleaf media tv view 1
224-```
225-226-### Updating TV Show Information
227-228-Update current episode:
229-230-```sh
231-noteleaf media tv update 1 --season 2 --episode 5
232-```
233-234-Add notes and rating:
235-236-```sh
237-noteleaf media tv update 1 --notes "Intense character development" --rating 5
238-```
239-240-### Removing TV Shows
241-242-Remove from list:
243-244-```sh
245-noteleaf media tv remove 1
246-```
247-248-## Common Workflows
249-250-### Weekend Watch List
251-252-Plan your weekend viewing:
253-254-```sh
255-# Add movies
256-noteleaf media movie add "The Shawshank Redemption"
257-noteleaf media movie add "Pulp Fiction"
258-noteleaf media movie add "Forrest Gump"
259-260-# View queue
261-noteleaf media movie list --status queued
262-```
263-264-### Reading Challenge
265-266-Track annual reading goal:
267-268-```sh
269-# Add books to queue
270-noteleaf media book add "The Lord of the Rings"
271-noteleaf media book add "The Hobbit"
272-noteleaf media book add "Mistborn"
273-274-# Check progress
275-noteleaf media book list --status finished
276-noteleaf media book list --status reading
277-```
278-279-### Binge Watching Tracker
280-281-Track TV series progress:
282-283-```sh
284-# Start series
285-noteleaf media tv add "Game of Thrones"
286-noteleaf media tv watching 1
287-288-# Update progress
289-noteleaf media tv update 1 --season 1 --episode 1
290-noteleaf media tv update 1 --season 1 --episode 2
291-292-# View current shows
293-noteleaf media tv list --status watching
294-```
295-296-### Media Recommendations
297-298-Keep track of recommendations:
299-300-```sh
301-# Add recommended items
302-noteleaf media book add "Sapiens" --notes "Recommended by John"
303-noteleaf media movie add "Parasite" --notes "Won Best Picture 2020"
304-noteleaf media tv add "Succession" --notes "From Reddit recommendations"
305-306-# View recommendations
307-noteleaf media book list --static | grep "Recommended"
308-```
309-310-### Review and Rating
311-312-After finishing, add review:
313-314-```sh
315-# Book review
316-noteleaf media book finished 1
317-noteleaf media book update 1 \
318- --rating 5 \
319- --notes "Masterful storytelling. The magic system is one of the best in fantasy."
320-321-# Movie review
322-noteleaf media movie watched 2
323-noteleaf media movie update 2 \
324- --rating 4 \
325- --notes "Great cinematography but slow pacing in second act."
326-327-# TV show review
328-noteleaf media tv watched 3
329-noteleaf media tv update 3 \
330- --rating 5 \
331- --notes "Best character development I've seen. Final season was perfect."
332-```
333-334-### Genre Organization
335-336-Organize by genre using notes:
337-338-```sh
339-noteleaf media book add "Snow Crash" --notes "Genre: Cyberpunk"
340-noteleaf media book add "Neuromancer" --notes "Genre: Cyberpunk"
341-noteleaf media book add "The Expanse" --notes "Genre: Space Opera"
342-343-# Find by genre
344-noteleaf media book list --static | grep "Cyberpunk"
345-```
346-347-### Currently Consuming
348-349-See what you're currently reading/watching:
350-351-```sh
352-noteleaf media book list --status reading
353-noteleaf media tv list --status watching
354-```
355-356-### Completed This Month
357-358-View completed items:
359-360-```sh
361-noteleaf media book list --status finished
362-noteleaf media movie list --status watched
363-noteleaf media tv list --status watched
364-```
365-366-### Clear Finished Items
367-368-Archive or remove completed media:
369-370-```sh
371-# Remove watched movies
372-noteleaf media movie remove 1 2 3
373-374-# Remove finished books
375-noteleaf media book remove 4 5 6
376-```
377-378-## Statistics and Reports
379-380-### Reading Statistics
381-382-Count books by status:
383-384-```sh
385-echo "Queued: $(noteleaf media book list --status queued --static | wc -l)"
386-echo "Reading: $(noteleaf media book list --status reading --static | wc -l)"
387-echo "Finished: $(noteleaf media book list --status finished --static | wc -l)"
388-```
389-390-### Viewing Habits
391-392-Track watch queue size:
393-394-```sh
395-echo "Movies to watch: $(noteleaf media movie list --status queued --static | wc -l)"
396-echo "Shows in progress: $(noteleaf media tv list --status watching --static | wc -l)"
397-```
···1-# Publication Examples
2-3-Examples of publishing notes to leaflet.pub using the AT Protocol integration.
4-5-## Overview
6-7-The publication system allows you to sync your local notes with leaflet.pub, an AT Protocol-based publishing platform. You can pull drafts from leaflet, publish local notes, and maintain a synchronized writing workflow across platforms.
8-9-## Authentication
10-11-### Initial Authentication
12-13-Authenticate with your BlueSky account:
14-15-```sh
16-noteleaf pub auth username.bsky.social
17-```
18-19-This will prompt for your app password interactively.
20-21-### Authenticate with Password Flag
22-23-Provide credentials directly:
24-25-```sh
26-noteleaf pub auth username.bsky.social --password "your-app-password"
27-```
28-29-### Creating an App Password
30-31-1. Visit [bsky.app/settings/app-passwords](https://bsky.app/settings/app-passwords)
32-2. Create a new app password named "noteleaf"
33-3. Use that password (not your main password) for authentication
34-35-### Check Authentication Status
36-37-```sh
38-noteleaf pub status
39-```
40-41-## Pulling Documents from Leaflet
42-43-### Pull All Documents
44-45-Fetch all drafts and published documents:
46-47-```sh
48-noteleaf pub pull
49-```
50-51-This will:
52-- Connect to your leaflet account
53-- Fetch all documents in your repository
54-- Create new notes for documents not yet synced
55-- Update existing notes that have changed
56-57-### After Pulling
58-59-List the synced notes:
60-61-```sh
62-noteleaf pub list
63-```
64-65-View synced notes interactively:
66-67-```sh
68-noteleaf pub list --interactive
69-```
70-71-## Publishing Local Notes
72-73-### Publish a Note
74-75-Create a new document on leaflet from a local note:
76-77-```sh
78-noteleaf pub post 123
79-```
80-81-### Publish as Draft
82-83-Create as draft instead of publishing immediately:
84-85-```sh
86-noteleaf pub post 123 --draft
87-```
88-89-### Preview Before Publishing
90-91-See what would be posted without actually posting:
92-93-```sh
94-noteleaf pub post 123 --preview
95-```
96-97-### Validate Conversion
98-99-Check if markdown conversion will work:
100-101-```sh
102-noteleaf pub post 123 --validate
103-```
104-105-## Updating Published Documents
106-107-### Update an Existing Document
108-109-Update a previously published note:
110-111-```sh
112-noteleaf pub patch 123
113-```
114-115-### Preview Update
116-117-See what would be updated:
118-119-```sh
120-noteleaf pub patch 123 --preview
121-```
122-123-### Validate Update
124-125-Check conversion before updating:
126-127-```sh
128-noteleaf pub patch 123 --validate
129-```
130-131-## Batch Operations
132-133-### Publish Multiple Notes
134-135-Create or update multiple documents at once:
136-137-```sh
138-noteleaf pub push 1 2 3 4 5
139-```
140-141-This will:
142-- Create new documents for notes never published
143-- Update existing documents for notes already on leaflet
144-145-### Batch Publish as Drafts
146-147-```sh
148-noteleaf pub push 10 11 12 --draft
149-```
150-151-## Viewing Publications
152-153-### List All Synced Notes
154-155-```sh
156-noteleaf pub list
157-```
158-159-Aliases:
160-```sh
161-noteleaf pub ls
162-```
163-164-### Filter by Status
165-166-Published documents only:
167-```sh
168-noteleaf pub list --published
169-```
170-171-Drafts only:
172-```sh
173-noteleaf pub list --draft
174-```
175-176-All documents:
177-```sh
178-noteleaf pub list --all
179-```
180-181-### Interactive Browser
182-183-Browse with TUI interface:
184-185-```sh
186-noteleaf pub list --interactive
187-noteleaf pub list -i
188-```
189-190-With filters:
191-```sh
192-noteleaf pub list --published --interactive
193-noteleaf pub list --draft -i
194-```
195-196-## Common Workflows
197-198-### Initial Setup and Pull
199-200-Set up leaflet integration and pull existing documents:
201-202-```sh
203-# Authenticate
204-noteleaf pub auth username.bsky.social
205-206-# Check status
207-noteleaf pub status
208-209-# Pull all documents
210-noteleaf pub pull
211-212-# View synced notes
213-noteleaf pub list --interactive
214-```
215-216-### Publishing Workflow
217-218-Write locally, then publish to leaflet:
219-220-```sh
221-# Create a note
222-noteleaf note create "My Blog Post" --interactive
223-224-# List notes to get ID
225-noteleaf note list
226-227-# Publish as draft first
228-noteleaf pub post 42 --draft
229-230-# Review draft on leaflet.pub
231-# Make edits locally
232-noteleaf note edit 42
233-234-# Update the draft
235-noteleaf pub patch 42
236-237-# When ready, republish without --draft flag
238-noteleaf pub post 42
239-```
240-241-### Sync Workflow
242-243-Keep local notes in sync with leaflet:
244-245-```sh
246-# Pull latest changes from leaflet
247-noteleaf pub pull
248-249-# Make local edits
250-noteleaf note edit 123
251-252-# Push changes back
253-noteleaf pub patch 123
254-255-# Check sync status
256-noteleaf pub list --published
257-```
258-259-### Draft Management
260-261-Work with drafts before publishing:
262-263-```sh
264-# Create drafts
265-noteleaf pub post 10 --draft
266-noteleaf pub post 11 --draft
267-noteleaf pub post 12 --draft
268-269-# View all drafts
270-noteleaf pub list --draft
271-272-# Edit a draft locally
273-noteleaf note edit 10
274-275-# Update on leaflet
276-noteleaf pub patch 10
277-278-# Promote draft to published (re-post without --draft)
279-noteleaf pub post 10
280-```
281-282-### Batch Publishing
283-284-Publish multiple notes at once:
285-286-```sh
287-# Create several notes
288-noteleaf note create "Post 1" "Content 1"
289-noteleaf note create "Post 2" "Content 2"
290-noteleaf note create "Post 3" "Content 3"
291-292-# Get note IDs
293-noteleaf note list --static
294-295-# Publish all at once
296-noteleaf pub push 50 51 52
297-298-# Or as drafts
299-noteleaf pub push 50 51 52 --draft
300-```
301-302-### Review Before Publishing
303-304-Always preview and validate before publishing:
305-306-```sh
307-# Validate markdown conversion
308-noteleaf pub post 99 --validate
309-310-# Preview the output
311-noteleaf pub post 99 --preview
312-313-# If everything looks good, publish
314-noteleaf pub post 99
315-```
316-317-### Cross-Platform Editing
318-319-Edit on leaflet.pub, sync to local:
320-321-```sh
322-# Pull changes from leaflet
323-noteleaf pub pull
324-325-# View what changed
326-noteleaf pub list --interactive
327-328-# Make additional edits locally
329-noteleaf note edit 123
330-331-# Push updates back
332-noteleaf pub patch 123
333-```
334-335-### Status Monitoring
336-337-Check authentication and publication status:
338-339-```sh
340-# Check auth status
341-noteleaf pub status
342-343-# List published documents
344-noteleaf pub list --published
345-346-# Count publications
347-noteleaf pub list --published --static | wc -l
348-```
349-350-## Troubleshooting
351-352-### Re-authenticate
353-354-If authentication expires:
355-356-```sh
357-noteleaf pub auth username.bsky.social
358-```
359-360-### Check Status
361-362-Verify connection:
363-364-```sh
365-noteleaf pub status
366-```
367-368-### Force Pull
369-370-Re-sync all documents:
371-372-```sh
373-noteleaf pub pull
374-```
375-376-### Validate Before Publishing
377-378-If publishing fails, validate first:
379-380-```sh
381-noteleaf pub post 123 --validate
382-```
383-384-Check for markdown formatting issues that might not convert properly.
385-386-## Integration with Notes
387-388-### Publishing Flow
389-390-```sh
391-# Create note locally
392-noteleaf note create "Article Title" --interactive
393-394-# Add tags for organization
395-noteleaf note tag 1 --add published,blog
396-397-# Publish to leaflet
398-noteleaf pub post 1
399-400-# Continue editing locally
401-noteleaf note edit 1
402-403-# Sync updates
404-noteleaf pub patch 1
405-```
406-407-### Import from Leaflet
408-409-```sh
410-# Pull from leaflet
411-noteleaf pub pull
412-413-# View imported notes
414-noteleaf pub list
415-416-# Edit locally
417-noteleaf note edit 123
418-419-# Continue working with standard note commands
420-noteleaf note read 123
421-noteleaf note tag 123 --add imported
422-```
423-424-## Advanced Usage
425-426-### Selective Publishing
427-428-Publish only specific notes with a tag:
429-430-```sh
431-# Tag notes for publication
432-noteleaf note tag 10 --add ready-to-publish
433-noteleaf note tag 11 --add ready-to-publish
434-435-# List tagged notes
436-noteleaf note list --tags ready-to-publish
437-438-# Publish those notes
439-noteleaf pub push 10 11
440-```
441-442-### Draft Review Cycle
443-444-```sh
445-# Publish drafts
446-noteleaf pub push 1 2 3 --draft
447-448-# Review on leaflet.pub in browser
449-# Make edits locally based on feedback
450-451-# Update drafts
452-noteleaf pub push 1 2 3
453-454-# When ready, publish (create as non-drafts)
455-noteleaf pub post 1
456-noteleaf pub post 2
457-noteleaf pub post 3
458-```
459-460-### Publication Archive
461-462-Keep track of published work:
463-464-```sh
465-# Tag published notes
466-noteleaf note tag 123 --add published,2024,blog
467-468-# List all published notes
469-noteleaf note list --tags published
470-471-# Archive old publications
472-noteleaf note archive 123
473-```
474-475-## Notes
476-477-- Authentication tokens are stored in the configuration file
478-- Notes are matched by their leaflet record key (rkey)
479-- The `push` command intelligently chooses between `post` and `patch`
480-- Draft status is preserved when patching existing documents
481-- Use `--preview` and `--validate` flags to test before publishing
482-- Pull regularly to stay synced with changes made on leaflet.pub
···1+---
2+title: Open Library API
3+sidebar_label: Open Library
4+sidebar_position: 1
5+description: Book metadata via Open Library API integration.
6+---
7+8+# Open Library API
9+10+Noteleaf integrates with [Open Library](https://openlibrary.org) to fetch book metadata, search for books, and enrich your reading list.
11+12+## Overview
13+14+Open Library provides:
15+16+- Book search by title, author, ISBN
17+- Work and edition metadata
18+- Author information
19+- Cover images
20+- Subject classifications
21+- Publication details
22+23+## Configuration
24+25+No API key required. Open Library is a free, open API service.
26+27+Optional user agent configuration is handled automatically:
28+29+```toml
30+# .noteleaf.conf.toml
31+# No configuration needed for Open Library
32+```
33+34+## Rate Limiting
35+36+Open Library enforces rate limits:
37+38+- 180 requests per minute
39+- 3 requests per second
40+- Burst limit: 5 requests
41+42+Noteleaf automatically manages rate limiting to stay within these boundaries.
43+44+## Book Search
45+46+Search for books from the command line:
47+48+```sh
49+noteleaf book search "Design Patterns"
50+noteleaf book search "Neal Stephenson"
51+```
52+53+Interactive selection shows:
54+55+- Title
56+- Author(s)
57+- First publication year
58+- Edition count
59+- Publisher information
60+61+## Book Metadata
62+63+When adding a book, Noteleaf fetches:
64+65+- Title
66+- Author names
67+- Publication year
68+- Edition information
69+- Subjects/genres
70+- Description (when available)
71+- Cover ID
72+73+## API Endpoints
74+75+### Search Endpoint
76+77+```
78+GET https://openlibrary.org/search.json
79+```
80+81+Parameters:
82+83+- `q`: Search query
84+- `offset`: Pagination offset
85+- `limit`: Results per page
86+- `fields`: Requested fields
87+88+### Work Endpoint
89+90+```
91+GET https://openlibrary.org/works/{work_key}.json
92+```
93+94+Returns detailed work information including authors, description, subjects, and covers.
95+96+## Data Mapping
97+98+Open Library data maps to Noteleaf book fields:
99+100+| Open Library | Noteleaf Field |
101+|--------------|----------------|
102+| title | Title |
103+| author_name | Author |
104+| first_publish_year | Notes (included) |
105+| edition_count | Notes (included) |
106+| publisher | Notes (included) |
107+| subject | Notes (included) |
108+| cover_i | Notes (cover ID) |
109+110+## Example API Response
111+112+Search result document:
113+114+```json
115+{
116+ "key": "/works/OL45804W",
117+ "title": "Design Patterns",
118+ "author_name": ["Erich Gamma", "Richard Helm"],
119+ "first_publish_year": 1994,
120+ "edition_count": 23,
121+ "isbn": ["0201633612", "9780201633610"],
122+ "publisher": ["Addison-Wesley"],
123+ "subject": ["Software design", "Object-oriented programming"],
124+ "cover_i": 8644882
125+}
126+```
127+128+## Limitations
129+130+### No Direct Page Count
131+132+Open Library doesn't consistently provide page counts in search results. Use the interactive editor to add page counts manually if needed.
133+134+### Author Keys vs Names
135+136+Work endpoints return author keys (`/authors/OL123A`) rather than full names. Noteleaf displays available author names from search results.
137+138+### Cover Images
139+140+Cover IDs are stored but not automatically downloaded. Future versions may support local cover image caching.
141+142+## Error Handling
143+144+### Network Issues
145+146+```sh
147+noteleaf book search "query"
148+# Error: failed to connect to Open Library
149+```
150+151+Check internet connection and Open Library status.
152+153+### Rate Limit Exceeded
154+155+Noteleaf automatically waits when approaching rate limits. If you see delays, this is normal behavior.
156+157+### No Results
158+159+```sh
160+noteleaf book search "very obscure title"
161+# No results found
162+```
163+164+Try:
165+166+- Different search terms
167+- Author names instead of titles
168+- ISBNs for specific editions
169+170+## API Service Architecture
171+172+Implementation in `internal/services/services.go`:
173+174+```go
175+type BookService struct {
176+ client *http.Client
177+ limiter *rate.Limiter
178+ baseURL string
179+}
180+```
181+182+Features:
183+184+- Automatic rate limiting
185+- Context-aware requests
186+- Proper error handling
187+- Timeout management (30s)
188+189+## Custom User Agent
190+191+Noteleaf identifies itself to Open Library:
192+193+```
194+User-Agent: Noteleaf/v{version} (contact: info@stormlightlabs.org)
195+```
196+197+This helps Open Library track API usage and contact developers if needed.
198+199+## Resources
200+201+- [Open Library API Documentation](https://openlibrary.org/dev/docs/api/books)
202+- [Open Library Search](https://openlibrary.org/dev/docs/api/search)
203+- [Open Library Covers](https://openlibrary.org/dev/docs/api/covers)
204+- [Rate Limiting Policy](https://openlibrary.org/developers/api)
···1+---
2+title: External Integrations
3+sidebar_label: Overview
4+sidebar_position: 1
5+description: Overview of external service integrations.
6+---
7+8+# External Integrations
9+10+Noteleaf integrates with external services to enrich your productivity workflow and extend functionality beyond local storage.
11+12+## Available Integrations
13+14+### Open Library API
15+16+Free book metadata service for building your reading list.
17+18+**Features:**
19+20+- Search books by title, author, ISBN
21+- Fetch metadata (author, year, subjects)
22+- Edition and publication information
23+- No API key required
24+25+**Use Cases:**
26+27+- Adding books to reading list
28+- Enriching book metadata
29+- Discovering related works
30+31+See [Open Library API](./openlibrary.md) for details.
32+33+### Leaflet.pub
34+35+Decentralized publishing platform built on AT Protocol.
36+37+**Features:**
38+39+- Publish notes as structured documents
40+- Pull existing documents into local notes
41+- Update published content
42+- Manage drafts and publications
43+44+**Use Cases:**
45+46+- Blog publishing from terminal
47+- Long-form content management
48+- Decentralized content ownership
49+50+See [Leaflet.pub section](../leaflet/intro.md) for details.
51+52+### AT Protocol (Bluesky)
53+54+Authentication and identity via AT Protocol network.
55+56+**Features:**
57+58+- Decentralized identity (DID)
59+- Session management
60+- Token refresh
61+- Secure authentication
62+63+**Use Cases:**
64+65+- Leaflet.pub authentication
66+- Portable identity across services
67+- Content verification
68+69+See [Authentication](../leaflet/authentication.md) for details.
70+71+## Integration Architecture
72+73+### Service Layer
74+75+External integrations live in `internal/services/`:
76+77+- `services.go` - Open Library API client
78+- `atproto.go` - AT Protocol authentication
79+- `http.go` - HTTP utilities and rate limiting
80+81+### Rate Limiting
82+83+All external services use rate limiting to respect API quotas:
84+85+- Open Library: 3 requests/second
86+- AT Protocol: Per PDS configuration
87+88+Rate limiters are built-in and automatic.
89+90+### Error Handling
91+92+Services implement consistent error handling:
93+94+- Network errors
95+- Rate limit exceeded
96+- Authentication failures
97+- Invalid responses
98+99+Errors propagate to user with actionable messages.
100+101+## Configuration
102+103+Integration configuration in `.noteleaf.conf.toml`:
104+105+```toml
106+# Open Library (no configuration needed)
107+# book_api_key = "" # Reserved for future use
108+109+# AT Protocol / Leaflet.pub
110+atproto_handle = "username.bsky.social"
111+atproto_did = "did:plc:..."
112+atproto_pds_url = "https://bsky.social"
113+atproto_access_jwt = "..."
114+atproto_refresh_jwt = "..."
115+```
116+117+See [Configuration](../Configuration.md) for all options.
118+119+## Offline Support
120+121+Noteleaf works fully offline for local data. Integrations are optional enhancements:
122+123+- Books can be added manually without Open Library
124+- Notes exist locally without Leaflet.pub
125+- Tasks and media work without any external service
126+127+External services enhance but don't require connectivity.
128+129+## Privacy and Data
130+131+### Data Sent
132+133+**Open Library:**
134+135+- Search queries
136+- Work/edition IDs
137+138+**AT Protocol:**
139+140+- Handle/DID
141+- Published note content
142+- Authentication credentials
143+144+### Data Stored Locally
145+146+- API responses (cached)
147+- Session tokens
148+- Publication metadata
149+150+### No Tracking
151+152+Noteleaf does not:
153+154+- Track usage
155+- Send analytics
156+- Share data with third parties
157+- Require accounts (except for publishing)
158+159+## Resources
160+161+- [Open Library API Documentation](https://openlibrary.org/developers/api)
162+- [AT Protocol Docs](https://atproto.com)
163+- [Leaflet.pub](https://leaflet.pub)
164+- [Bluesky](https://bsky.app)
-47
website/docs/intro.md
···1----
2-sidebar_position: 1
3----
4-5-# Tutorial Intro
6-7-Let's discover **Docusaurus in less than 5 minutes**.
8-9-## Getting Started
10-11-Get started by **creating a new site**.
12-13-Or **try Docusaurus immediately** with **[docusaurus.new](https://docusaurus.new)**.
14-15-### What you'll need
16-17-- [Node.js](https://nodejs.org/en/download/) version 20.0 or above:
18- - When installing Node.js, you are recommended to check all checkboxes related to dependencies.
19-20-## Generate a new site
21-22-Generate a new Docusaurus site using the **classic template**.
23-24-The classic template will automatically be added to your project after you run the command:
25-26-```bash
27-npm init docusaurus@latest my-website classic
28-```
29-30-You can type this command into Command Prompt, Powershell, Terminal, or any other integrated terminal of your code editor.
31-32-The command also installs all necessary dependencies you need to run Docusaurus.
33-34-## Start your site
35-36-Run the development server:
37-38-```bash
39-cd my-website
40-npm run start
41-```
42-43-The `cd` command changes the directory you're working with. In order to work with your newly created Docusaurus site, you'll need to navigate the terminal there.
44-45-The `npm run start` command builds your website locally and serves it through a development server, ready for you to view at http://localhost:3000/.
46-47-Open `docs/intro.md` (this page) and edit some lines: the site **reloads automatically** and displays your changes.
···1+{
2+ "label": "Leaflet Publishing",
3+ "position": 5,
4+ "link": {
5+ "type": "generated-index",
6+ "title": "Leaflet Publishing",
7+ "description": "Publish and sync documents with leaflet.pub and the AT Protocol."
8+ }
9+}
+41
website/docs/leaflet/authentication.md
···00000000000000000000000000000000000000000
···1+---
2+title: Authentication and Identity
3+sidebar_label: Auth & Identity
4+description: AT Protocol authentication, security, and session handling.
5+sidebar_position: 8
6+---
7+8+# Authentication and Identity
9+10+## AT Protocol Authentication
11+12+Noteleaf uses AT Protocol's authentication system:
13+14+1. **Handle Resolution**: Your handle (e.g., `username.bsky.social`) is resolved to a DID (Decentralized Identifier)
15+2. **Session Creation**: Authenticate with your app password to create a session
16+3. **Session Token**: Noteleaf stores the session token for future requests
17+4. **Token Refresh**: Sessions are refreshed automatically when they expire
18+19+## Security Considerations
20+21+**Use app passwords**: Never use your main BlueSky password with third-party tools. App passwords can be revoked without affecting your account.
22+23+**Token storage**: Session tokens are stored locally in the Noteleaf database. Protect your database file.
24+25+**Revocation**: If compromised, revoke the app password at [bsky.app/settings/app-passwords](https://bsky.app/settings/app-passwords).
26+27+## Session Management
28+29+**Check status**:
30+31+```sh
32+noteleaf pub status
33+```
34+35+**Re-authenticate**:
36+37+```sh
38+noteleaf pub auth
39+```
40+41+Sessions typically last 2-4 hours before requiring refresh. Noteleaf handles refresh automatically, but if authentication fails, run `pub auth` again.
···1+---
2+title: Getting Started with Leaflet
3+sidebar_label: Getting Started
4+description: Prerequisites, app passwords, and authentication commands.
5+sidebar_position: 2
6+---
7+8+# Getting Started with Leaflet
9+10+## Prerequisites
11+12+- Noteleaf installed and configured
13+- A BlueSky & [Leaflet](https://leaflet.pub) account (create at [bsky.app](https://bsky.app))
14+- App password for authentication
15+16+## Creating an App Password
17+18+For security, Noteleaf uses app passwords instead of your main BlueSky password:
19+20+1. Go to [bsky.app/settings/app-passwords](https://bsky.app/settings/app-passwords)
21+2. Click "Add App Password"
22+3. Name it "noteleaf" or similar
23+4. Copy the generated password (you won't see it again)
24+25+### Authentication
26+27+Authenticate with your BlueSky handle and app password:
28+29+```sh
30+noteleaf pub auth username.bsky.social
31+```
32+33+You'll be prompted for the app password. Alternatively, provide it via flag:
34+35+```sh
36+noteleaf pub auth username.bsky.social --password <app-password>
37+```
38+39+**Re-authentication**: If your session expires, run `pub auth` again. Noteleaf remembers your last authenticated handle, so you can just run:
40+41+```sh
42+noteleaf pub auth
43+```
44+45+### Check Authentication Status
46+47+Verify you're authenticated:
48+49+```sh
50+noteleaf pub status
51+```
52+53+Shows your handle and session state.
+36
website/docs/leaflet/intro.md
···000000000000000000000000000000000000
···1+---
2+title: Leaflet.pub Introduction
3+sidebar_label: Introduction
4+description: Understand leaflet.pub and how Noteleaf integrates with it.
5+sidebar_position: 1
6+---
7+8+# Leaflet.pub Introduction
9+10+## What is Leaflet.pub?
11+12+[Leaflet.pub](https://leaflet.pub) is a decentralized publishing platform built on the AT Protocol (the same protocol that powers BlueSky). It allows you to publish long-form content as structured documents while maintaining ownership and control of your data through decentralized identity.
13+14+## AT Protocol and Decentralized Publishing
15+16+AT Protocol provides:
17+18+**Portable Identity**: Your identity (DID) is separate from any single service. You own your content and can move it between providers.
19+20+**Verifiable Data**: All documents are content-addressed and cryptographically signed, ensuring authenticity and preventing tampering.
21+22+**Interoperability**: Content published to leaflet.pub can be discovered and consumed by any AT Protocol-compatible client.
23+24+**Decentralized Storage**: Data is stored in personal data repositories (PDSs) under your control, not locked in a proprietary platform.
25+26+## How Noteleaf Integrates with Leaflet
27+28+Noteleaf can act as a leaflet.pub client, allowing you to:
29+30+1. **Authenticate** with your BlueSky/AT Protocol identity
31+2. **Pull** existing documents from leaflet.pub into local notes
32+3. **Publish** local notes as new leaflet documents
33+4. **Update** previously published documents with changes
34+5. **Manage** drafts and published content from the command line
35+36+This integration lets you write locally in markdown, manage content alongside tasks and research notes, and publish to a decentralized platform when ready.
···1+---
2+title: Listing and Reading Publications
3+sidebar_label: Listing & Reading
4+description: Browse leaflet-backed notes and read content locally.
5+sidebar_position: 7
6+---
7+8+# Listing and Reading Publications
9+10+## List Published Documents
11+12+**All leaflet-synced notes**:
13+14+```sh
15+noteleaf pub list
16+```
17+18+**Only published documents**:
19+20+```sh
21+noteleaf pub list --published
22+```
23+24+**Only drafts**:
25+26+```sh
27+noteleaf pub list --draft
28+```
29+30+**Interactive browser**:
31+32+```sh
33+noteleaf pub list --interactive
34+```
35+36+Navigate with arrow keys, press Enter to read, `q` to quit.
37+38+## Reading a Publication
39+40+**Read specific document**:
41+42+```sh
43+noteleaf pub read 123
44+```
45+46+The identifier can be:
47+48+- Note ID (e.g., `123`)
49+- Leaflet record key (rkey, e.g., `3jxx...`)
50+51+**Read newest publication**:
52+53+```sh
54+noteleaf pub read
55+```
56+57+Omitting the identifier shows the most recently published document.
+16
website/docs/leaflet/publications.md
···0000000000000000
···1+---
2+title: Leaflet Publications
3+sidebar_label: Publications
4+description: How publications work and how Noteleaf interacts with them.
5+sidebar_position: 3
6+---
7+8+# Leaflet Publications
9+10+## What is a Publication?
11+12+In leaflet.pub, a publication is a collection of documents. While Noteleaf doesn't support management commands, documents you create are associated with your default publication.
13+14+Future versions may support:
15+16+- Switching between publications
···1+---
2+title: Leaflet Rich Text and Blocks
3+sidebar_label: Rich Text
4+description: How markdown maps to leaflet blocks and formatting.
5+sidebar_position: 5
6+---
7+8+# Leaflet Rich Text and Blocks
9+10+## Document Structure
11+12+Leaflet documents consist of blocksโdiscrete content units:
13+14+**Text Blocks**: Paragraphs of formatted text
15+**Header Blocks**: Section titles (level 1-6)
16+**Code Blocks**: Syntax-highlighted code with language annotation
17+**Quote Blocks**: Blockquotes for citations
18+**List Blocks**: Ordered or unordered lists
19+**Rule Blocks**: Horizontal rules for visual separation
20+21+## Text Formatting
22+23+Text within blocks can have inline formatting called facets:
24+25+**Bold**: `**bold text**` โ Bold facet
26+**Italic**: `*italic text*` โ Italic facet
27+**Code**: `` `inline code` `` โ Code facet
28+**Links**: `[text](url)` โ Link facet with URL
29+**Strikethrough**: `~~struck~~` โ Strikethrough facet
30+31+Multiple formats can be combined:
32+33+```markdown
34+**bold and *italic* text with [a link](https://example.com)**
35+```
36+37+## Code Blocks
38+39+Code blocks preserve language information for syntax highlighting:
40+41+````markdown
42+```python
43+def hello():
44+ print("Hello, leaflet!")
45+```
46+````
47+48+Converts to a code block with language="python".
49+50+Supported languages: Any language identifier is preserved, but rendering depends on leaflet.pub's syntax highlighter support.
51+52+## Blockquotes
53+54+Markdown blockquotes become quote blocks:
55+56+```markdown
57+> This is a quote from another source.
58+> It can span multiple lines.
59+```
60+61+Nested blockquotes are flattened (leaflet doesn't support nesting).
62+63+## Lists
64+65+Both ordered and unordered lists are supported:
66+67+```markdown
68+- Unordered item 1
69+- Unordered item 2
70+ - Nested item
71+72+1. Ordered item 1
73+2. Ordered item 2
74+ 1. Nested ordered item
75+```
76+77+Nesting is preserved up to leaflet's limits.
78+79+## Horizontal Rules
80+81+Markdown horizontal rules become rule blocks:
82+83+```markdown
84+---
85+```
86+87+Use for section breaks.
88+89+## Images and Media
90+91+**Current status**: Image support is not yet implemented in the Noteleaf-to-leaflet converter.
92+93+**Future plans**: Images will be uploaded to blob storage and embedded in documents with image blocks.
94+95+**Workaround**: For now, images in markdown are either skipped or converted to links.
···1+---
2+title: Publishing Workflow
3+sidebar_label: Workflow
4+description: Post, patch, drafts, pulling, and syncing documents.
5+sidebar_position: 4
6+---
7+8+# Publishing Workflow
9+10+## Converting Notes to Leaflet Documents
11+12+Noteleaf converts markdown notes to leaflet's rich text block format:
13+14+**Supported Markdown Features**:
15+16+- Headers (`#`, `##`, `###`, etc.)
17+- Paragraphs
18+- Bold (`**bold**`)
19+- Italic (`*italic*`)
20+- Code (`inline code`)
21+- Strikethrough (`~~text~~`)
22+- Links (`[text](url)`)
23+- Code blocks (` ```language ... ``` `)
24+- Blockquotes (`> quote`)
25+- Lists (ordered and unordered)
26+- Horizontal rules (`---`)
27+28+**Conversion Process**:
29+30+1. Parse markdown into AST (abstract syntax tree)
31+2. Convert AST nodes to leaflet block records
32+3. Process text formatting into facets
33+4. Validate document structure
34+5. Upload to leaflet.pub via AT Protocol
35+36+## Creating a New Document
37+38+Publish a local note as a new leaflet document:
39+40+```sh
41+noteleaf pub post 123
42+```
43+44+This:
45+46+1. Converts the note to leaflet format
47+2. Creates a new document on leaflet.pub
48+3. Links the note to the document (stores the rkey)
49+4. Marks the note as published
50+51+**Create as draft**:
52+53+```sh
54+noteleaf pub post 123 --draft
55+```
56+57+Drafts are saved to leaflet but not publicly visible until you publish them.
58+59+**Preview before posting**:
60+61+```sh
62+noteleaf pub post 123 --preview
63+```
64+65+Shows what the document will look like without actually posting.
66+67+**Validate conversion**:
68+69+```sh
70+noteleaf pub post 123 --validate
71+```
72+73+Checks if the markdown converts correctly to leaflet format without posting.
74+75+**Save to file**:
76+77+```sh
78+noteleaf pub post 123 --preview --output document.json
79+noteleaf pub post 123 --preview --output document.txt --plaintext
80+```
81+82+## Updating Published Documents
83+84+Update an existing leaflet document from a local note:
85+86+```sh
87+noteleaf pub patch 123
88+```
89+90+Requirements:
91+92+- Note must have been previously posted or pulled from leaflet
93+- Note must have a leaflet record key (rkey) in the database
94+95+**Preserve draft/published status**: The `patch` command maintains the document's current status. If it's published, it stays published. If it's a draft, it stays a draft.
96+97+**Preview changes**:
98+99+```sh
100+noteleaf pub patch 123 --preview
101+```
102+103+**Validate before patching**:
104+105+```sh
106+noteleaf pub patch 123 --validate
107+```
108+109+## Managing Drafts
110+111+**Create as draft**:
112+113+```sh
114+noteleaf pub post 123 --draft
115+```
116+117+**Update draft**:
118+119+```sh
120+noteleaf pub patch 123
121+```
122+123+**List drafts**:
124+125+```sh
126+noteleaf pub list --draft
127+```
128+129+**Publish a draft**: Edit the draft on leaflet.pub or use the API to change status (command support coming in future versions).
130+131+## Pulling Documents from Leaflet
132+133+Sync leaflet documents to local notes:
134+135+```sh
136+noteleaf pub pull
137+```
138+139+This:
140+141+1. Authenticates with leaflet.pub
142+2. Fetches all documents in your repository
143+3. Creates new notes for documents not yet synced
144+4. Updates existing notes that have changed
145+146+**Matching logic**: Notes are matched to leaflet documents by their record key (rkey) stored in the database.
147+If a document doesn't have a corresponding note, a new one is created. If it does, the note is updated only if the content has changed (using CID for change detection).
···1----
2-id: articles
3-title: Articles
4-sidebar_position: 3
5-description: Save and archive web articles
6----
7-8-## article
9-10-Save and archive web articles locally.
11-12-Parse articles from supported websites, extract clean content, and save as
13-both markdown and HTML. Maintains a searchable archive of articles with
14-metadata including author, title, and publication date.
15-16-```bash
17-noteleaf article
18-```
19-20-### Subcommands
21-22-#### add
23-24-Parse and save article content from a supported website.
25-26-The article will be parsed using domain-specific XPath rules and saved
27-as both Markdown and HTML files. Article metadata is stored in the database.
28-29-**Usage:**
30-31-```bash
32-noteleaf article add <url>
33-```
34-35-#### list
36-37-List saved articles with optional filtering.
38-39-Use query to filter by title, or use flags for more specific filtering.
40-41-**Usage:**
42-43-```bash
44-noteleaf article list [query] [flags]
45-```
46-47-**Options:**
48-49-```
50- --author string Filter by author
51- -l, --limit int Limit number of results (0 = no limit)
52-```
53-54-**Aliases:** ls
55-56-#### view
57-58-Display article metadata and summary.
59-60-Shows article title, author, publication date, URL, and a brief content
61-preview. Use 'read' command to view the full article content.
62-63-**Usage:**
64-65-```bash
66-noteleaf article view <id>
67-```
68-69-**Aliases:** show
70-71-#### read
72-73-Read the full markdown content of an article with beautiful formatting.
74-75-This displays the complete article content using syntax highlighting and proper formatting.
76-77-**Usage:**
78-79-```bash
80-noteleaf article read <id>
81-```
82-83-#### remove
84-85-Delete an article and its files permanently.
86-87-Removes the article metadata from the database and deletes associated markdown
88-and HTML files. This operation cannot be undone.
89-90-**Usage:**
91-92-```bash
93-noteleaf article remove <id>
94-```
95-96-**Aliases:** rm, delete
97-
···1----
2-id: books
3-title: Books
4-sidebar_position: 4
5-description: Manage reading list and track progress
6----
7-8-## book
9-10-Track books and reading progress.
11-12-Search Google Books API to add books to your reading list. Track which books
13-you're reading, update progress percentages, and maintain a history of finished
14-books.
15-16-```bash
17-noteleaf media book
18-```
19-20-### Subcommands
21-22-#### add
23-24-Search for books and add them to your reading list.
25-26-By default, shows search results in a simple list format where you can select by number.
27-Use the -i flag for an interactive interface with navigation keys.
28-29-**Usage:**
30-31-```bash
32-noteleaf media book add [search query...] [flags]
33-```
34-35-**Options:**
36-37-```
38- -i, --interactive Use interactive interface for book selection
39-```
40-41-#### list
42-43-Display books in your reading list with progress indicators.
44-45-Shows book titles, authors, and reading progress percentages. Filter by --all,
46---reading for books in progress, --finished for completed books, or --queued
47-for books not yet started. Default shows queued books only.
48-49-**Usage:**
50-51-```bash
52-noteleaf media book list [--all|--reading|--finished|--queued]
53-```
54-55-#### reading
56-57-Mark a book as currently reading. Use this when you start a book from your queue.
58-59-**Usage:**
60-61-```bash
62-noteleaf media book reading <id>
63-```
64-65-#### finished
66-67-Mark a book as finished with current timestamp. Sets reading progress to 100%.
68-69-**Usage:**
70-71-```bash
72-noteleaf media book finished <id>
73-```
74-75-**Aliases:** read
76-77-#### remove
78-79-Remove a book from your reading list. Use this for books you no longer want to track.
80-81-**Usage:**
82-83-```bash
84-noteleaf media book remove <id>
85-```
86-87-**Aliases:** rm
88-89-#### progress
90-91-Set reading progress for a book.
92-93-Specify a percentage value between 0 and 100 to indicate how far you've
94-progressed through the book. Automatically updates status to 'reading' if not
95-already set.
96-97-**Usage:**
98-99-```bash
100-noteleaf media book progress <id> <percentage>
101-```
102-103-#### update
104-105-Change a book's status directly.
106-107-Valid statuses are: queued (not started), reading (in progress), finished
108-(completed), or removed (no longer tracking).
109-110-**Usage:**
111-112-```bash
113-noteleaf media book update <id> <status>
114-```
115-
···1----
2-id: index
3-title: CLI Reference
4-sidebar_label: Overview
5-sidebar_position: 0
6-description: Complete command-line reference for noteleaf
7----
8-9-# noteleaf CLI Reference
10-11-noteleaf - personal information manager for the command line
12-13-A comprehensive CLI tool for managing tasks, notes, articles, and media queues.
14-Inspired by TaskWarrior, noteleaf combines todo management with reading lists,
15-watch queues, and a personal knowledge base.
16-17-Core features include hierarchical tasks with dependencies, recurring tasks,
18-time tracking, markdown notes with tags, article archiving, and media queue
19-management for books, movies, and TV shows.
20-21-## Usage
22-23-```bash
24-noteleaf
25-```
26-27-## Command Groups
28-29-- **[Task Management](tasks)** - Manage todos, projects, and time tracking
30-- **[Notes](notes)** - Create and organize markdown notes
31-- **[Articles](articles)** - Save and archive web articles
32-- **[Books](books)** - Track reading list and progress
33-- **[Movies](movies)** - Manage movie watch queue
34-- **[TV Shows](tv-shows)** - Track TV show watching
35-- **[Configuration](configuration)** - Manage settings
36-- **[Management](management)** - Application management
37-
···0000000000000000000000000000000000000
-61
website/docs/manual/management.md
···1----
2-id: management
3-title: Management
4-sidebar_position: 8
5-description: Application management commands
6----
7-8-## status
9-10-Display comprehensive application status information.
11-12-Shows database location, configuration file path, data directories, and current
13-settings. Use this command to verify your noteleaf installation and diagnose
14-configuration issues.
15-16-```bash
17-noteleaf status
18-```
19-20-## setup
21-22-Initialize noteleaf for first use.
23-24-Creates the database, configuration file, and required data directories. Run
25-this command after installing noteleaf or when setting up a new environment.
26-Safe to run multiple times as it will skip existing resources.
27-28-```bash
29-noteleaf setup
30-```
31-32-### Subcommands
33-34-#### seed
35-36-Add sample tasks, books, and notes to the database for testing and demonstration purposes
37-38-**Usage:**
39-40-```bash
41-noteleaf setup seed [flags]
42-```
43-44-**Options:**
45-46-```
47- -f, --force Clear existing data and re-seed
48-```
49-50-## reset
51-52-Remove all application data and return to initial state.
53-54-This command deletes the database, all media files, notes, and articles. The
55-configuration file is preserved. Use with caution as this operation cannot be
56-undone. You will be prompted for confirmation before deletion proceeds.
57-58-```bash
59-noteleaf reset
60-```
61-
···1----
2-id: movies
3-title: Movies
4-sidebar_position: 5
5-description: Track movies in watch queue
6----
7-8-## movie
9-10-Track movies you want to watch.
11-12-Search TMDB for movies and add them to your queue. Mark movies as watched when
13-completed. Maintains a history of your movie watching activity.
14-15-```bash
16-noteleaf media movie
17-```
18-19-### Subcommands
20-21-#### add
22-23-Search for movies and add them to your watch queue.
24-25-By default, shows search results in a simple list format where you can select by number.
26-Use the -i flag for an interactive interface with navigation keys.
27-28-**Usage:**
29-30-```bash
31-noteleaf media movie add [search query...] [flags]
32-```
33-34-**Options:**
35-36-```
37- -i, --interactive Use interactive interface for movie selection
38-```
39-40-#### list
41-42-Display movies in your queue with optional status filters.
43-44-Shows movie titles, release years, and current status. Filter by --all to show
45-everything, --watched for completed movies, or --queued for unwatched items.
46-Default shows queued movies only.
47-48-**Usage:**
49-50-```bash
51-noteleaf media movie list [--all|--watched|--queued]
52-```
53-54-#### watched
55-56-Mark a movie as watched with current timestamp. Moves the movie from queued to watched status.
57-58-**Usage:**
59-60-```bash
61-noteleaf media movie watched [id]
62-```
63-64-**Aliases:** seen
65-66-#### remove
67-68-Remove a movie from your watch queue. Use this for movies you no longer want to track.
69-70-**Usage:**
71-72-```bash
73-noteleaf media movie remove [id]
74-```
75-76-**Aliases:** rm
77-
···1----
2-id: notes
3-title: Notes
4-sidebar_position: 2
5-description: Create and organize markdown notes
6----
7-8-## note
9-10-Create and organize markdown notes with tags.
11-12-Write notes in markdown format, organize them with tags, browse them in an
13-interactive TUI, and edit them in your preferred editor. Notes are stored as
14-files on disk with metadata tracked in the database.
15-16-```bash
17-noteleaf note
18-```
19-20-### Subcommands
21-22-#### create
23-24-Create a new markdown note.
25-26-Provide a title and optional content inline, or use --interactive to open an
27-editor. Use --file to import content from an existing markdown file. Notes
28-support tags for organization and full-text search.
29-30-Examples:
31- noteleaf note create "Meeting notes" "Discussed project timeline"
32- noteleaf note create -i
33- noteleaf note create --file ~/documents/draft.md
34-35-**Usage:**
36-37-```bash
38-noteleaf note create [title] [content...] [flags]
39-```
40-41-**Options:**
42-43-```
44- -e, --editor Prompt to open note in editor after creation
45- -f, --file string Create note from markdown file
46- -i, --interactive Open interactive editor
47-```
48-49-**Aliases:** new
50-51-#### list
52-53-Opens interactive TUI browser for navigating and viewing notes
54-55-**Usage:**
56-57-```bash
58-noteleaf note list [--archived] [--static] [--tags=tag1,tag2] [flags]
59-```
60-61-**Options:**
62-63-```
64- -a, --archived Show archived notes
65- -s, --static Show static list instead of interactive TUI
66- --tags string Filter by tags (comma-separated)
67-```
68-69-**Aliases:** ls
70-71-#### read
72-73-Display note content with formatted markdown rendering.
74-75-Shows the note with syntax highlighting, proper formatting, and metadata.
76-Useful for quick viewing without opening an editor.
77-78-**Usage:**
79-80-```bash
81-noteleaf note read [note-id]
82-```
83-84-**Aliases:** view
85-86-#### edit
87-88-Open note in your configured text editor.
89-90-Uses the editor specified in your noteleaf configuration or the EDITOR
91-environment variable. Changes are automatically saved when you close the
92-editor.
93-94-**Usage:**
95-96-```bash
97-noteleaf note edit [note-id]
98-```
99-100-#### remove
101-102-Delete a note permanently.
103-104-Removes both the markdown file and database metadata. This operation cannot be
105-undone. You will be prompted for confirmation before deletion.
106-107-**Usage:**
108-109-```bash
110-noteleaf note remove [note-id]
111-```
112-113-**Aliases:** rm, delete, del
114-
···1----
2-id: task-management
3-title: Task Management
4-sidebar_position: 1
5-description: Manage tasks with TaskWarrior-inspired features
6----
7-8-## todo
9-10-Manage tasks with TaskWarrior-inspired features.
11-12-Track todos with priorities, projects, contexts, and tags. Supports hierarchical
13-tasks with parent/child relationships, task dependencies, recurring tasks, and
14-time tracking. Tasks can be filtered by status, priority, project, or context.
15-16-```bash
17-noteleaf todo
18-```
19-20-### Subcommands
21-22-#### add
23-24-Create a new task with description and optional attributes.
25-26-Tasks can be created with priority levels (low, medium, high, urgent), assigned
27-to projects and contexts, tagged for organization, and configured with due dates
28-and recurrence rules. Dependencies can be established to ensure tasks are
29-completed in order.
30-31-Examples:
32- noteleaf todo add "Write documentation" --priority high --project docs
33- noteleaf todo add "Weekly review" --recur "FREQ=WEEKLY" --due 2024-01-15
34-35-**Usage:**
36-37-```bash
38-noteleaf todo add [description] [flags]
39-```
40-41-**Options:**
42-43-```
44- -c, --context string Set task context
45- --depends-on string Set task dependencies (comma-separated UUIDs)
46- -d, --due string Set due date (YYYY-MM-DD)
47- --parent string Set parent task UUID
48- -p, --priority string Set task priority
49- --project string Set task project
50- --recur string Set recurrence rule (e.g., FREQ=DAILY)
51- -t, --tags strings Add tags to task
52- --until string Set recurrence end date (YYYY-MM-DD)
53-```
54-55-**Aliases:** create, new
56-57-#### list
58-59-List tasks with optional filtering and display modes.
60-61-By default, shows tasks in an interactive TaskWarrior-like interface.
62-Use --static to show a simple text list instead.
63-Use --all to show all tasks, otherwise only pending tasks are shown.
64-65-**Usage:**
66-67-```bash
68-noteleaf todo list [flags]
69-```
70-71-**Options:**
72-73-```
74- -a, --all Show all tasks (default: pending only)
75- --context string Filter by context
76- -i, --interactive Force interactive mode (default)
77- --priority string Filter by priority
78- --project string Filter by project
79- --static Use static text output instead of interactive
80- --status string Filter by status
81-```
82-83-**Aliases:** ls
84-85-#### view
86-87-Display detailed information for a specific task.
88-89-Shows all task attributes including description, status, priority, project,
90-context, tags, due date, creation time, and modification history. Use --json
91-for machine-readable output or --no-metadata to show only the description.
92-93-**Usage:**
94-95-```bash
96-noteleaf todo view [task-id] [flags]
97-```
98-99-**Options:**
100-101-```
102- --format string Output format (detailed, brief) (default "detailed")
103- --json Output as JSON
104- --no-metadata Hide creation/modification timestamps
105-```
106-107-#### update
108-109-Modify attributes of an existing task.
110-111-Update any task property including description, status, priority, project,
112-context, due date, recurrence rule, or parent task. Add or remove tags and
113-dependencies. Multiple attributes can be updated in a single command.
114-115-Examples:
116- noteleaf todo update 123 --priority urgent --due tomorrow
117- noteleaf todo update 456 --add-tag urgent --project website
118-119-**Usage:**
120-121-```bash
122-noteleaf todo update [task-id] [flags]
123-```
124-125-**Options:**
126-127-```
128- --add-depends string Add task dependencies (comma-separated UUIDs)
129- --add-tag strings Add tags to task
130- -c, --context string Set task context
131- --description string Update task description
132- -d, --due string Set due date (YYYY-MM-DD)
133- --parent string Set parent task UUID
134- -p, --priority string Set task priority
135- --project string Set task project
136- --recur string Set recurrence rule (e.g., FREQ=DAILY)
137- --remove-depends string Remove task dependencies (comma-separated UUIDs)
138- --remove-tag strings Remove tags from task
139- --status string Update task status
140- -t, --tags strings Add tags to task
141- --until string Set recurrence end date (YYYY-MM-DD)
142-```
143-144-#### edit
145-146-Open interactive editor for task modification.
147-148-Provides a user-friendly interface with status picker and priority toggle.
149-Easier than using multiple command-line flags for complex updates.
150-151-**Usage:**
152-153-```bash
154-noteleaf todo edit [task-id]
155-```
156-157-**Aliases:** e
158-159-#### delete
160-161-Permanently remove a task from the database.
162-163-This operation cannot be undone. Consider updating the task status to
164-'deleted' instead if you want to preserve the record for historical purposes.
165-166-**Usage:**
167-168-```bash
169-noteleaf todo delete [task-id]
170-```
171-172-#### projects
173-174-Display all projects with task counts.
175-176-Shows each project used in your tasks along with the number of tasks in each
177-project. Use --todo-txt to format output with +project syntax for compatibility
178-with todo.txt tools.
179-180-**Usage:**
181-182-```bash
183-noteleaf todo projects [flags]
184-```
185-186-**Options:**
187-188-```
189- --static Use static text output instead of interactive
190- --todo-txt Format output with +project prefix for todo.txt compatibility
191-```
192-193-**Aliases:** proj
194-195-#### tags
196-197-Display all tags used across tasks.
198-199-Shows each tag with the number of tasks using it. Tags provide flexible
200-categorization orthogonal to projects and contexts.
201-202-**Usage:**
203-204-```bash
205-noteleaf todo tags [flags]
206-```
207-208-**Options:**
209-210-```
211- --static Use static text output instead of interactive
212-```
213-214-**Aliases:** t
215-216-#### contexts
217-218-Display all contexts with task counts.
219-220-Contexts represent locations or environments where tasks can be completed (e.g.,
221-@home, @office, @errands). Use --todo-txt to format output with @context syntax
222-for compatibility with todo.txt tools.
223-224-**Usage:**
225-226-```bash
227-noteleaf todo contexts [flags]
228-```
229-230-**Options:**
231-232-```
233- --static Use static text output instead of interactive
234- --todo-txt Format output with @context prefix for todo.txt compatibility
235-```
236-237-**Aliases:** con, loc, ctx, locations
238-239-#### done
240-241-Mark a task as completed with current timestamp.
242-243-Sets the task status to 'completed' and records the completion time. For
244-recurring tasks, generates the next instance based on the recurrence rule.
245-246-**Usage:**
247-248-```bash
249-noteleaf todo done [task-id]
250-```
251-252-**Aliases:** complete
253-254-#### start
255-256-Begin tracking time spent on a task.
257-258-Records the start time for a work session. Only one task can be actively
259-tracked at a time. Use --note to add a description of what you're working on.
260-261-**Usage:**
262-263-```bash
264-noteleaf todo start [task-id] [flags]
265-```
266-267-**Options:**
268-269-```
270- -n, --note string Add a note to the time entry
271-```
272-273-#### stop
274-275-End time tracking for the active task.
276-277-Records the end time and calculates duration for the current work session.
278-Duration is added to the task's total time tracked.
279-280-**Usage:**
281-282-```bash
283-noteleaf todo stop [task-id]
284-```
285-286-#### timesheet
287-288-Show time tracking summary for tasks.
289-290-By default shows time entries for the last 7 days.
291-Use --task to show timesheet for a specific task.
292-Use --days to change the date range.
293-294-**Usage:**
295-296-```bash
297-noteleaf todo timesheet [flags]
298-```
299-300-**Options:**
301-302-```
303- -d, --days int Number of days to show in timesheet (default 7)
304- -t, --task string Show timesheet for specific task ID
305-```
306-307-#### recur
308-309-Configure recurring task patterns.
310-311-Create tasks that repeat on a schedule using iCalendar recurrence rules (RRULE).
312-Supports daily, weekly, monthly, and yearly patterns with optional end dates.
313-314-**Usage:**
315-316-```bash
317-noteleaf todo recur
318-```
319-320-**Aliases:** repeat
321-322-##### set
323-324-Apply a recurrence rule to create repeating task instances.
325-326-Uses iCalendar RRULE syntax (e.g., "FREQ=DAILY" for daily tasks, "FREQ=WEEKLY;BYDAY=MO,WE,FR"
327-for specific weekdays). When a recurring task is completed, the next instance is
328-automatically generated.
329-330-Examples:
331- noteleaf todo recur set 123 --rule "FREQ=DAILY"
332- noteleaf todo recur set 456 --rule "FREQ=WEEKLY;BYDAY=MO" --until 2024-12-31
333-334-**Usage:**
335-336-```bash
337-noteleaf todo recur set [task-id] [flags]
338-```
339-340-**Options:**
341-342-```
343- --rule string Recurrence rule (e.g., FREQ=DAILY)
344- --until string Recurrence end date (YYYY-MM-DD)
345-```
346-347-##### clear
348-349-Remove recurrence from a task.
350-351-Converts a recurring task to a one-time task. Existing future instances are not
352-affected.
353-354-**Usage:**
355-356-```bash
357-noteleaf todo recur clear [task-id]
358-```
359-360-##### show
361-362-Display recurrence rule and schedule information.
363-364-Shows the RRULE pattern, next occurrence date, and recurrence end date if
365-configured.
366-367-**Usage:**
368-369-```bash
370-noteleaf todo recur show [task-id]
371-```
372-373-#### depend
374-375-Create and manage task dependencies.
376-377-Establish relationships where one task must be completed before another can
378-begin. Useful for multi-step workflows and project management.
379-380-**Usage:**
381-382-```bash
383-noteleaf todo depend
384-```
385-386-**Aliases:** dep, deps
387-388-##### add
389-390-Make a task dependent on another task's completion.
391-392-The first task cannot be started until the second task is completed. Use task
393-UUIDs to specify dependencies.
394-395-**Usage:**
396-397-```bash
398-noteleaf todo depend add [task-id] [depends-on-uuid]
399-```
400-401-##### remove
402-403-Delete a dependency relationship between two tasks.
404-405-**Usage:**
406-407-```bash
408-noteleaf todo depend remove [task-id] [depends-on-uuid]
409-```
410-411-**Aliases:** rm
412-413-##### list
414-415-Show all tasks that must be completed before this task can be started.
416-417-**Usage:**
418-419-```bash
420-noteleaf todo depend list [task-id]
421-```
422-423-**Aliases:** ls
424-425-##### blocked-by
426-427-Display all tasks that depend on this task's completion.
428-429-**Usage:**
430-431-```bash
432-noteleaf todo depend blocked-by [task-id]
433-```
434-435-## todo
436-437-Manage tasks with TaskWarrior-inspired features.
438-439-Track todos with priorities, projects, contexts, and tags. Supports hierarchical
440-tasks with parent/child relationships, task dependencies, recurring tasks, and
441-time tracking. Tasks can be filtered by status, priority, project, or context.
442-443-```bash
444-noteleaf todo
445-```
446-447-### Subcommands
448-449-#### add
450-451-Create a new task with description and optional attributes.
452-453-Tasks can be created with priority levels (low, medium, high, urgent), assigned
454-to projects and contexts, tagged for organization, and configured with due dates
455-and recurrence rules. Dependencies can be established to ensure tasks are
456-completed in order.
457-458-Examples:
459- noteleaf todo add "Write documentation" --priority high --project docs
460- noteleaf todo add "Weekly review" --recur "FREQ=WEEKLY" --due 2024-01-15
461-462-**Usage:**
463-464-```bash
465-noteleaf todo add [description] [flags]
466-```
467-468-**Options:**
469-470-```
471- -c, --context string Set task context
472- --depends-on string Set task dependencies (comma-separated UUIDs)
473- -d, --due string Set due date (YYYY-MM-DD)
474- --parent string Set parent task UUID
475- -p, --priority string Set task priority
476- --project string Set task project
477- --recur string Set recurrence rule (e.g., FREQ=DAILY)
478- -t, --tags strings Add tags to task
479- --until string Set recurrence end date (YYYY-MM-DD)
480-```
481-482-**Aliases:** create, new
483-484-#### list
485-486-List tasks with optional filtering and display modes.
487-488-By default, shows tasks in an interactive TaskWarrior-like interface.
489-Use --static to show a simple text list instead.
490-Use --all to show all tasks, otherwise only pending tasks are shown.
491-492-**Usage:**
493-494-```bash
495-noteleaf todo list [flags]
496-```
497-498-**Options:**
499-500-```
501- -a, --all Show all tasks (default: pending only)
502- --context string Filter by context
503- -i, --interactive Force interactive mode (default)
504- --priority string Filter by priority
505- --project string Filter by project
506- --static Use static text output instead of interactive
507- --status string Filter by status
508-```
509-510-**Aliases:** ls
511-512-#### view
513-514-Display detailed information for a specific task.
515-516-Shows all task attributes including description, status, priority, project,
517-context, tags, due date, creation time, and modification history. Use --json
518-for machine-readable output or --no-metadata to show only the description.
519-520-**Usage:**
521-522-```bash
523-noteleaf todo view [task-id] [flags]
524-```
525-526-**Options:**
527-528-```
529- --format string Output format (detailed, brief) (default "detailed")
530- --json Output as JSON
531- --no-metadata Hide creation/modification timestamps
532-```
533-534-#### update
535-536-Modify attributes of an existing task.
537-538-Update any task property including description, status, priority, project,
539-context, due date, recurrence rule, or parent task. Add or remove tags and
540-dependencies. Multiple attributes can be updated in a single command.
541-542-Examples:
543- noteleaf todo update 123 --priority urgent --due tomorrow
544- noteleaf todo update 456 --add-tag urgent --project website
545-546-**Usage:**
547-548-```bash
549-noteleaf todo update [task-id] [flags]
550-```
551-552-**Options:**
553-554-```
555- --add-depends string Add task dependencies (comma-separated UUIDs)
556- --add-tag strings Add tags to task
557- -c, --context string Set task context
558- --description string Update task description
559- -d, --due string Set due date (YYYY-MM-DD)
560- --parent string Set parent task UUID
561- -p, --priority string Set task priority
562- --project string Set task project
563- --recur string Set recurrence rule (e.g., FREQ=DAILY)
564- --remove-depends string Remove task dependencies (comma-separated UUIDs)
565- --remove-tag strings Remove tags from task
566- --status string Update task status
567- -t, --tags strings Add tags to task
568- --until string Set recurrence end date (YYYY-MM-DD)
569-```
570-571-#### edit
572-573-Open interactive editor for task modification.
574-575-Provides a user-friendly interface with status picker and priority toggle.
576-Easier than using multiple command-line flags for complex updates.
577-578-**Usage:**
579-580-```bash
581-noteleaf todo edit [task-id]
582-```
583-584-**Aliases:** e
585-586-#### delete
587-588-Permanently remove a task from the database.
589-590-This operation cannot be undone. Consider updating the task status to
591-'deleted' instead if you want to preserve the record for historical purposes.
592-593-**Usage:**
594-595-```bash
596-noteleaf todo delete [task-id]
597-```
598-599-#### projects
600-601-Display all projects with task counts.
602-603-Shows each project used in your tasks along with the number of tasks in each
604-project. Use --todo-txt to format output with +project syntax for compatibility
605-with todo.txt tools.
606-607-**Usage:**
608-609-```bash
610-noteleaf todo projects [flags]
611-```
612-613-**Options:**
614-615-```
616- --static Use static text output instead of interactive
617- --todo-txt Format output with +project prefix for todo.txt compatibility
618-```
619-620-**Aliases:** proj
621-622-#### tags
623-624-Display all tags used across tasks.
625-626-Shows each tag with the number of tasks using it. Tags provide flexible
627-categorization orthogonal to projects and contexts.
628-629-**Usage:**
630-631-```bash
632-noteleaf todo tags [flags]
633-```
634-635-**Options:**
636-637-```
638- --static Use static text output instead of interactive
639-```
640-641-**Aliases:** t
642-643-#### contexts
644-645-Display all contexts with task counts.
646-647-Contexts represent locations or environments where tasks can be completed (e.g.,
648-@home, @office, @errands). Use --todo-txt to format output with @context syntax
649-for compatibility with todo.txt tools.
650-651-**Usage:**
652-653-```bash
654-noteleaf todo contexts [flags]
655-```
656-657-**Options:**
658-659-```
660- --static Use static text output instead of interactive
661- --todo-txt Format output with @context prefix for todo.txt compatibility
662-```
663-664-**Aliases:** con, loc, ctx, locations
665-666-#### done
667-668-Mark a task as completed with current timestamp.
669-670-Sets the task status to 'completed' and records the completion time. For
671-recurring tasks, generates the next instance based on the recurrence rule.
672-673-**Usage:**
674-675-```bash
676-noteleaf todo done [task-id]
677-```
678-679-**Aliases:** complete
680-681-#### start
682-683-Begin tracking time spent on a task.
684-685-Records the start time for a work session. Only one task can be actively
686-tracked at a time. Use --note to add a description of what you're working on.
687-688-**Usage:**
689-690-```bash
691-noteleaf todo start [task-id] [flags]
692-```
693-694-**Options:**
695-696-```
697- -n, --note string Add a note to the time entry
698-```
699-700-#### stop
701-702-End time tracking for the active task.
703-704-Records the end time and calculates duration for the current work session.
705-Duration is added to the task's total time tracked.
706-707-**Usage:**
708-709-```bash
710-noteleaf todo stop [task-id]
711-```
712-713-#### timesheet
714-715-Show time tracking summary for tasks.
716-717-By default shows time entries for the last 7 days.
718-Use --task to show timesheet for a specific task.
719-Use --days to change the date range.
720-721-**Usage:**
722-723-```bash
724-noteleaf todo timesheet [flags]
725-```
726-727-**Options:**
728-729-```
730- -d, --days int Number of days to show in timesheet (default 7)
731- -t, --task string Show timesheet for specific task ID
732-```
733-734-#### recur
735-736-Configure recurring task patterns.
737-738-Create tasks that repeat on a schedule using iCalendar recurrence rules (RRULE).
739-Supports daily, weekly, monthly, and yearly patterns with optional end dates.
740-741-**Usage:**
742-743-```bash
744-noteleaf todo recur
745-```
746-747-**Aliases:** repeat
748-749-##### set
750-751-Apply a recurrence rule to create repeating task instances.
752-753-Uses iCalendar RRULE syntax (e.g., "FREQ=DAILY" for daily tasks, "FREQ=WEEKLY;BYDAY=MO,WE,FR"
754-for specific weekdays). When a recurring task is completed, the next instance is
755-automatically generated.
756-757-Examples:
758- noteleaf todo recur set 123 --rule "FREQ=DAILY"
759- noteleaf todo recur set 456 --rule "FREQ=WEEKLY;BYDAY=MO" --until 2024-12-31
760-761-**Usage:**
762-763-```bash
764-noteleaf todo recur set [task-id] [flags]
765-```
766-767-**Options:**
768-769-```
770- --rule string Recurrence rule (e.g., FREQ=DAILY)
771- --until string Recurrence end date (YYYY-MM-DD)
772-```
773-774-##### clear
775-776-Remove recurrence from a task.
777-778-Converts a recurring task to a one-time task. Existing future instances are not
779-affected.
780-781-**Usage:**
782-783-```bash
784-noteleaf todo recur clear [task-id]
785-```
786-787-##### show
788-789-Display recurrence rule and schedule information.
790-791-Shows the RRULE pattern, next occurrence date, and recurrence end date if
792-configured.
793-794-**Usage:**
795-796-```bash
797-noteleaf todo recur show [task-id]
798-```
799-800-#### depend
801-802-Create and manage task dependencies.
803-804-Establish relationships where one task must be completed before another can
805-begin. Useful for multi-step workflows and project management.
806-807-**Usage:**
808-809-```bash
810-noteleaf todo depend
811-```
812-813-**Aliases:** dep, deps
814-815-##### add
816-817-Make a task dependent on another task's completion.
818-819-The first task cannot be started until the second task is completed. Use task
820-UUIDs to specify dependencies.
821-822-**Usage:**
823-824-```bash
825-noteleaf todo depend add [task-id] [depends-on-uuid]
826-```
827-828-##### remove
829-830-Delete a dependency relationship between two tasks.
831-832-**Usage:**
833-834-```bash
835-noteleaf todo depend remove [task-id] [depends-on-uuid]
836-```
837-838-**Aliases:** rm
839-840-##### list
841-842-Show all tasks that must be completed before this task can be started.
843-844-**Usage:**
845-846-```bash
847-noteleaf todo depend list [task-id]
848-```
849-850-**Aliases:** ls
851-852-##### blocked-by
853-854-Display all tasks that depend on this task's completion.
855-856-**Usage:**
857-858-```bash
859-noteleaf todo depend blocked-by [task-id]
860-```
861-
···1----
2-id: tv-shows
3-title: TV Shows
4-sidebar_position: 6
5-description: Manage TV show watching
6----
7-8-## tv
9-10-Track TV shows and episodes.
11-12-Search TMDB for TV shows and add them to your queue. Track which shows you're
13-currently watching, mark episodes as watched, and maintain a complete history
14-of your viewing activity.
15-16-```bash
17-noteleaf media tv
18-```
19-20-### Subcommands
21-22-#### add
23-24-Search for TV shows and add them to your watch queue.
25-26-By default, shows search results in a simple list format where you can select by number.
27-Use the -i flag for an interactive interface with navigation keys.
28-29-**Usage:**
30-31-```bash
32-noteleaf media tv add [search query...] [flags]
33-```
34-35-**Options:**
36-37-```
38- -i, --interactive Use interactive interface for TV show selection
39-```
40-41-#### list
42-43-Display TV shows in your queue with optional status filters.
44-45-Shows show titles, air dates, and current status. Filter by --all, --queued,
46---watching for shows in progress, or --watched for completed series. Default
47-shows queued shows only.
48-49-**Usage:**
50-51-```bash
52-noteleaf media tv list [--all|--queued|--watching|--watched]
53-```
54-55-#### watching
56-57-Mark a TV show as currently watching. Use this when you start watching a series.
58-59-**Usage:**
60-61-```bash
62-noteleaf media tv watching [id]
63-```
64-65-#### watched
66-67-Mark TV show episodes or entire series as watched.
68-69-Updates episode tracking and completion status. Can mark individual episodes
70-or complete seasons/series depending on ID format.
71-72-**Usage:**
73-74-```bash
75-noteleaf media tv watched [id]
76-```
77-78-**Aliases:** seen
79-80-#### remove
81-82-Remove a TV show from your watch queue. Use this for shows you no longer want to track.
83-84-**Usage:**
85-86-```bash
87-noteleaf media tv remove [id]
88-```
89-90-**Aliases:** rm
91-
···1+---
2+title: Books
3+sidebar_label: Books
4+description: Build and maintain your reading list with Open Library metadata.
5+sidebar_position: 2
6+---
7+8+# Books
9+10+The book workflow revolves around Open Library search results. Each command lives under `noteleaf media book`.
11+12+## Add Books
13+14+Search Open Library and pick a result:
15+16+```sh
17+noteleaf media book add "Project Hail Mary"
18+```
19+20+Flags:
21+22+- `-i, --interactive`: open the TUI browser (currently shows your local listโuseful for triage).
23+- Plain mode prints the top five matches inline and prompts for a numeric selection.
24+25+Behind the scenes Noteleaf records the title, authors, edition details, and any subjects returned by the API. New entries start in the `queued` status.
26+27+## Manage the Reading List
28+29+List and filter:
30+31+```sh
32+# Everything
33+noteleaf media book list --all
34+35+# Only active reads
36+noteleaf media book list --reading
37+38+# Completed books
39+noteleaf media book list --finished
40+```
41+42+Each line shows the ID, title, author, status, progress percentage, and any captured metadata (publishers, edition counts, etc.).
43+44+Remove items you no longer care about:
45+46+```sh
47+noteleaf media book remove 42
48+```
49+50+## Track Progress
51+52+You can explicitly set the status:
53+54+```sh
55+noteleaf media book reading 7
56+noteleaf media book finished 7
57+noteleaf media book update 7 queued
58+```
59+60+But the fastest way is to update the percentage:
61+62+```sh
63+noteleaf media book progress 7 45 # Moves status to reading and records start time
64+noteleaf media book progress 7 100 # Marks finished and records completion time
65+```
66+67+Logic applied automatically:
68+69+- `0%` โ resets to `queued` and clears the โstartedโ timestamp.
70+- `1โ99%` โ flips to `reading` (start time captured).
71+- `100%` โ marks `finished`, sets end time, and locks progress at 100%.
72+73+## Reading Lists and Search
74+75+Common workflows:
76+77+- **Focus view**: `noteleaf media book list --reading | fzf` to pick the next session book.
78+- **Backlog grooming**: `noteleaf media book list --queued` to prune items before they go stale.
79+- **Author sprint**: pipe the list to `rg` to filter by author (`noteleaf media book list --all | rg "Le Guin"`).
80+81+The TUI (`noteleaf media book add -i` or `noteleaf media book list` with the `--interactive` switch) supports `/` to search titles/authors/notes live and `v` for a detailed preview with timestamps.
82+83+## Metadata and Notes
84+85+Each record stores:
86+87+- Title & authors (comma separated when multiple).
88+- Edition count, publishers, subject tags, or cover IDs exposed as inline notes.
89+- Added/started/finished timestamps.
90+- Optional page count (if Open Library exposes it).
91+92+Use those IDs anywhere else (tasks or notes). Example note snippet:
93+94+```markdown
95+## Reading Log
96+- 2024-02-01 โ Started book #7 ("Project Hail Mary")
97+- 2024-02-05 โ Captured ideas in note #128 linked back to the book.
98+```
99+100+Because media lives in the same database as tasks and notes, full-text search will surface those references instantly.
···1+---
2+title: Movies
3+sidebar_label: Movies
4+description: Keep track of your movie queue with Rotten Tomatoes metadata.
5+sidebar_position: 3
6+---
7+8+# Movies
9+10+Movie commands hang off `noteleaf media movie`. Results use Rotten Tomatoes search so you get consistent titles plus critic scores.
11+12+## Add Movies
13+14+```sh
15+noteleaf media movie add "The Matrix"
16+```
17+18+What happens:
19+20+1. The CLI fetches the first five Rotten Tomatoes matches.
21+2. You select the right one by number.
22+3. The chosen movie is inserted into the local queue with status `queued`.
23+24+The `-i/--interactive` flag is reserved for a future selector; currently the inline prompt is the quickest path.
25+26+## List and Filter
27+28+```sh
29+# Default: queued items only
30+noteleaf media movie list
31+32+# Include everything
33+noteleaf media movie list --all
34+35+# Review history
36+noteleaf media movie list --watched
37+```
38+39+Each entry shows:
40+41+- `ID` and title.
42+- Release year (if Rotten Tomatoes provided one).
43+- Status (`queued` or `watched`).
44+- Critic score snippet (stored inside the Notes column).
45+- Watched timestamp for completed items.
46+47+## Mark Movies as Watched
48+49+```sh
50+noteleaf media movie watched 12
51+```
52+53+The command sets the status to `watched` and records `watched_at` using the current timestamp. Removing an item uses the same ID:
54+55+```sh
56+noteleaf media movie remove 12
57+```
58+59+Use removal for titles you abandoned or added by mistakeโthe CLI deletes the database entry so your queue stays focused.
60+61+## Metadata Cheat Sheet
62+63+- **Notes field**: includes critic score, whether Rotten Tomatoes marked it โCertified Fresh,โ and the canonical URL.
64+- **Rating column**: reserved for future personal ratings; right now it mirrors the upstream critic context.
65+- **Timestamps**: `added` when you saved it, `watched` when you complete it.
66+67+To keep a running diary, drop the IDs into a note:
68+69+```markdown
70+### Queue Ideas
71+- Movie #31 โ Watch before sequel comes out
72+- Movie #12 โ Pair with article #5 for cyberpunk research
73+```
74+75+This keeps everything searchable without having to leave the terminal.
···1+---
2+title: Media Organization
3+sidebar_label: Organization
4+description: Keep queues manageable with filters, reviews, and note links.
5+sidebar_position: 5
6+---
7+8+# Media Organization
9+10+Media entries share the same database as tasks and notes, so you can cross-reference everything. This page outlines the practical workflows for keeping large queues in check.
11+12+## Tags and Categories
13+14+Dedicated media tags have not shipped yet. Until they do:
15+16+- Use the free-form `Notes` column (populated automatically from Open Library or Rotten Tomatoes) to stash keywords such as โHugo shortlistโ or โDocumentaryโ.
17+- When you need stricter structure, create a note that tracks an ad-hoc category and reference media IDs inside it:
18+19+```markdown
20+## Cozy backlog
21+- Book #11 โ comfort reread
22+- Movie #25 โ rainy-day pick
23+```
24+25+Full-text search (`noteleaf note list` โ `/` and search) will surface the note instantly, and the numeric IDs jump you right back into the media commands.
26+27+## Custom Lists
28+29+You already get status-based filters out of the box:
30+31+```sh
32+noteleaf media book list --reading
33+noteleaf media movie list --watched
34+noteleaf media tv list --all | rg "FX" # filter with ripgrep
35+```
36+37+For more bespoke dashboards:
38+39+1. Use `noteleaf status` to grab the SQLite path.
40+2. Query it with tools like `sqlite-utils` or `datasette` to build spreadsheets or dashboards.
41+3. Export subsets via `sqlite3 noteleaf.db "SELECT * FROM books WHERE status='reading'" > reading.csv`.
42+43+That approach keeps the CLI fast while still letting you slice the data any way you need.
44+45+## Ratings and Reviews
46+47+The database schema already includes a `rating` column for every media type. Rotten Tomatoes/Open Library populate it with critic hints for now; personal star ratings will become editable in a future release.
48+49+Until then, keep reviews as regular notes:
50+51+```sh
52+noteleaf note create "Thoughts on Book #7"
53+```
54+55+Inside the note, link back to the record (`Book #7`, `Movie #18`, etc.) so searches tie everything together. Because notes live on disk you can also version-control your reviews.
56+57+## Linking Media to Notes
58+59+There is no special โlinkโ command yet, but the following pattern works well:
60+61+1. Create a dedicated note per book/movie/show (or per collection).
62+2. Add a heading with the media ID and paste the generated markdown path from `noteleaf article view` or the queue list.
63+3. Optionally embed checklists or quotes gathered while reading/watching.
64+65+Example snippet:
66+67+```markdown
68+### Book #7 โ Project Hail Mary
69+- Status: reading (45%)
70+- Tasks: todo #128 covers the experiment described in chapter 12
71+- Next action: finish Part II before Friday
72+```
73+74+Because tasks, notes, and media share the same SQLite file, future automation can join across them without migrations. When official linking lands it will reuse these IDs, so the prep work you do now keeps paying off.
···1+---
2+title: Media Overview
3+sidebar_label: Overview
4+description: Manage reading lists and watch queues from the CLI.
5+sidebar_position: 1
6+---
7+8+# Media Tracking Overview
9+10+Noteleaf keeps book, movie, and TV data next to your tasks and notes so you do not need a separate โwatch listโ app.
11+All media commands hang off a single entry point:
12+13+```sh
14+noteleaf media <book|movie|tv> <subcommand>
15+```
16+17+- **Books** pull metadata from the Open Library API.
18+- **Movies/TV** scrape Rotten Tomatoes search results to capture critic scores and canonical titles.
19+- Everything is stored in the local SQLite database located in your data directory (`~/.local/share/noteleaf` on Linux, `~/Library/Application Support/noteleaf` on macOS, `%LOCALAPPDATA%\noteleaf` on Windows).
20+21+## Lifecycle Statuses
22+23+| Type | Statuses | Notes |
24+| ------ | ------------------------------------------ | ------------------------------------------------------------------------------------------------- |
25+| Books | `queued`, `reading`, `finished`, `removed` | Progress updates automatically bump status (0% โ `queued`, 1-99% โ `reading`, 100% โ `finished`). |
26+| Movies | `queued`, `watched`, `removed` | Marking as watched stores the completion timestamp. |
27+| TV | `queued`, `watching`, `watched`, `removed` | Watching/watched commands also record the last watched time. |
28+29+Statuses control list filtering and show up beside each item in the TUI.
30+31+## Metadata That Gets Saved
32+33+- **Books**: title, authors, Open Library notes (editions, publishers, subjects), started/finished timestamps, progress percentage.
34+- **Movies**: release year when available, Rotten Tomatoes critic score details inside the notes field, watched timestamp.
35+- **TV**: show title plus critic score details, optional season/episode numbers, last watched timestamp.
36+37+You can safely edit the generated markdown/notes in your favorite editorโthe records keep pointing to the updated files.
38+39+## Interactive vs Static Workflows
40+41+All `list` commands default to a simple textual table. For books you can pass `-i/--interactive` to open the Bubble Tea list browser (TV and movie interactive selectors are planned). Inside the list view:
42+43+- `j/k` or arrow keys move between entries.
44+- `/` starts search across titles, authors, and metadata.
45+- `v` opens a focused preview.
46+- `?` shows all shortcuts.
47+48+If you prefer scripts, combine the static lists with tools like `rg` or `jq`.
49+50+## Storage Layout
51+52+Media records live in the SQLite database (`noteleaf.db`). Binary assets are not downloaded; the metadata stores canonical URLs so you can jump back to the source at any time.
53+Use `noteleaf status` to see the exact paths for your database, data directory, and configuration file.
···1+---
2+title: TV Shows
3+sidebar_label: TV Shows
4+description: Track long-form series with simple queue management.
5+sidebar_position: 4
6+---
7+8+# TV Shows
9+10+TV commands live under `noteleaf media tv`. Like movies, they use Rotten Tomatoes search so you can trust the spelling and canonical links.
11+12+## Add Shows
13+14+```sh
15+noteleaf media tv add "Breaking Bad"
16+```
17+18+- Inline mode shows up to five matches and asks you to choose.
19+- `-i/--interactive` is wired up for the future list selector.
20+21+Every new show starts as `queued`.
22+23+## List the Queue
24+25+```sh
26+noteleaf media tv list # queued shows
27+noteleaf media tv list --watching # in-progress series
28+noteleaf media tv list --watched # finished shows
29+noteleaf media tv list --all # everything
30+```
31+32+Output includes the ID, title, optional season/episode numbers (once those fields are set), status, critic-score snippet, and timestamps.
33+34+## Update Status
35+36+Use semantic verbs instead of editing the status manually:
37+38+```sh
39+noteleaf media tv watching 8 # Moved to โcurrently watchingโ
40+noteleaf media tv watched 8 # Mark completed
41+noteleaf media tv remove 8 # Drop from the queue entirely
42+```
43+44+Each transition records `last_watched` so you know when you left off. Future releases will expose explicit season/episode commands; until then store quick reminders in a linked note:
45+46+```markdown
47+### TV checklist
48+- TV #8 โ resume Season 3 Episode 5
49+- TV #15 โ waiting for new season announcement
50+```
51+52+## Organization Tips
53+54+- Use `noteleaf media tv list --watching | fzf` to pick tonightโs episode.
55+- Pipe `--all` into `rg "HBO"` to filter on the metadata snippet that contains the network/URL.
56+- Include `TV #ID` references in your weekly review note so you can jump back with a single ID lookup.
57+58+## What Gets Stored
59+60+- Rotten Tomatoes critic info plus canonical URL (inside the Notes column).
61+- Optional season/episode integers for future episode tracking (already part of the schema).
62+- Added timestamps and โlast watchedโ timestamps.
63+64+Because shows can last months, keeping the queue short (just what you plan to watch soon) makes the `list` output far easier to scan.
···1+---
2+title: Advanced Note Features
3+sidebar_label: Advanced
4+description: Search, exports, backlinks, and automation tips.
5+sidebar_position: 5
6+---
7+8+# Advanced Note Features
9+10+## Full-Text Search
11+12+While not exposed as a dedicated command, you can search note content using the database:
13+14+**Search with grep** (searches file content):
15+16+```sh
17+grep -r "search term" ~/.local/share/noteleaf/notes/
18+```
19+20+**Search titles and metadata**:
21+22+```sh
23+noteleaf note list --static | grep "keyword"
24+```
25+26+Future versions may include built-in full-text search with relevance ranking.
27+28+## Note Exports
29+30+Export notes to different formats using standard markdown tools:
31+32+**Convert to HTML with pandoc**:
33+34+```sh
35+noteleaf note view 1 --format=raw | pandoc -o output.html
36+```
37+38+**Convert to PDF**:
39+40+```sh
41+noteleaf note view 1 --format=raw | pandoc -o output.pdf
42+```
43+44+**Batch export all notes**:
45+46+```sh
47+for note in ~/.local/share/noteleaf/notes/*.md; do
48+ pandoc "$note" -o "${note%.md}.html"
49+done
50+```
51+52+## Backlinks and References
53+54+Manually create backlinks between notes using markdown links:
55+56+```markdown
57+See also: [[Research on Authentication]] for background
58+Related: [[API Design Principles]]
59+```
60+61+While Noteleaf doesn't automatically parse or display backlinks yet, this syntax prepares notes for future backlink support and works with tools like Obsidian if you point it at the notes directory.
···1+---
2+title: Note Basics
3+sidebar_label: Basics
4+description: Creating notes, metadata, and storage model.
5+sidebar_position: 2
6+---
7+8+# Note Basics
9+10+## Creation
11+12+**Quick note from command line**:
13+14+```sh
15+noteleaf note create "Meeting Notes" "Discussed Q4 roadmap and hiring plans"
16+```
17+18+**Interactive creation** (opens editor):
19+20+```sh
21+noteleaf note create --interactive
22+```
23+24+**From existing file**:
25+26+```sh
27+noteleaf note create --file ~/Documents/draft.md
28+```
29+30+**Create and immediately edit**:
31+32+```sh
33+noteleaf note create "Research Notes" --editor
34+```
35+36+## Structure
37+38+Notes consist of:
39+40+**Title**: Short descriptor shown in lists and searches. Can be updated later.
41+42+**Content**: Full markdown text. Supports all standard markdown features including code blocks, lists, tables, and links.
43+44+**Tags**: Categorization labels for organizing and filtering notes. Multiple tags per note.
45+46+**Dates**: Creation and modification timestamps tracked automatically.
47+48+**File Path**: Location of the markdown file on disk, managed by Noteleaf.
49+50+## Storage
51+52+**File Location**: Notes are stored as individual `.md` files in your notes directory (typically `~/.local/share/noteleaf/notes` or `~/Library/Application Support/noteleaf/notes`).
53+54+**Naming**: Files are named with a UUID to ensure uniqueness. The title is stored in the database, not the filename.
55+56+**Portability**: Since notes are plain markdown, you can read them with any text editor or markdown viewer.
57+The database provides additional functionality like tagging and search, but the files remain standalone.
+28
website/docs/notes/best-practices.md
···0000000000000000000000000000
···1+---
2+title: Note Tips and Best Practices
3+sidebar_label: Best Practices
4+description: Guidelines for keeping notes useful over time.
5+sidebar_position: 8
6+---
7+8+# Note Tips and Best Practices
9+10+**Write in plain language**: Notes are for your future self. Avoid jargon you might forget.
11+12+**Tag consistently**: Establish a tagging taxonomy early and stick to it. Review tags periodically with `noteleaf note tags`.
13+14+**Link liberally**: Reference related notes, tasks, and articles using markdown links and references.
15+16+**Short, focused notes**: Better to have many small notes than few giant ones. Easier to link and reuse.
17+18+**Regular review**: Schedule time to review notes, add tags, create links, and archive outdated content.
19+20+**Edit immediately**: If you notice incomplete or unclear notes, edit them now. Stale notes lose value.
21+22+**Use your editor**: Configure your favorite editor with markdown plugins for better syntax highlighting and live preview.
23+24+**Backup regularly**: While notes are files, backup both the notes directory and the database to preserve metadata.
25+26+**Experiment with formats**: Try different note structures (journal, zettelkasten, topic-based) to find what works for you.
27+28+For CLI command reference, run `noteleaf note --help` or open the contextual help inside the TUI.
···1+---
2+title: Note Operations
3+sidebar_label: Operations
4+description: List, read, edit, and delete notes from the CLI.
5+sidebar_position: 3
6+---
7+8+# Note Operations
9+10+### Listing Notes
11+12+**Interactive TUI** (default):
13+```sh
14+noteleaf note list
15+```
16+17+Navigate with arrow keys, press Enter to read, `e` to edit, `q` to quit.
18+19+**Static list**:
20+```sh
21+noteleaf note list --static
22+```
23+24+**Filter by tags**:
25+```sh
26+noteleaf note list --tags research,technical
27+```
28+29+**Show archived notes**:
30+```sh
31+noteleaf note list --archived
32+```
33+34+### Reading Notes
35+36+View note content with formatted rendering:
37+38+```sh
39+noteleaf note read 1
40+```
41+42+Aliases: `noteleaf note view 1`
43+44+The viewer renders markdown with syntax highlighting for code blocks, proper formatting for headers and lists, and displays metadata (title, tags, dates).
45+46+### Editing Notes
47+48+Open note in your configured editor:
49+50+```sh
51+noteleaf note edit 1
52+```
53+54+Noteleaf uses the editor specified in your configuration or the `$EDITOR` environment variable. Common choices: `vim`, `nvim`, `nano`, `code`, `emacs`.
55+56+**Configure editor**:
57+```sh
58+noteleaf config set editor nvim
59+```
60+61+Changes are saved automatically when you close the editor. The modification timestamp updates to track when notes were last changed.
62+63+### Deleting Notes
64+65+Remove a note permanently:
66+67+```sh
68+noteleaf note remove 1
69+```
70+71+Aliases: `rm`, `delete`, `del`
72+73+This deletes both the markdown file and database metadata. You'll be prompted for confirmation. This operation cannot be undone, so consider archiving instead if you might need the note later.
···1+---
2+title: Note Organization
3+sidebar_label: Organization
4+description: Tagging, linking, and template workflows for notes.
5+sidebar_position: 4
6+---
7+8+# Note Organization
9+10+## Tagging
11+12+Tags provide flexible categorization without hierarchical constraints.
13+14+**Add tags during creation**:
15+16+```sh
17+noteleaf note create "API Design" --tags architecture,reference
18+```
19+20+**Add tags to existing note**:
21+22+```sh
23+noteleaf note update 1 --add-tag reference
24+```
25+26+**Remove tags**:
27+28+```sh
29+noteleaf note update 1 --remove-tag draft
30+```
31+32+**List all tags**:
33+34+```sh
35+noteleaf note tags
36+```
37+38+Shows each tag with the count of notes using it.
39+40+**Tag naming conventions**: Use lowercase, hyphens for compound tags. Examples: `research`, `meeting-notes`, `how-to`, `reference`, `technical`, `personal`.
41+42+## Linking
43+44+While not a first-class feature in the current UI, notes can reference tasks by ID or description:
45+46+```markdown
47+# Implementation Plan
48+49+Related task: #42 (Deploy authentication service)
50+51+## Next Steps
52+- Complete testing (task #43)
53+- Write documentation (task #44)
54+```
55+56+Future versions may support automatic linking between notes and tasks in the database.
57+58+## Templates
59+60+Create reusable note structures using shell functions or scripts:
61+62+**In ~/.bashrc or ~/.zshrc**:
63+64+```sh
65+meeting_note() {
66+ local title="Meeting: $1"
67+ local date=$(date +%Y-%m-%d)
68+ local content="# $title
69+70+**Date**: $date
71+72+## Attendees
73+-
74+75+## Agenda
76+-
77+78+## Discussion
79+-
80+81+## Action Items
82+- [ ]
83+84+## Next Meeting
85+- "
86+87+ echo "$content" | noteleaf note create "$title" --tags meeting --editor
88+}
89+90+daily_note() {
91+ local date=$(date +%Y-%m-%d)
92+ local title="Daily: $date"
93+ local content="# $title
94+95+## Completed Today
96+-
97+98+## In Progress
99+-
100+101+## Tomorrow's Focus
102+-
103+104+## Notes
105+- "
106+107+ echo "$content" | noteleaf note create "$title" --tags daily --editor
108+}
109+```
110+111+Usage:
112+113+```sh
114+meeting_note "Q4 Planning"
115+daily_note
116+```
+11
website/docs/notes/overview.md
···00000000000
···1+---
2+title: Notes Overview
3+sidebar_label: Overview
4+description: How Noteleaf manages markdown-based notes.
5+sidebar_position: 1
6+---
7+8+# Notes Overview
9+10+Noteleaf provides a markdown-based note-taking system integrated with your tasks, articles, and media tracking.
11+Notes are stored as individual markdown files with metadata tracked in the database, giving you both structure and portability.
···1+---
2+title: Note-Taking Workflows
3+sidebar_label: Workflows
4+description: Zettelkasten, meeting notes, daily notes, and more.
5+sidebar_position: 7
6+---
7+8+# Note-Taking Workflows
9+10+## Zettelkasten
11+12+Zettelkasten emphasizes atomic notes with heavy linking:
13+14+1. **Create atomic notes**: Each note covers one concept
15+2. **Add descriptive tags**: Use tags for categorization
16+3. **Link related notes**: Reference other notes by title
17+4. **Develop ideas over time**: Expand notes with new insights
18+19+Example:
20+21+```sh
22+noteleaf note create "Dependency Injection" --tags architecture,patterns
23+noteleaf note create "Inversion of Control" --tags architecture,patterns
24+# In each note, reference the other
25+```
26+27+### Research
28+29+For academic or technical research:
30+31+1. **Source note per paper/article**: Create note for each source
32+2. **Extract key points**: Summarize in your own words
33+3. **Tag by topic**: Use consistent tags across research area
34+4. **Link to related work**: Reference other sources
35+36+Example:
37+38+```sh
39+noteleaf note create "Paper: Microservices Patterns" \
40+ --tags research,architecture,microservices
41+```
42+43+### Meeting
44+45+Capture discussions and action items:
46+47+1. **Template-based**: Use meeting_note function from earlier
48+2. **Consistent structure**: Attendees, agenda, discussion, actions
49+3. **Action items**: Extract as tasks for follow-up
50+4. **Link to projects**: Tag with project name
51+52+Example:
53+54+```sh
55+meeting_note "Sprint Planning"
56+# Then extract action items as tasks
57+noteleaf task add "Implement auth endpoint" --project web-service
58+```
59+60+### Daily
61+62+Journal-style daily entries:
63+64+1. **Daily template**: Use daily_note function
65+2. **Reflect on work**: What was accomplished, what's next
66+3. **Capture ideas**: Random thoughts for later processing
67+4. **Review weekly**: Scan week's notes for patterns
68+69+Example:
70+71+```sh
72+daily_note
73+# Creates note tagged with 'daily' and today's date
74+```
75+76+### Personal Knowledge Base
77+78+Build a reference library:
79+80+1. **How-to guides**: Document procedures and commands
81+2. **Troubleshooting notes**: Solutions to problems encountered
82+3. **Concept explanations**: Notes on topics you're learning
83+4. **Snippets**: Code examples and configurations
84+85+Use tags like: `how-to`, `troubleshooting`, `reference`, `snippet`
···1+---
2+title: Task Basics
3+sidebar_label: Basics
4+description: Create tasks and understand their core attributes.
5+sidebar_position: 2
6+---
7+8+# Task Basics
9+10+## Creation
11+12+Create a simple task:
13+14+```sh
15+noteleaf task add "Write documentation"
16+```
17+18+Create a task with attributes:
19+20+```sh
21+noteleaf task add "Review pull requests" \
22+ --priority high \
23+ --project work \
24+ --tags urgent,code-review \
25+ --due 2025-01-15
26+```
27+28+## Properties
29+30+**Description**: What needs to be done. Can be updated later with `task update`.
31+32+**Status**: Task lifecycle state:
33+34+- `pending`: Not yet started (default for new tasks)
35+- `active`: Currently being worked on
36+- `completed`: Finished successfully
37+- `deleted`: Removed but preserved for history
38+- `waiting`: Blocked or postponed
39+40+**Priority**: Importance level affects sorting and display:
41+42+- `low`: Nice to have, defer if busy
43+- `medium`: Standard priority (default)
44+- `high`: Important, should be done soon
45+- `urgent`: Critical, top of the list
46+47+**Project**: Group related tasks together. Examples: `work`, `home`, `side-project`. Projects create organizational boundaries and enable filtering.
48+49+**Context**: Location or mode where task can be done. Examples: `@home`, `@office`, `@phone`, `@computer`. Contexts help filter tasks based on current situation.
50+51+**Tags**: Flexible categorization orthogonal to projects. Examples: `urgent`, `quick-win`, `research`, `bug`. Multiple tags per task.
52+53+**Due Date**: When the task should be completed. Format: `YYYY-MM-DD` or relative (`tomorrow`, `next week`).
54+55+### Lifecycle
56+57+Tasks move through statuses as work progresses:
58+59+```
60+pending -> active -> completed
61+ |
62+ v
63+ waiting
64+ |
65+ v
66+ deleted
67+```
68+69+**Mark task as active**:
70+71+```sh
72+noteleaf task update 1 --status active
73+```
74+75+**Complete a task**:
76+77+```sh
78+noteleaf task done 1
79+```
80+81+**Delete a task**:
82+83+```sh
84+noteleaf task delete 1
85+```
+26
website/docs/tasks/batch-operations.md
···00000000000000000000000000
···1+---
2+title: Batch Operations
3+sidebar_label: Batch Ops
4+description: Use shell scripting patterns for mass task edits.
5+sidebar_position: 8
6+---
7+8+# Batch Operations
9+10+While Noteleaf doesn't have built-in bulk update commands, you can use shell scripting for batch operations:
11+12+**Complete all tasks in a project**:
13+14+```sh
15+noteleaf task list --project old-project --static | \
16+ awk '{print $1}' | \
17+ xargs -I {} noteleaf task done {}
18+```
19+20+**Add tag to multiple tasks**:
21+22+```sh
23+for id in 1 2 3 4 5; do
24+ noteleaf task update $id --add-tag urgent
25+done
26+```
+26
website/docs/tasks/best-practices.md
···00000000000000000000000000
···1+---
2+title: Task Tips and Best Practices
3+sidebar_label: Best Practices
4+description: Practical guidance for staying productive with tasks.
5+sidebar_position: 10
6+---
7+8+# Task Tips and Best Practices
9+10+**Start with simple workflows**: Don't over-organize initially. Use basic priorities and projects before adding contexts, tags, and dependencies.
11+12+**Review regularly**: Use `task list` daily to check pending work. Weekly reviews help catch stale tasks.
13+14+**Use contexts for GTD**: If following Getting Things Done, contexts help filter tasks by what you can do right now.
15+16+**Project-based work**: For complex initiatives, use projects to group tasks and dependencies to order work.
17+18+**Time tracking for accountability**: Even rough time tracking reveals where hours go and helps with estimates.
19+20+**Recurrence for habits**: Use recurring tasks for daily/weekly habits, but keep the list short to avoid clutter.
21+22+**Tags for cross-cutting concerns**: Use tags for themes that span projects: `urgent`, `blocked`, `waiting-on-feedback`, `quick-win`.
23+24+**JSON output for scripts**: Use `--json` flag with scripting to build custom reports and integrations.
25+26+For CLI command reference, run `noteleaf task --help` or explore the inline help on each subcommand.
···1+---
2+title: Task Organization
3+sidebar_label: Organization
4+description: Use projects, contexts, and tags to structure work.
5+sidebar_position: 5
6+---
7+8+# Task Organization
9+10+## Projects
11+12+Projects group related tasks. Useful for separating work contexts or major initiatives.
13+14+**List all projects**:
15+16+```sh
17+noteleaf task projects
18+```
19+20+Shows each project with task count.
21+22+**Filter tasks by project**:
23+24+```sh
25+noteleaf task list --project work
26+```
27+28+**Project naming**: Use lowercase, hyphens for spaces. Examples: `work`, `side-project`, `home-improvement`.
29+30+## Contexts
31+32+Contexts represent where or how a task can be done. Helps with GTD-style workflow.
33+34+**List all contexts**:
35+36+```sh
37+noteleaf task contexts
38+```
39+40+**Filter by context**:
41+42+```sh
43+noteleaf task list --context @home
44+```
45+46+**Context naming**: Prefix with `@` following GTD convention. Examples: `@home`, `@office`, `@phone`, `@errands`.
47+48+## Tags
49+50+Tags provide flexible categorization. Unlike projects and contexts, tasks can have multiple tags.
51+52+**List all tags**:
53+54+```sh
55+noteleaf task tags
56+```
57+58+**Filter by tags** (tasks must have all specified tags):
59+60+```sh
61+noteleaf task list --tags urgent,bug
62+```
63+64+**Tag naming**: Use lowercase, hyphens for compound tags. Examples: `urgent`, `quick-win`, `code-review`, `waiting-on-feedback`.
+11
website/docs/tasks/overview.md
···00000000000
···1+---
2+title: Task Management Overview
3+sidebar_label: Overview
4+description: High-level summary of Noteleaf's task workflow.
5+sidebar_position: 1
6+---
7+8+# Task Management Overview
9+10+Noteleaf provides TaskWarrior-inspired task management with priorities, projects, contexts, tags, dependencies, and time tracking.
11+Whether you're managing personal todos or complex projects, Noteleaf helps you organize work and track progress.
+33
website/docs/tasks/queries.md
···000000000000000000000000000000000
···1+---
2+title: Task Queries and Filtering
3+sidebar_label: Queries
4+description: Compose filters for precise task lists and reports.
5+sidebar_position: 7
6+---
7+8+# Task Queries and Filtering
9+10+Combine filters for precise task lists:
11+12+**High priority work tasks due this week**:
13+14+```sh
15+noteleaf task list \
16+ --project work \
17+ --priority high \
18+ --status pending
19+```
20+21+**All completed tasks from specific project**:
22+23+```sh
24+noteleaf task list \
25+ --project side-project \
26+ --status completed
27+```
28+29+**Quick wins** (tasks tagged as quick):
30+31+```sh
32+noteleaf task list --tags quick-win
33+```
+34
website/docs/tasks/templates.md
···0000000000000000000000000000000000
···1+---
2+title: Task Templates
3+sidebar_label: Templates
4+description: Shell helpers for creating consistent task structures.
5+sidebar_position: 9
6+---
7+8+# Task Templates
9+10+While templates aren't built-in, you can create shell functions for common task patterns:
11+12+```sh
13+# In your ~/.bashrc or ~/.zshrc
14+bug() {
15+ noteleaf task add "$1" \
16+ --project $(git rev-parse --show-toplevel | xargs basename) \
17+ --tags bug \
18+ --priority high
19+}
20+21+meeting() {
22+ noteleaf task add "$1" \
23+ --project work \
24+ --context @office \
25+ --recur "FREQ=WEEKLY;BYDAY=$2"
26+}
27+```
28+29+Usage:
30+31+```sh
32+bug "Fix login redirect"
33+meeting "Sprint planning" "MO"
34+```
···1+---
2+title: Time Tracking
3+sidebar_label: Time Tracking
4+description: Track work, review sessions, and generate timesheets.
5+sidebar_position: 4
6+---
7+8+# Time Tracking
9+10+Track hours spent on tasks for billing, reporting, or personal analytics.
11+12+## Starting and Stopping
13+14+**Start tracking**:
15+16+```sh
17+noteleaf task start 1
18+```
19+20+With a note about what you're doing:
21+22+```sh
23+noteleaf task start 1 --note "Implementing authentication"
24+```
25+26+**Stop tracking**:
27+28+```sh
29+noteleaf task stop 1
30+```
31+32+Only one task can be actively tracked at a time.
33+34+## Viewing Timesheets
35+36+**Last 7 days** (default):
37+38+```sh
39+noteleaf task timesheet
40+```
41+42+**Specific time range**:
43+44+```sh
45+noteleaf task timesheet --days 30
46+```
47+48+**For specific task**:
49+50+```sh
51+noteleaf task timesheet --task 1
52+```
53+54+Timesheet shows:
55+56+- Date and time range for each session
57+- Duration
58+- Notes attached to the session
59+- Total time per task
60+- Total time across all tasks