···3030### First Steps
31313232For a comprehensive walkthrough including task management, time tracking, notes, and media tracking, see the [Quickstart Guide](website/docs/Quickstart.md).
3333+3434+## Development
3535+3636+Noteleaf uses [Task](https://taskfile.dev) for build automation. Development builds include additional tooling commands not available in production builds.
3737+3838+### Building
3939+4040+```sh
4141+# Production build
4242+task build
4343+4444+# Development build (with version info and dev tools)
4545+task build:dev
4646+4747+# Run tests
4848+task test
4949+task cov # ...with coverage
5050+```
5151+5252+### Development Tools
5353+5454+Dev builds (`task build:dev`) include a `tools` subcommand with maintenance utilities:
5555+5656+**Documentation Generation:**
5757+5858+```sh
5959+# Generate Docusaurus documentation
6060+noteleaf tools docgen --format docusaurus --out website/docs/manual
6161+6262+# Generate man pages
6363+noteleaf tools docgen --format man --out docs/manual
6464+```
6565+6666+**Data Synchronization:**
6767+6868+```sh
6969+# Fetch Leaflet lexicons from GitHub
7070+noteleaf tools fetch lexicons
7171+7272+# Fetch from a specific commit
7373+noteleaf tools fetch lexicons --sha abc123def
7474+7575+# Generic GitHub repository archive fetcher
7676+noteleaf tools fetch gh-repo \
7777+ --repo owner/repo \
7878+ --path schemas/ \
7979+ --output local/schemas/
8080+```
8181+8282+Production builds (`task build:rc`, `task build:prod`) use the `-tags prod` flag to exclude dev tools.
+5-5
Taskfile.yml
···5151 - echo "Built {{.BUILD_DIR}}/{{.BINARY_NAME}}"
52525353 build:dev:
5454- desc: Build binary with dev version (includes git commit hash)
5454+ desc: Build binary with dev version (includes git commit hash and dev tools)
5555 vars:
5656 VERSION: "{{.GIT_DESCRIBE}}"
5757 LDFLAGS: "-X {{.VERSION_PKG}}.Version={{.VERSION}} -X {{.VERSION_PKG}}.Commit={{.GIT_COMMIT}} -X {{.VERSION_PKG}}.BuildDate={{.BUILD_DATE}}"
···6161 - 'echo "Built {{.BUILD_DIR}}/{{.BINARY_NAME}} (version: {{.VERSION}})"'
62626363 build:rc:
6464- desc: Build release candidate binary (requires git tag with -rc suffix)
6464+ desc: Build release candidate binary (requires git tag with -rc suffix, excludes dev tools)
6565 vars:
6666 VERSION: "{{.GIT_TAG}}"
6767 LDFLAGS: "-X {{.VERSION_PKG}}.Version={{.VERSION}} -X {{.VERSION_PKG}}.Commit={{.GIT_COMMIT}} -X {{.VERSION_PKG}}.BuildDate={{.BUILD_DATE}}"
···7272 msg: "Git tag must contain '-rc' for release candidate builds (e.g., v1.0.0-rc1)"
7373 cmds:
7474 - mkdir -p {{.BUILD_DIR}}
7575- - go build -ldflags "{{.LDFLAGS}}" -o {{.BUILD_DIR}}/{{.BINARY_NAME}} {{.CMD_DIR}}
7575+ - go build -tags prod -ldflags "{{.LDFLAGS}}" -o {{.BUILD_DIR}}/{{.BINARY_NAME}} {{.CMD_DIR}}
7676 - 'echo "Built {{.BUILD_DIR}}/{{.BINARY_NAME}} (version: {{.VERSION}})"'
77777878 build:prod:
7979- desc: Build production binary (requires clean semver git tag)
7979+ desc: Build production binary (requires clean semver git tag, excludes dev tools)
8080 vars:
8181 VERSION: "{{.GIT_TAG}}"
8282 LDFLAGS: "-X {{.VERSION_PKG}}.Version={{.VERSION}} -X {{.VERSION_PKG}}.Commit={{.GIT_COMMIT}} -X {{.VERSION_PKG}}.BuildDate={{.BUILD_DATE}}"
···8989 msg: "Working directory must be clean (no uncommitted changes) for production builds"
9090 cmds:
9191 - mkdir -p {{.BUILD_DIR}}
9292- - go build -ldflags "{{.LDFLAGS}}" -o {{.BUILD_DIR}}/{{.BINARY_NAME}} {{.CMD_DIR}}
9292+ - go build -tags prod -ldflags "{{.LDFLAGS}}" -o {{.BUILD_DIR}}/{{.BINARY_NAME}} {{.CMD_DIR}}
9393 - 'echo "Built {{.BUILD_DIR}}/{{.BINARY_NAME}} (version: {{.VERSION}})"'
94949595 clean:
+9-6
cmd/commands.go
···3030 Short: "Manage movie watch queue",
3131 Long: `Track movies you want to watch.
32323333-Search TMDB for movies and add them to your queue. Mark movies as watched when
3434-completed. Maintains a history of your movie watching activity.`,
3333+Search for movies and add them to your queue. Mark movies as watched
3434+when completed. Maintains a history of your movie watching activity.`,
3535 }
36363737+ // TODO: add colors
3838+ // TODO: fix critic score parsing
3739 addCmd := &cobra.Command{
3840 Use: "add [search query...]",
3941 Short: "Search and add movie to watch queue",
···5456 addCmd.Flags().BoolP("interactive", "i", false, "Use interactive interface for movie selection")
5557 root.AddCommand(addCmd)
56585959+ // TODO: add interactive list view
5760 root.AddCommand(&cobra.Command{
5861 Use: "list [--all|--watched|--queued]",
5962 Short: "List movies in queue with status filtering",
···102105 return c.handler.Remove(cmd.Context(), args[0])
103106 },
104107 })
105105-106108 return root
107109}
108110···122124 Short: "Manage TV show watch queue",
123125 Long: `Track TV shows and episodes.
124126125125-Search TMDB for TV shows and add them to your queue. Track which shows you're
126126-currently watching, mark episodes as watched, and maintain a complete history
127127-of your viewing activity.`,
127127+Search for TV shows and add them to your queue. Track which shows you're currently
128128+watching, mark episodes as watched, and maintain a complete history of your viewing
129129+activity.`,
128130 }
129131130132 addCmd := &cobra.Command{
···147149 addCmd.Flags().BoolP("interactive", "i", false, "Use interactive interface for TV show selection")
148150 root.AddCommand(addCmd)
149151152152+ // TODO: Add interactive list view
150153 root.AddCommand(&cobra.Command{
151154 Use: "list [--all|--queued|--watching|--watched]",
152155 Short: "List TV shows in queue with status filtering",
···11+package main
22+33+import (
44+ "strings"
55+66+ "github.com/spf13/cobra"
77+ "github.com/stormlightlabs/noteleaf/internal/handlers"
88+)
99+1010+// SearchCommand implements [CommandGroup] for document search commands
1111+type SearchCommand struct {
1212+ handler *handlers.DocumentHandler
1313+}
1414+1515+// NewSearchCommand creates a new search command group
1616+func NewSearchCommand(handler *handlers.DocumentHandler) *SearchCommand {
1717+ return &SearchCommand{handler: handler}
1818+}
1919+2020+func (c *SearchCommand) Create() *cobra.Command {
2121+ root := &cobra.Command{
2222+ Use: "search",
2323+ Short: "Search notes using TF-IDF",
2424+ Long: `Full-text search for notes using Term Frequency-Inverse Document Frequency (TF-IDF) ranking.
2525+2626+The search engine tokenizes text, builds an inverted index, and ranks results by relevance.
2727+Results are sorted by TF-IDF score, with higher scores indicating better matches.`,
2828+ }
2929+3030+ queryCmd := &cobra.Command{
3131+ Use: "query [search terms...]",
3232+ Short: "Search for documents matching query terms",
3333+ Long: `Search for documents using TF-IDF ranking.
3434+3535+Examples:
3636+ noteleaf search query go programming
3737+ noteleaf search query "machine learning" --limit 5`,
3838+ Args: cobra.MinimumNArgs(1),
3939+ RunE: func(cmd *cobra.Command, args []string) error {
4040+ query := strings.Join(args, " ")
4141+ limit, _ := cmd.Flags().GetInt("limit")
4242+4343+ return c.handler.Search(cmd.Context(), query, limit)
4444+ },
4545+ }
4646+ queryCmd.Flags().IntP("limit", "l", 10, "Maximum number of results to return")
4747+ root.AddCommand(queryCmd)
4848+4949+ rebuildCmd := &cobra.Command{
5050+ Use: "rebuild",
5151+ Short: "Rebuild search index from notes",
5252+ Long: `Rebuild the search index from all notes in the database.
5353+5454+This command:
5555+1. Clears the existing document index
5656+2. Copies all notes to the documents table
5757+3. Builds a new TF-IDF search index
5858+5959+Run this after adding, updating, or deleting notes to refresh the search index.`,
6060+ RunE: func(cmd *cobra.Command, args []string) error {
6161+ return c.handler.RebuildIndex(cmd.Context())
6262+ },
6363+ }
6464+ root.AddCommand(rebuildCmd)
6565+6666+ return root
6767+}
+244-4
cmd/task_commands.go
···11package main
2233import (
44+ "fmt"
55+ "strconv"
46 "strings"
5768 "github.com/spf13/cobra"
···3335 &cobra.Group{ID: "task-ops", Title: "Basic Operations"},
3436 &cobra.Group{ID: "task-meta", Title: "Metadata"},
3537 &cobra.Group{ID: "task-tracking", Title: "Tracking"},
3838+ &cobra.Group{ID: "task-reports", Title: "Reports & Views"},
3639 )
37403841 for _, init := range []func(*handlers.TaskHandler) *cobra.Command{
3939- addTaskCmd, listTaskCmd, viewTaskCmd, updateTaskCmd, editTaskCmd, deleteTaskCmd,
4242+ addTaskCmd, listTaskCmd, viewTaskCmd, updateTaskCmd, editTaskCmd, deleteTaskCmd, taskAnnotateCmd, taskBulkEditCmd,
4043 } {
4144 cmd := init(c.handler)
4245 cmd.GroupID = "task-ops"
···5255 }
53565457 for _, init := range []func(*handlers.TaskHandler) *cobra.Command{
5555- timesheetViewCmd, taskStartCmd, taskStopCmd, taskCompleteCmd, taskRecurCmd, taskDependCmd,
5858+ timesheetViewCmd, taskStartCmd, taskStopCmd, taskCompleteCmd, taskRecurCmd, taskDependCmd, taskUndoCmd, taskHistoryCmd,
5659 } {
5760 cmd := init(c.handler)
5861 cmd.GroupID = "task-tracking"
5962 root.AddCommand(cmd)
6063 }
61646565+ for _, init := range []func(*handlers.TaskHandler) *cobra.Command{
6666+ nextActionsCmd, reportCompletedCmd, reportWaitingCmd, reportBlockedCmd, calendarCmd,
6767+ } {
6868+ cmd := init(c.handler)
6969+ cmd.GroupID = "task-reports"
7070+ root.AddCommand(cmd)
7171+ }
7272+6273 return root
6374}
6475···8495 project, _ := c.Flags().GetString("project")
8596 context, _ := c.Flags().GetString("context")
8697 due, _ := c.Flags().GetString("due")
9898+ wait, _ := c.Flags().GetString("wait")
9999+ scheduled, _ := c.Flags().GetString("scheduled")
87100 recur, _ := c.Flags().GetString("recur")
88101 until, _ := c.Flags().GetString("until")
89102 parent, _ := c.Flags().GetString("parent")
···91104 tags, _ := c.Flags().GetStringSlice("tags")
9210593106 defer h.Close()
9494- return h.Create(c.Context(), description, priority, project, context, due, recur, until, parent, dependsOn, tags)
107107+ // TODO: Make a CreateTask struct
108108+ return h.Create(c.Context(), description, priority, project, context, due, wait, scheduled, recur, until, parent, dependsOn, tags)
95109 },
96110 }
97111 addCommonTaskFlags(cmd)
98112 addDueDateFlag(cmd)
113113+ addWaitScheduledFlags(cmd)
99114 addRecurrenceFlags(cmd)
100115 addParentFlag(cmd)
101116 addDependencyFlags(cmd)
···120135 priority, _ := c.Flags().GetString("priority")
121136 project, _ := c.Flags().GetString("project")
122137 context, _ := c.Flags().GetString("context")
138138+ sortBy, _ := c.Flags().GetString("sort")
123139124140 defer h.Close()
125125- return h.List(c.Context(), static, showAll, status, priority, project, context)
141141+ // TODO: TaskFilter struct
142142+ return h.List(c.Context(), static, showAll, status, priority, project, context, sortBy)
126143 },
127144 }
128145 cmd.Flags().BoolP("interactive", "i", false, "Force interactive mode (default)")
···132149 cmd.Flags().String("priority", "", "Filter by priority")
133150 cmd.Flags().String("project", "", "Filter by project")
134151 cmd.Flags().String("context", "", "Filter by context")
152152+ cmd.Flags().String("sort", "", "Sort by (urgency)")
135153136154 return cmd
137155}
···451469 return root
452470}
453471472472+func nextActionsCmd(h *handlers.TaskHandler) *cobra.Command {
473473+ cmd := &cobra.Command{
474474+ Use: "next",
475475+ Short: "Show next actions (actionable tasks sorted by urgency)",
476476+ Aliases: []string{"na"},
477477+ Long: `Display actionable tasks sorted by urgency score.
478478+479479+Shows tasks that can be worked on now (not waiting, not blocked, not completed),
480480+ordered by their computed urgency based on priority, due date, age, and other factors.`,
481481+ RunE: func(c *cobra.Command, args []string) error {
482482+ limit, _ := c.Flags().GetInt("limit")
483483+ defer h.Close()
484484+ return h.NextActions(c.Context(), limit)
485485+ },
486486+ }
487487+ cmd.Flags().IntP("limit", "n", 10, "Limit number of tasks shown")
488488+ return cmd
489489+}
490490+491491+func reportCompletedCmd(h *handlers.TaskHandler) *cobra.Command {
492492+ cmd := &cobra.Command{
493493+ Use: "completed",
494494+ Short: "Show completed tasks",
495495+ Long: "Display tasks that have been completed, sorted by completion date.",
496496+ RunE: func(c *cobra.Command, args []string) error {
497497+ limit, _ := c.Flags().GetInt("limit")
498498+ defer h.Close()
499499+ return h.ReportCompleted(c.Context(), limit)
500500+ },
501501+ }
502502+ cmd.Flags().IntP("limit", "n", 20, "Limit number of tasks shown")
503503+ return cmd
504504+}
505505+506506+func reportWaitingCmd(h *handlers.TaskHandler) *cobra.Command {
507507+ cmd := &cobra.Command{
508508+ Use: "waiting",
509509+ Short: "Show waiting tasks",
510510+ Long: "Display tasks that are waiting for a specific date before becoming actionable.",
511511+ RunE: func(c *cobra.Command, args []string) error {
512512+ defer h.Close()
513513+ return h.ReportWaiting(c.Context())
514514+ },
515515+ }
516516+ return cmd
517517+}
518518+519519+func reportBlockedCmd(h *handlers.TaskHandler) *cobra.Command {
520520+ cmd := &cobra.Command{
521521+ Use: "blocked",
522522+ Short: "Show blocked tasks",
523523+ Long: "Display tasks that are blocked by dependencies on other tasks.",
524524+ RunE: func(c *cobra.Command, args []string) error {
525525+ defer h.Close()
526526+ return h.ReportBlocked(c.Context())
527527+ },
528528+ }
529529+ return cmd
530530+}
531531+532532+func calendarCmd(h *handlers.TaskHandler) *cobra.Command {
533533+ cmd := &cobra.Command{
534534+ Use: "calendar",
535535+ Short: "Show tasks in calendar view",
536536+ Aliases: []string{"cal"},
537537+ Long: `Display tasks with due dates in a calendar format.
538538+539539+Shows tasks organized by week and day, making it easy to see upcoming deadlines
540540+and plan your work schedule.`,
541541+ RunE: func(c *cobra.Command, args []string) error {
542542+ weeks, _ := c.Flags().GetInt("weeks")
543543+ defer h.Close()
544544+ return h.Calendar(c.Context(), weeks)
545545+ },
546546+ }
547547+ cmd.Flags().IntP("weeks", "w", 4, "Number of weeks to show")
548548+ return cmd
549549+}
550550+454551func taskDependCmd(h *handlers.TaskHandler) *cobra.Command {
455552 root := &cobra.Command{
456553 Use: "depend",
···514611 root.AddCommand(addCmd, removeCmd, listCmd, blockedByCmd)
515612 return root
516613}
614614+615615+func taskAnnotateCmd(h *handlers.TaskHandler) *cobra.Command {
616616+ root := &cobra.Command{
617617+ Use: "annotate",
618618+ Aliases: []string{"note"},
619619+ Short: "Manage task annotations",
620620+ Long: `Add, list, or remove annotations on tasks.
621621+622622+Annotations are timestamped notes that provide context and updates
623623+about a task's progress or relevant information.`,
624624+ }
625625+626626+ addCmd := &cobra.Command{
627627+ Use: "add <task-id> <annotation>",
628628+ Short: "Add an annotation to a task",
629629+ Aliases: []string{"create"},
630630+ Args: cobra.MinimumNArgs(2),
631631+ RunE: func(c *cobra.Command, args []string) error {
632632+ taskID := args[0]
633633+ annotation := strings.Join(args[1:], " ")
634634+ defer h.Close()
635635+ return h.Annotate(c.Context(), taskID, annotation)
636636+ },
637637+ }
638638+639639+ listCmd := &cobra.Command{
640640+ Use: "list <task-id>",
641641+ Short: "List all annotations for a task",
642642+ Aliases: []string{"ls", "show"},
643643+ Args: cobra.ExactArgs(1),
644644+ RunE: func(c *cobra.Command, args []string) error {
645645+ defer h.Close()
646646+ return h.ListAnnotations(c.Context(), args[0])
647647+ },
648648+ }
649649+650650+ removeCmd := &cobra.Command{
651651+ Use: "remove <task-id> <index>",
652652+ Short: "Remove an annotation by index",
653653+ Aliases: []string{"rm", "delete"},
654654+ Args: cobra.ExactArgs(2),
655655+ RunE: func(c *cobra.Command, args []string) error {
656656+ taskID := args[0]
657657+ index, err := strconv.Atoi(args[1])
658658+ if err != nil {
659659+ return fmt.Errorf("invalid annotation index: %w", err)
660660+ }
661661+ defer h.Close()
662662+ return h.RemoveAnnotation(c.Context(), taskID, index)
663663+ },
664664+ }
665665+666666+ root.AddCommand(addCmd, listCmd, removeCmd)
667667+ return root
668668+}
669669+670670+func taskBulkEditCmd(h *handlers.TaskHandler) *cobra.Command {
671671+ cmd := &cobra.Command{
672672+ Use: "bulk-edit <task-id>...",
673673+ Aliases: []string{"bulk"},
674674+ Short: "Update multiple tasks at once",
675675+ Long: `Update multiple tasks with the same changes.
676676+677677+Allows batch updates to status, priority, project, context, and tags.
678678+Use --add-tags to add tags without replacing existing ones.
679679+Use --remove-tags to remove specific tags from tasks.
680680+681681+Examples:
682682+ noteleaf todo bulk-edit 1 2 3 --status done
683683+ noteleaf todo bulk-edit 1 2 --project web --priority high
684684+ noteleaf todo bulk-edit 1 2 3 --add-tags urgent,review`,
685685+ Args: cobra.MinimumNArgs(1),
686686+ RunE: func(c *cobra.Command, args []string) error {
687687+ status, _ := c.Flags().GetString("status")
688688+ priority, _ := c.Flags().GetString("priority")
689689+ project, _ := c.Flags().GetString("project")
690690+ context, _ := c.Flags().GetString("context")
691691+ tags, _ := c.Flags().GetStringSlice("tags")
692692+ addTags, _ := c.Flags().GetBool("add-tags")
693693+ removeTags, _ := c.Flags().GetBool("remove-tags")
694694+695695+ defer h.Close()
696696+ return h.BulkEdit(c.Context(), args, status, priority, project, context, tags, addTags, removeTags)
697697+ },
698698+ }
699699+700700+ cmd.Flags().String("status", "", "Set status for all tasks")
701701+ cmd.Flags().String("priority", "", "Set priority for all tasks")
702702+ cmd.Flags().String("project", "", "Set project for all tasks")
703703+ cmd.Flags().String("context", "", "Set context for all tasks")
704704+ cmd.Flags().StringSlice("tags", []string{}, "Set tags for all tasks")
705705+ cmd.Flags().Bool("add-tags", false, "Add tags instead of replacing")
706706+ cmd.Flags().Bool("remove-tags", false, "Remove specified tags")
707707+708708+ return cmd
709709+}
710710+711711+func taskUndoCmd(h *handlers.TaskHandler) *cobra.Command {
712712+ cmd := &cobra.Command{
713713+ Use: "undo <task-id>",
714714+ Short: "Undo the last change to a task",
715715+ Long: `Revert a task to its previous state before the last update.
716716+717717+This command uses the task history to restore the task to how it was
718718+before the most recent modification.
719719+720720+Examples:
721721+ noteleaf todo undo 1
722722+ noteleaf todo undo abc-123-uuid`,
723723+ Args: cobra.ExactArgs(1),
724724+ RunE: func(c *cobra.Command, args []string) error {
725725+ defer h.Close()
726726+ return h.UndoTask(c.Context(), args[0])
727727+ },
728728+ }
729729+730730+ return cmd
731731+}
732732+733733+func taskHistoryCmd(h *handlers.TaskHandler) *cobra.Command {
734734+ cmd := &cobra.Command{
735735+ Use: "history <task-id>",
736736+ Aliases: []string{"log"},
737737+ Short: "Show change history for a task",
738738+ Long: `Display the history of changes made to a task.
739739+740740+Shows a chronological list of modifications with timestamps.
741741+742742+Examples:
743743+ noteleaf todo history 1
744744+ noteleaf todo history 1 --limit 5`,
745745+ Args: cobra.ExactArgs(1),
746746+ RunE: func(c *cobra.Command, args []string) error {
747747+ limit, _ := c.Flags().GetInt("limit")
748748+ defer h.Close()
749749+ return h.ShowHistory(c.Context(), args[0], limit)
750750+ },
751751+ }
752752+753753+ cmd.Flags().IntP("limit", "n", 10, "Limit number of history entries")
754754+755755+ return cmd
756756+}
+5
cmd/task_flags.go
···3131func addDueDateFlag(cmd *cobra.Command) {
3232 cmd.Flags().StringP("due", "d", "", "Set due date (YYYY-MM-DD)")
3333}
3434+3535+func addWaitScheduledFlags(cmd *cobra.Command) {
3636+ cmd.Flags().StringP("wait", "w", "", "Task not actionable until date (YYYY-MM-DD)")
3737+ cmd.Flags().StringP("scheduled", "s", "", "Task scheduled to start on date (YYYY-MM-DD)")
3838+}
+13
cmd/tools_dev.go
···11+//go:build !prod
22+33+package main
44+55+import (
66+ "github.com/spf13/cobra"
77+ "github.com/stormlightlabs/noteleaf/tools"
88+)
99+1010+// registerTools adds development tools to the root command
1111+func registerTools(root *cobra.Command) {
1212+ root.AddCommand(tools.NewToolsCommand(root))
1313+}
+8
cmd/tools_prod.go
···11+//go:build prod
22+33+package main
44+55+import "github.com/spf13/cobra"
66+77+// registerTools is a no-op in production builds
88+func registerTools(*cobra.Command) {}
+193-42
internal/docs/ROADMAP.md
···4455## Core Usability
6677-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.
77+The foundation across all domains is implemented. Tasks support CRUD operations, projects, tags, contexts, and time tracking.
88+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.
89910## RC
1011···4344#### Publication
44454546- [x] Implement authentication with BlueSky/leaflet (AT Protocol).
4646- - [ ] Add OAuth2
4747+ - [ ] Add [OAuth2](#publications--authentication)
4748- [x] Verify `pub pull` fetches and syncs documents from leaflet.
4849- [x] Confirm `pub list` with status filtering (`all`, `published`, `draft`).
4949-- [ ] Test `pub post` creates new documents with draft/preview/validate modes.
5050-- [ ] Ensure `pub patch` updates existing documents correctly.
5151-- [ ] Validate `pub push` handles batch operations (create/update).
5252-- [ ] Verify markdown conversion to leaflet block format (headings, code, images, facets).
5050+- [x] Test `pub post` creates new documents with draft/preview/validate modes.
5151+- [x] Ensure `pub patch` updates existing documents correctly.
5252+- [x] Validate `pub push` handles batch operations (create/update).
5353+- [x] Verify markdown conversion to leaflet block format (headings, code, images, facets).
53545455### Media Domains
5556···109110 - Invalid IDs
110111 - Invalid flags
111112 - Schema corruption (already tested in repo)
112112-- [ ] Test cross-platform behavior (Linux/macOS/Windows).
113113114114### Packaging
115115···125125126126### Tasks
127127128128-- [ ] Model
129129- - [ ] Dependencies
130130- - [ ] Recurrence (`recur`, `until`, templates)
131131- - [ ] Wait/scheduled dates
132132- - [ ] Urgency scoring
133133-- [ ] Operations
134134- - [ ] `annotate`
135135- - [ ] Bulk edit and undo/history
136136- - [ ] `$EDITOR` integration
137137-- [ ] Reports and Views
138138- - [ ] Next actions
139139- - [ ] Completed/waiting/blocked reports
140140- - [ ] Calendar view
141141- - [ ] Sorting and urgency-based views
128128+- [x] Model
129129+ - [x] Dependencies
130130+ - [x] Recurrence (`recur`, `until`, templates)
131131+ - [x] Wait/scheduled dates
132132+ - [x] Urgency scoring
133133+- [x] Operations
134134+ - [x] `annotate`
135135+ - [x] Bulk edit and undo/history
136136+- [x] Reports and Views
137137+ - [x] Next actions
138138+ - [x] Completed/waiting/blocked reports
139139+ - [x] Calendar view
140140+ - [x] Sorting and urgency-based views
142141- [ ] Queries and Filters
143142 - [ ] Rich query language
144143 - [ ] Saved filters and aliases
···149148### Notes
150149151150- [ ] Commands
152152- - [ ] `note search`
151151+ - [x] `note search` - TF-IDF search via `search query` command
153152 - [ ] `note tag`
154153 - [ ] `note recent`
155154 - [ ] `note templates`
156155 - [ ] `note archive`
157156 - [ ] `note export`
158157- [ ] Features
159159- - [ ] Full-text search
158158+ - [x] Full-text search - TF-IDF ranking with Unicode tokenization
160159 - [ ] Linking between notes, tasks, and media
161160161161+### Search
162162+163163+#### Ranking Improvements
164164+165165+- [ ] BM25 scoring algorithm
166166+ - [ ] Implement Okapi BM25 with configurable parameters (k1, b)
167167+ - [ ] Field-aware BM25F with title/body weighting
168168+ - [ ] Pluggable scoring strategy interface (TF-IDF/BM25 interchangeable)
169169+ - [ ] Benchmark against TF-IDF on sample corpus
170170+171171+#### Query Features
172172+173173+- [ ] Phrase and proximity queries
174174+ - [ ] Positional inverted index (track term positions in documents)
175175+ - [ ] Exact phrase matching (`"go programming"`)
176176+ - [ ] Proximity scoring (boost when terms appear near each other)
177177+- [ ] Query understanding
178178+ - [ ] Synonym expansion with configurable dictionaries
179179+ - [ ] Boolean operators (AND, OR, NOT)
180180+ - [ ] Field-specific queries (`title:golang body:concurrency`)
181181+ - [ ] Spelling correction with edit distance suggestions
182182+ - [ ] Query boosting syntax (`title^3 golang`)
183183+184184+#### Linguistic Processing
185185+186186+- [ ] Text normalization
187187+ - [ ] Porter stemmer for English (run/runs/running โ run)
188188+ - [ ] Stopword filtering with domain-specific lists
189189+ - [ ] Unicode normalization and diacritic folding
190190+ - [ ] Configurable token filter pipeline
191191+- [ ] Multi-language support
192192+ - [ ] Language detection
193193+ - [ ] Language-specific stemmers
194194+ - [ ] CJK tokenization improvements
195195+196196+#### Advanced Scoring
197197+198198+- [ ] Learning to Rank
199199+ - [ ] Feature extraction (TF-IDF/BM25 scores, term coverage, recency)
200200+ - [ ] Click-through rate tracking for relevance feedback
201201+ - [ ] Gradient-boosted tree models for re-ranking
202202+ - [ ] Evaluation metrics (NDCG, MAP)
203203+- [ ] Non-text signals
204204+ - [ ] Document recency scoring
205205+ - [ ] Tag-based relevance
206206+ - [ ] User interaction signals
207207+208208+#### Index Management
209209+210210+- [ ] Persistence and optimization
211211+ - [ ] On-disk index snapshots (gob serialization)
212212+ - [ ] Segmented indexing with periodic merging (Lucene-style)
213213+ - [ ] Incremental updates (add/update/delete without full rebuild)
214214+ - [ ] Index versioning and rollback
215215+ - [ ] Compression for large corpora
216216+- [ ] Performance
217217+ - [ ] Index build benchmarks vs corpus size
218218+ - [ ] Query latency monitoring
219219+ - [ ] Memory usage profiling
220220+ - [ ] Concurrent search support
221221+222222+#### User Experience
223223+224224+- [ ] Interactive search interface
225225+ - [ ] TUI with real-time search-as-you-type
226226+ - [ ] Result navigation with vim keybindings
227227+ - [ ] Preview pane showing full note content
228228+ - [ ] Filtering by tags, date ranges, doc kind
229229+ - [ ] Sort options (relevance, date, alphabetical)
230230+ - [ ] Quick actions (open in editor, copy ID, tag)
231231+- [ ] Search result display
232232+ - [ ] Snippet generation with matched term highlighting
233233+ - [ ] Configurable result limit and pagination
234234+ - [ ] Score explanation mode (`--explain` flag)
235235+ - [ ] Export results to JSON/CSV
236236+- [ ] CLI
237237+ - [ ] Saved search queries and aliases
238238+ - [ ] Search history
239239+ - [ ] Query latency and result count in output
240240+ - [ ] Color-coded relevance scores
241241+162242### Media
163243164244- [ ] Articles/papers/blogs
···199279- [ ] External imports (Goodreads, IMDB, Letterboxd)
200280- [ ] Cross-referencing across media types
201281- [ ] Analytics: velocity, completion rates
282282+- [ ] Books (Open Library integration enhancements)
283283+ - [ ] Author detail fetching (full names, bio)
284284+ - [ ] Edition-specific metadata
285285+ - [ ] Cover image download and caching
286286+ - [ ] Reading progress tracking
287287+ - [ ] Personal reading lists sync
288288+- [ ] Movies/TV (external API integration)
289289+ - [ ] Movie databases (TMDb, OMDb)
290290+ - [ ] Rotten Tomatoes integration
291291+- [ ] Music
292292+ - [ ] Music services (MusicBrainz, Album of the Year)
202293203294### Articles
204295···206297- [ ] Export to multiple formats
207298- [ ] Linking with tasks and notes
208299300300+### Publications & Authentication
301301+302302+- [ ] OAuth2 authentication for AT Protocol
303303+ - [ ] Client metadata server for publishing application details
304304+ - [ ] DPoP (Demonstrating Proof of Possession) implementation
305305+ - [ ] ES256 JWT generation with unique JTI nonces
306306+ - [ ] Server-issued nonce management with 5-minute rotation
307307+ - [ ] Separate nonce tracking for authorization and resource servers
308308+ - [ ] PAR (Pushed Authorization Requests) flow
309309+ - [ ] PKCE code challenge generation
310310+ - [ ] State token management
311311+ - [ ] Request URI handling
312312+ - [ ] Identity resolution and verification
313313+ - [ ] Bidirectional handle verification
314314+ - [ ] DID resolution from handles
315315+ - [ ] Authorization server discovery via .well-known endpoints
316316+ - [ ] Token lifecycle management
317317+ - [ ] Access token refresh (5-15 min lifetime recommended)
318318+ - [ ] Refresh token rotation (180 day max for confidential clients)
319319+ - [ ] Concurrent request handling to prevent duplicate refreshes
320320+ - [ ] Secure token storage (encrypted at rest)
321321+ - [ ] Local callback server for OAuth redirects
322322+ - [ ] Ephemeral HTTP server on localhost
323323+ - [ ] Browser launch integration
324324+ - [ ] Timeout handling for abandoned flows
325325+ - [ ] Support both OAuth & App Passwords but recommend OAuth
326326+- [ ] Leaflet.pub enhancements
327327+ - [ ] Multiple Publications: Manage separate publications for different topics
328328+ - [ ] Image Upload: Automatically upload images to blob storage and embed in documents
329329+ - [ ] Status Management: Publish drafts and unpublish documents from CLI
330330+ - [ ] Metadata Editing: Update document titles, summaries, and tags
331331+ - [ ] Backlink Support: Parse and resolve cross-references between documents
332332+ - [ ] Offline Mode: Queue posts and patches for later upload
333333+209334### User Experience
210335211336- [ ] Shell completions
212337- [ ] Manpages and docs generator
213338- [ ] Theming and customizable output
214339- [ ] Calendar integration
340340+- [ ] Task synchronization services
341341+- [ ] Git repository linking
342342+- [ ] Note export to other platforms
215343216344### Tasks
217345···243371244372### Local API Server
245373246246-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.
374374+A local HTTP server daemon that exposes Noteleaf data for web UIs and extensions.
375375+Runs on the user's machine and provides programmatic access to tasks, notes, and media.
247376248377#### Architecture
249378···371500#### Post v1
372501373502- Backup/restore
503503+ - [ ] Automated backups
504504+ - [ ] Backup scheduling and rotation
374505- Multiple profiles
375506- Optional synchronization
507507+ - [ ] Sync service
508508+- Import/Export
509509+ - [ ] CSV export for tasks
510510+ - [ ] Markdown export for tasks
511511+ - [ ] Bulk export commands
512512+ - [ ] Migration utilities (TaskWarrior, todo.txt, etc.)
513513+ - [ ] Git integration for notes/data versioning
376514377515## v1 Feature Matrix
378516379379-| Domain | Feature | Status |
380380-|----------|-----------------------|-----------|
381381-| Tasks | CRUD | Complete |
382382-| Tasks | Projects/tags | Complete |
383383-| Tasks | Time tracking | Complete |
384384-| Tasks | Dependencies | Complete |
385385-| Tasks | Recurrence | Complete |
386386-| Tasks | Wait/scheduled | Planned |
387387-| Tasks | Urgency scoring | Planned |
388388-| Notes | CRUD | Complete |
389389-| Notes | Search/tagging | Planned |
390390-| Media | Books/movies/TV | Complete |
391391-| Media | Articles | Complete |
392392-| Media | Source/ratings | Planned |
393393-| Articles | Parser + storage | Complete |
394394-| System | SQLite persistence | Complete |
395395-| System | Synchronization | Future |
396396-| System | Import/export formats | Future |
517517+| Domain | Feature | Status |
518518+|--------------|----------------------------|-----------|
519519+| Tasks | CRUD | Complete |
520520+| Tasks | Projects/tags | Complete |
521521+| Tasks | Time tracking | Complete |
522522+| Tasks | Dependencies | Complete |
523523+| Tasks | Recurrence | Complete |
524524+| Tasks | Wait/scheduled | Complete |
525525+| Tasks | Urgency scoring | Complete |
526526+| Tasks | Reports and views | Complete |
527527+| Notes | CRUD | Complete |
528528+| Notes | Search (TF-IDF) | Complete |
529529+| Notes | Advanced search | Planned |
530530+| Notes | Tagging | Planned |
531531+| Publications | AT Protocol sync | Complete |
532532+| Publications | Post/patch/push | Complete |
533533+| Publications | Markdown conversion | Complete |
534534+| Publications | OAuth2 | Future |
535535+| Media | Books/movies/TV | Complete |
536536+| Media | Articles | Complete |
537537+| Media | Source/ratings | Planned |
538538+| Articles | Parser + storage | Complete |
539539+| System | SQLite persistence | Complete |
540540+| System | Configuration management | Complete |
541541+| System | Synchronization | Future |
542542+| System | Import/export formats | Future |
543543+544544+## Parking Lot
545545+546546+- [ ] Test cross-platform behavior (Linux/macOS/Windows).
547547+- [ ] `$EDITOR` integration
+153
internal/documents/documents.go
···11+// Term Frequency-Inverse Document Frequency search model for notes
22+package documents
33+44+import (
55+ "math"
66+ "regexp"
77+ "sort"
88+ "strings"
99+ "time"
1010+)
1111+1212+type DocKind int64
1313+1414+const (
1515+ NoteDoc DocKind = iota
1616+ ArticleDoc
1717+ MovieDoc
1818+ BookDoc
1919+ TVDoc
2020+)
2121+2222+type Document struct {
2323+ ID int64
2424+ Title string
2525+ Body string
2626+ CreatedAt time.Time
2727+ DocKind int64
2828+}
2929+3030+type Posting struct {
3131+ DocID int64
3232+ TF int
3333+}
3434+3535+type Index struct {
3636+ Postings map[string][]Posting
3737+ DocLengths map[int64]int
3838+ NumDocs int
3939+}
4040+4141+type Result struct {
4242+ DocID int64
4343+ Score float64
4444+}
4545+4646+type Searchable interface {
4747+ Search(query string, limit int) ([]Result, error)
4848+}
4949+5050+// Tokenizer handles text tokenization and normalization
5151+type Tokenizer struct {
5252+ pattern *regexp.Regexp
5353+}
5454+5555+// NewTokenizer creates a new tokenizer with Unicode-aware word/number matching
5656+func NewTokenizer() *Tokenizer {
5757+ return &Tokenizer{
5858+ pattern: regexp.MustCompile(`\p{L}+\p{M}*|\p{N}+`),
5959+ }
6060+}
6161+6262+// Tokenize splits text into normalized tokens (lowercase words and numbers)
6363+func (t *Tokenizer) Tokenize(text string) []string {
6464+ lowered := strings.ToLower(text)
6565+ return t.pattern.FindAllString(lowered, -1)
6666+}
6767+6868+// TokenFrequency computes term frequency map for tokens
6969+func TokenFrequency(tokens []string) map[string]int {
7070+ freq := make(map[string]int)
7171+ for _, token := range tokens {
7272+ freq[token]++
7373+ }
7474+ return freq
7575+}
7676+7777+// BuildIndex constructs a TF-IDF index from a collection of documents
7878+func BuildIndex(docs []Document) *Index {
7979+ idx := &Index{
8080+ Postings: make(map[string][]Posting),
8181+ DocLengths: make(map[int64]int),
8282+ NumDocs: 0,
8383+ }
8484+8585+ tokenizer := NewTokenizer()
8686+8787+ for _, doc := range docs {
8888+ text := doc.Title + " " + doc.Body
8989+ tokens := tokenizer.Tokenize(text)
9090+9191+ idx.NumDocs++
9292+ idx.DocLengths[doc.ID] = len(tokens)
9393+9494+ freq := TokenFrequency(tokens)
9595+9696+ for term, tf := range freq {
9797+ idx.Postings[term] = append(idx.Postings[term], Posting{
9898+ DocID: doc.ID,
9999+ TF: tf,
100100+ })
101101+ }
102102+ }
103103+104104+ return idx
105105+}
106106+107107+// Search performs TF-IDF ranked search on the index
108108+func (idx *Index) Search(query string, limit int) ([]Result, error) {
109109+ tokenizer := NewTokenizer()
110110+ queryTokens := tokenizer.Tokenize(query)
111111+112112+ if len(queryTokens) == 0 {
113113+ return []Result{}, nil
114114+ }
115115+116116+ scores := make(map[int64]float64)
117117+118118+ for _, term := range queryTokens {
119119+ postings, exists := idx.Postings[term]
120120+ if !exists {
121121+ continue
122122+ }
123123+124124+ df := len(postings)
125125+ idf := math.Log(float64(idx.NumDocs) / float64(df))
126126+127127+ for _, posting := range postings {
128128+ tf := float64(posting.TF)
129129+ scores[posting.DocID] += tf * idf
130130+ }
131131+ }
132132+133133+ results := make([]Result, 0, len(scores))
134134+ for docID, score := range scores {
135135+ results = append(results, Result{
136136+ DocID: docID,
137137+ Score: score,
138138+ })
139139+ }
140140+141141+ sort.Slice(results, func(i, j int) bool {
142142+ if results[i].Score != results[j].Score {
143143+ return results[i].Score > results[j].Score
144144+ }
145145+ return results[i].DocID > results[j].DocID
146146+ })
147147+148148+ if limit > 0 && limit < len(results) {
149149+ results = results[:limit]
150150+ }
151151+152152+ return results, nil
153153+}
···11+CREATE TABLE IF NOT EXISTS documents (
22+ id INTEGER PRIMARY KEY AUTOINCREMENT,
33+ title TEXT NOT NULL,
44+ body TEXT NOT NULL,
55+ created_at DATETIME NOT NULL,
66+ doc_kind INTEGER NOT NULL
77+);
88+99+CREATE INDEX IF NOT EXISTS idx_documents_doc_kind ON documents(doc_kind);
1010+CREATE INDEX IF NOT EXISTS idx_documents_created_at ON documents(created_at);
···11+-- Task history table for undo functionality
22+CREATE TABLE IF NOT EXISTS task_history (
33+ id INTEGER PRIMARY KEY AUTOINCREMENT,
44+ task_id INTEGER NOT NULL,
55+ operation TEXT NOT NULL, -- 'update', 'delete'
66+ snapshot TEXT NOT NULL, -- JSON snapshot of task before operation
77+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
88+);
99+1010+CREATE INDEX IF NOT EXISTS idx_task_history_task_id ON task_history(task_id);
1111+CREATE INDEX IF NOT EXISTS idx_task_history_created_at ON task_history(created_at);
···493493 }
494494 })
495495496496- t.Run("formatPublicationForView", func(t *testing.T) {
496496+ t.Run("buildPublicationMarkdown", func(t *testing.T) {
497497 t.Run("formats published note with all metadata", func(t *testing.T) {
498498 rkey := "test-rkey"
499499 cid := "test-cid"
···510510 LeafletCID: &cid,
511511 }
512512513513- result := formatPublicationForView(note)
513513+ result := buildPublicationMarkdown(note)
514514515515 if !strings.Contains(result, "Test Article") {
516516- t.Errorf("Formatted view should contain title\nGot: %s", result)
516516+ t.Error("Markdown should contain title")
517517 }
518518 if !strings.Contains(result, "published") {
519519- t.Errorf("Formatted view should contain status 'published'\nGot: %s", result)
519519+ t.Error("Markdown should contain status 'published'")
520520 }
521521 if !strings.Contains(result, "2024-01-15") {
522522- t.Errorf("Formatted view should contain published date\nGot: %s", result)
522522+ t.Error("Markdown should contain published date")
523523 }
524524- if !strings.Contains(result, "Modified") && !strings.Contains(result, "2024-01-16") {
525525- t.Errorf("Formatted view should contain modified date\nGot: %s", result)
526526- }
527527- if !strings.Contains(result, "test-rkey") {
528528- t.Error("Formatted view should contain rkey")
529529- }
530530- if !strings.Contains(result, "test-cid") {
531531- t.Error("Formatted view should contain cid")
524524+ if !strings.Contains(result, "2024-01-16") {
525525+ t.Error("Markdown should contain modified date")
532526 }
533527 })
534528···541535 Modified: time.Date(2024, 1, 20, 14, 0, 0, 0, time.UTC),
542536 }
543537544544- result := formatPublicationForView(note)
538538+ result := buildPublicationMarkdown(note)
545539546540 if !strings.Contains(result, "Draft Article") {
547547- t.Error("Formatted view should contain title")
541541+ t.Error("Markdown should contain title")
548542 }
549543 if !strings.Contains(result, "draft") {
550550- t.Error("Formatted view should contain status 'draft'")
544544+ t.Error("Markdown should contain status 'draft'")
551545 }
552546 if strings.Contains(result, "Published:") {
553553- t.Error("Formatted draft view should not contain published date")
547547+ t.Error("Draft markdown should not contain published date")
554548 }
555549 if !strings.Contains(result, "2024-01-20 14:00") {
556556- t.Error("Formatted view should contain modified date")
550550+ t.Error("Markdown should contain modified date")
557551 }
558552 })
559553···566560 Modified: time.Now(),
567561 }
568562569569- result := formatPublicationForView(note)
563563+ result := buildPublicationMarkdown(note)
570564571565 if !strings.Contains(result, "Plain Content") {
572572- t.Error("Formatted view should contain title")
566566+ t.Error("Markdown should contain title")
573567 }
574568 if !strings.Contains(result, "This content has no markdown header") {
575575- t.Error("Formatted view should contain full content")
569569+ t.Error("Markdown should contain full content")
576570 }
577571 })
578572···585579 Modified: time.Now(),
586580 }
587581588588- result := formatPublicationForView(note)
582582+ result := buildPublicationMarkdown(note)
589583590584 titleCount := strings.Count(result, "Article Title")
591585 if titleCount < 1 {
592592- t.Error("Formatted view should contain title at least once")
586586+ t.Error("Markdown should contain title at least once")
593587 }
594588 if !strings.Contains(result, "Content after title") {
595595- t.Error("Formatted view should contain content after title")
589589+ t.Error("Markdown should contain content after title")
596590 }
597591 })
598592 })
+50-45
internal/ui/publication_view.go
···55 "fmt"
66 "io"
77 "os"
88- "strings"
88+ "unicode/utf8"
991010 "github.com/charmbracelet/bubbles/help"
1111 "github.com/charmbracelet/bubbles/key"
···162162 status = "draft"
163163 }
164164165165- title := TitleColorStyle.Render(fmt.Sprintf("%s (%s)", m.note.Title, status))
165165+ title := TableTitleStyle.Render(fmt.Sprintf("%s (%s)", m.note.Title, status))
166166 content := m.viewport.View()
167167- help := lipgloss.NewStyle().Foreground(lipgloss.Color(Squid.Hex())).Render(m.help.View(m.keys))
167167+ help := MutedStyle.Render(m.help.View(m.keys))
168168169169 if !m.ready {
170170 return "\n Initializing..."
···173173 return lipgloss.JoinVertical(lipgloss.Left, title, "", content, "", help)
174174}
175175176176-// buildPublicationMarkdown creates the markdown content for rendering
177177-func buildPublicationMarkdown(note *models.Note) string {
178178- var content strings.Builder
179179-180180- content.WriteString("# " + note.Title + "\n\n")
181181-182182- status := "published"
183183- if note.IsDraft {
184184- status = "draft"
185185- }
186186- content.WriteString("**Status:** " + status + "\n")
187187-188188- if note.PublishedAt != nil {
189189- content.WriteString("**Published:** " + note.PublishedAt.Format("2006-01-02 15:04") + "\n")
190190- }
191191-192192- content.WriteString("**Modified:** " + note.Modified.Format("2006-01-02 15:04") + "\n")
193193-194194- if note.LeafletRKey != nil {
195195- content.WriteString("**RKey:** `" + *note.LeafletRKey + "`\n")
196196- }
197197-198198- if note.LeafletCID != nil {
199199- content.WriteString("**CID:** `" + *note.LeafletCID + "`\n")
200200- }
201201-202202- content.WriteString("\n---\n\n")
203203-204204- noteContent := strings.TrimSpace(note.Content)
205205- if !strings.HasPrefix(noteContent, "# ") {
206206- content.WriteString(noteContent)
207207- } else {
208208- lines := strings.Split(noteContent, "\n")
209209- if len(lines) > 1 {
210210- content.WriteString(strings.Join(lines[1:], "\n"))
211211- }
212212- }
213213-214214- return content.String()
215215-}
216216-217176// formatPublicationContent renders markdown with glamour for viewport display
218177func formatPublicationContent(note *models.Note) (string, error) {
219178 markdown := buildPublicationMarkdown(note)
220179221180 renderer, err := glamour.NewTermRenderer(
222181 glamour.WithAutoStyle(),
223223- glamour.WithWordWrap(80),
182182+ glamour.WithStandardStyle("tokyo-night"),
183183+ glamour.WithPreservedNewLines(),
184184+ glamour.WithWordWrap(79),
224185 )
225186 if err != nil {
226187 return markdown, fmt.Errorf("failed to create renderer: %w", err)
···277238 fmt.Fprint(pv.opts.Output, content)
278239 return nil
279240}
241241+242242+// ObfuscateMiddle returns a string where the middle portion is replaced by "..."
243243+// TODO: move to package utils or shared
244244+func ObfuscateMiddle(s string, left, right int) string {
245245+ if s == "" {
246246+ return s
247247+ }
248248+ if left < 0 {
249249+ left = 0
250250+ }
251251+ if right < 0 {
252252+ right = 0
253253+ }
254254+255255+ n := utf8.RuneCountInString(s)
256256+ if left+right >= n {
257257+ return s
258258+ }
259259+260260+ var (
261261+ prefixRunes = make([]rune, 0, left)
262262+ suffixRunes = make([]rune, 0, right)
263263+ )
264264+ i := 0
265265+ for _, r := range s {
266266+ if i >= left {
267267+ break
268268+ }
269269+ prefixRunes = append(prefixRunes, r)
270270+ i++
271271+ }
272272+273273+ if right > 0 {
274274+ allRunes := []rune(s)
275275+ start := max(n-right, 0)
276276+ suffixRunes = append(suffixRunes, allRunes[start:]...)
277277+ }
278278+279279+ const repl = "..."
280280+ if right == 0 {
281281+ return string(prefixRunes) + repl
282282+ }
283283+ return string(prefixRunes) + repl + string(suffixRunes)
284284+}
+11-11
internal/ui/publication_view_test.go
···138138139139 output := buf.String()
140140141141- if !strings.Contains(output, "Test Publication") {
141141+ if !strings.Contains(output, "Test") || !strings.Contains(output, "Publication") {
142142 t.Error("Note title not displayed")
143143 }
144144 if !strings.Contains(output, "published") {
···153153 if !strings.Contains(output, "RKey:") {
154154 t.Error("RKey not displayed")
155155 }
156156- if !strings.Contains(output, "test-rkey-123") {
156156+ if !strings.Contains(output, "tes") || !strings.Contains(output, "123") {
157157 t.Error("RKey value not displayed")
158158 }
159159 if !strings.Contains(output, "CID:") {
160160 t.Error("CID not displayed")
161161 }
162162- if !strings.Contains(output, "test-cid-456") {
162162+ if !strings.Contains(output, "tes") || !strings.Contains(output, "456") {
163163 t.Error("CID value not displayed")
164164 }
165165- if !strings.Contains(output, "This is the content") {
165165+ if !strings.Contains(output, "This") || !strings.Contains(output, "content") {
166166 t.Error("Note content not displayed")
167167 }
168168 })
···213213214214 output := buf.String()
215215216216- if !strings.Contains(output, "Minimal Note") {
216216+ if !strings.Contains(output, "Minimal") || !strings.Contains(output, "Note") {
217217 t.Error("Note title not displayed")
218218 }
219219- if !strings.Contains(output, "Simple content") {
219219+ if !strings.Contains(output, "Simple") || !strings.Contains(output, "content") {
220220 t.Error("Note content not displayed")
221221 }
222222 if !strings.Contains(output, "Modified:") {
···235235 "**Status:** published",
236236 "**Published:**",
237237 "**Modified:**",
238238- "**RKey:** `test-rkey-123`",
239239- "**CID:** `test-cid-456`",
238238+ "**RKey:**",
239239+ "**CID:**",
240240 "---",
241241 "This is the content",
242242 }
···308308 t.Fatalf("formatPublicationContent failed: %v", err)
309309 }
310310311311- if !strings.Contains(content, "Test Publication") {
311311+ if !strings.Contains(content, "Test") || !strings.Contains(content, "Publication") {
312312 t.Error("Formatted content should include note title")
313313 }
314314 })
···634634 t.Error("No output generated")
635635 }
636636637637- if !strings.Contains(output, note.Title) {
637637+ if !strings.Contains(output, "Test") || !strings.Contains(output, "Publication") {
638638 t.Error("Note title not displayed")
639639 }
640640- if !strings.Contains(output, "This is the content") {
640640+ if !strings.Contains(output, "This") || !strings.Contains(output, "content") {
641641 t.Error("Note content not displayed")
642642 }
643643 })
+4-4
internal/ui/task_edit.go
···350350351351 var content strings.Builder
352352353353- title := TitleColorStyle.Render("Edit Task")
353353+ title := TableTitleStyle.Render("Edit Task")
354354 content.WriteString(title + "\n\n")
355355356356 for i, field := range m.fields {
357357 fieldStyle := lipgloss.NewStyle()
358358 if i == m.currentField && m.mode == fieldNavigation {
359359- fieldStyle = SelectedColorStyle
359359+ fieldStyle = TableSelectedStyle
360360 }
361361362362 switch field {
···427427 for i, status := range statusOptions {
428428 style := lipgloss.NewStyle()
429429 if i == m.statusIndex {
430430- style = SelectedColorStyle
430430+ style = TableSelectedStyle
431431 }
432432433433 line := fmt.Sprintf("%s %s", FormatStatusIndicator(status), status)
···460460 for i, priority := range options {
461461 style := lipgloss.NewStyle()
462462 if i == m.priorityIndex {
463463- style = SelectedColorStyle
463463+ style = TableSelectedStyle
464464 }
465465466466 var line string
+14-26
internal/ui/task_information.go
···4444 PriorityNonePattern = "โโโ"
4545)
46464747+// Type aliases for status and priority styles (now defined in palette.go)
4748var (
4848- // Gray
4949- TodoStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
5050- // Blue
5151- InProgressStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("12"))
5252- // Red
5353- BlockedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("9"))
5454- // Green
5555- DoneStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("10"))
5656- // Dark Gray
5757- AbandonedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
5858- // Light Gray
5959- PendingStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("7"))
6060- // Green
6161- CompletedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("10"))
6262- // Dark Red
6363- DeletedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("1"))
6464- // Bright Red - highest urgency
6565- PriorityHighStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("196"))
6666- // Yellow - medium urgency
6767- PriorityMediumStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("11"))
6868- // Cyan - low urgency
6969- PriorityLowStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("14"))
7070- // Gray - no priority
7171- PriorityNoneStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
7272- // For legacy A-Z and numeric priorities
7373- PriorityLegacyStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("13")) // Magenta
4949+ TodoStyle = StatusTodo
5050+ InProgressStyle = StatusInProgress
5151+ BlockedStyle = StatusBlocked
5252+ DoneStyle = StatusDone
5353+ AbandonedStyle = StatusAbandoned
5454+ PendingStyle = StatusPending
5555+ CompletedStyle = StatusCompleted
5656+ DeletedStyle = StatusDeleted
5757+ PriorityHighStyle = PriorityHigh
5858+ PriorityMediumStyle = PriorityMedium
5959+ PriorityLowStyle = PriorityLow
6060+ PriorityNoneStyle = PriorityNone
6161+ PriorityLegacyStyle = PriorityLegacy
7462)
75637664// GetStatusSymbol returns the unicode symbol for a given status
+2-2
internal/ui/task_view.go
···157157 return m.help.View(m.keys)
158158 }
159159160160- title := TitleColorStyle.Render(fmt.Sprintf("Task %d", m.task.ID))
160160+ title := TableTitleStyle.Render(fmt.Sprintf("Task %d", m.task.ID))
161161 content := m.viewport.View()
162162- help := lipgloss.NewStyle().Foreground(lipgloss.Color(Squid.Hex())).Render(m.help.View(m.keys))
162162+ help := MutedStyle.Render(m.help.View(m.keys))
163163164164 return lipgloss.JoinVertical(lipgloss.Left, title, "", content, "", help)
165165}
+3-6
tools/docgen.go
···11+//go:build !prod
22+13package tools
2435import (
···324326 }
325327326328 for _, cmd := range root.Commands() {
327327- if cmd.Name() == path[0] || contains(cmd.Aliases, path[0]) {
329329+ if cmd.Name() == path[0] || slices.Contains(cmd.Aliases, path[0]) {
328330 if len(path) == 1 {
329331 return cmd
330332 }
···334336335337 return nil
336338}
337337-338338-// contains checks if a string is in a slice
339339-func contains(slice []string, str string) bool {
340340- return slices.Contains(slice, str)
341341-}
+21
tools/fetch.go
···11+//go:build !prod
22+33+package tools
44+55+import "github.com/spf13/cobra"
66+77+// NewFetchCommand creates a parent command for fetching remote resources
88+func NewFetchCommand() *cobra.Command {
99+ cmd := &cobra.Command{
1010+ Use: "fetch",
1111+ Short: "Fetch remote resources",
1212+ Long: `Fetch and synchronize remote resources from GitHub repositories.
1313+1414+Includes commands for fetching lexicons, schemas, and other data files.`,
1515+ }
1616+1717+ cmd.AddCommand(NewGHRepoCommand())
1818+ cmd.AddCommand(NewLexiconsCommand())
1919+2020+ return cmd
2121+}
+51
tools/lexicon_fetch.go
···11+//go:build !prod
22+33+package tools
44+55+import (
66+ "context"
77+88+ "github.com/spf13/cobra"
99+)
1010+1111+// NewLexiconsCommand creates a command for fetching Leaflet lexicons
1212+func NewLexiconsCommand() *cobra.Command {
1313+ var sha string
1414+ var output string
1515+1616+ cmd := &cobra.Command{
1717+ Use: "lexicons",
1818+ Short: "Fetch Leaflet lexicons from GitHub",
1919+ Long: `Fetches Leaflet lexicons from the hyperlink-academy/leaflet repository.
2020+2121+This is a convenience wrapper around gh-repo with pre-configured defaults
2222+for the Leaflet lexicon repository.`,
2323+ Example: ` # Fetch latest lexicons
2424+ noteleaf tools fetch lexicons
2525+2626+ # Fetch from a specific commit
2727+ noteleaf tools fetch lexicons --sha abc123def
2828+2929+ # Fetch to a custom directory
3030+ noteleaf tools fetch lexicons --output ./tmp/lexicons`,
3131+ RunE: func(cmd *cobra.Command, args []string) error {
3232+ config := ArchiveConfig{
3333+ Repo: "hyperlink-academy/leaflet",
3434+ Path: "lexicons/pub/leaflet/",
3535+ Output: output,
3636+ SHA: sha,
3737+ FormatJSON: true,
3838+ }
3939+4040+ ctx := cmd.Context()
4141+ if ctx == nil {
4242+ ctx = context.Background()
4343+ }
4444+4545+ return fetchAndExtractArchive(ctx, config, cmd.OutOrStdout())
4646+ },
4747+ }
4848+ cmd.Flags().StringVar(&sha, "sha", "", "Specific commit SHA (default: latest)")
4949+ cmd.Flags().StringVar(&output, "output", "lexdocs/leaflet/", "Output directory for lexicons")
5050+ return cmd
5151+}
+19
tools/registry.go
···11+//go:build !prod
22+33+package tools
44+55+import "github.com/spf13/cobra"
66+77+// NewToolsCommand creates a parent command for all development tools
88+func NewToolsCommand(root *cobra.Command) *cobra.Command {
99+ cmd := &cobra.Command{
1010+ Use: "tools",
1111+ Short: "Development and maintenance tools",
1212+ Long: `Development tools for documentation generation, data synchronization,
1313+and maintenance tasks. These commands are only available in dev builds.`,
1414+ }
1515+ cmd.AddCommand(NewDocGenCommand(root))
1616+ cmd.AddCommand(NewFetchCommand())
1717+1818+ return cmd
1919+}
+251
tools/repo_archive.go
···11+//go:build !prod
22+33+package tools
44+55+import (
66+ "archive/tar"
77+ "compress/gzip"
88+ "context"
99+ "encoding/json"
1010+ "fmt"
1111+ "io"
1212+ "net/http"
1313+ "os"
1414+ "path/filepath"
1515+ "strings"
1616+ "time"
1717+1818+ "github.com/spf13/cobra"
1919+)
2020+2121+// GitHubCommit represents a GitHub API commit response
2222+type GitHubCommit struct {
2323+ SHA string `json:"sha"`
2424+ Commit struct {
2525+ Message string `json:"message"`
2626+ } `json:"commit"`
2727+}
2828+2929+// ArchiveConfig contains configuration for fetching and extracting archives
3030+type ArchiveConfig struct {
3131+ Repo string
3232+ Path string
3333+ Output string
3434+ SHA string
3535+ FormatJSON bool
3636+}
3737+3838+// NewGHRepoCommand creates a command for fetching GitHub repository archives
3939+func NewGHRepoCommand() *cobra.Command {
4040+ var config ArchiveConfig
4141+4242+ cmd := &cobra.Command{
4343+ Use: "gh-repo",
4444+ Short: "Fetch and extract files from a GitHub repository archive",
4545+ Long: `Fetches a GitHub repository archive (tarball), extracts specific paths,
4646+and optionally formats JSON files using Go's standard library.
4747+4848+This is useful for syncing lexicons, schemas, or other data files from GitHub repositories.`,
4949+ Example: ` # Fetch lexicons from a specific path
5050+ noteleaf tools fetch gh-repo \
5151+ --repo hyperlink-academy/leaflet \
5252+ --path lexicons/pub/leaflet/ \
5353+ --output lexdocs/leaflet/
5454+5555+ # Fetch from a specific commit
5656+ noteleaf tools fetch gh-repo \
5757+ --repo owner/repo \
5858+ --path schemas/ \
5959+ --output local/schemas/ \
6060+ --sha abc123def`,
6161+ RunE: func(cmd *cobra.Command, args []string) error {
6262+ if config.Repo == "" {
6363+ return fmt.Errorf("--repo is required")
6464+ }
6565+ if config.Path == "" {
6666+ return fmt.Errorf("--path is required")
6767+ }
6868+ if config.Output == "" {
6969+ return fmt.Errorf("--output is required")
7070+ }
7171+7272+ ctx := cmd.Context()
7373+ if ctx == nil {
7474+ ctx = context.Background()
7575+ }
7676+7777+ return fetchAndExtractArchive(ctx, config, cmd.OutOrStdout())
7878+ },
7979+ }
8080+8181+ cmd.Flags().StringVar(&config.Repo, "repo", "", "GitHub repository (owner/name)")
8282+ cmd.Flags().StringVar(&config.Path, "path", "", "Path within repository to extract")
8383+ cmd.Flags().StringVar(&config.Output, "output", "", "Output directory for extracted files")
8484+ cmd.Flags().StringVar(&config.SHA, "sha", "", "Specific commit SHA (default: latest)")
8585+ cmd.Flags().BoolVar(&config.FormatJSON, "format-json", true, "Format JSON files with indentation")
8686+ return cmd
8787+}
8888+8989+// fetchAndExtractArchive fetches a GitHub archive and extracts specific paths
9090+func fetchAndExtractArchive(ctx context.Context, config ArchiveConfig, out io.Writer) error {
9191+ sha := config.SHA
9292+ if sha == "" {
9393+ var err error
9494+ sha, err = getLatestCommit(ctx, config.Repo, config.Path)
9595+ if err != nil {
9696+ return fmt.Errorf("failed to get latest commit: %w", err)
9797+ }
9898+ fmt.Fprintf(out, "Latest commit: %s\n", sha)
9999+ }
100100+101101+ tmpDir, err := os.MkdirTemp("", "repo-archive-*")
102102+ if err != nil {
103103+ return fmt.Errorf("failed to create temp directory: %w", err)
104104+ }
105105+ defer os.RemoveAll(tmpDir)
106106+107107+ fmt.Fprintf(out, "Fetching archive for %s@%s\n", config.Repo, sha[:7])
108108+ if err := downloadAndExtract(ctx, config.Repo, sha, config.Path, tmpDir, config.FormatJSON, out); err != nil {
109109+ return fmt.Errorf("failed to download and extract: %w", err)
110110+ }
111111+112112+ fmt.Fprintf(out, "Writing README with source information\n")
113113+ readme := fmt.Sprintf("Source: https://github.com/%s/tree/%s/%s\n", config.Repo, sha, config.Path)
114114+ if err := os.WriteFile(filepath.Join(tmpDir, "README.md"), []byte(readme), 0o644); err != nil {
115115+ return fmt.Errorf("failed to write README: %w", err)
116116+ }
117117+118118+ fmt.Fprintf(out, "Moving extracted files to %s\n", config.Output)
119119+ if err := os.RemoveAll(config.Output); err != nil {
120120+ return fmt.Errorf("failed to remove existing output directory: %w", err)
121121+ }
122122+ if err := os.Rename(tmpDir, config.Output); err != nil {
123123+ return fmt.Errorf("failed to move files to output directory: %w", err)
124124+ }
125125+126126+ fmt.Fprintf(out, "Successfully extracted archive to %s\n", config.Output)
127127+ return nil
128128+}
129129+130130+// getLatestCommit fetches the latest commit SHA for a given repository and path
131131+func getLatestCommit(ctx context.Context, repo, path string) (string, error) {
132132+ url := fmt.Sprintf("https://api.github.com/repos/%s/commits?path=%s&per_page=1", repo, path)
133133+134134+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
135135+ if err != nil {
136136+ return "", err
137137+ }
138138+139139+ client := &http.Client{Timeout: 30 * time.Second}
140140+ resp, err := client.Do(req)
141141+ if err != nil {
142142+ return "", err
143143+ }
144144+ defer resp.Body.Close()
145145+146146+ if resp.StatusCode != http.StatusOK {
147147+ return "", fmt.Errorf("GitHub API returned status %d", resp.StatusCode)
148148+ }
149149+150150+ var commits []GitHubCommit
151151+ if err := json.NewDecoder(resp.Body).Decode(&commits); err != nil {
152152+ return "", fmt.Errorf("failed to decode response: %w", err)
153153+ }
154154+155155+ if len(commits) == 0 {
156156+ return "", fmt.Errorf("no commits found for path %s", path)
157157+ }
158158+159159+ return commits[0].SHA, nil
160160+}
161161+162162+// downloadAndExtract downloads a GitHub archive and extracts files from a specific path
163163+func downloadAndExtract(ctx context.Context, repo, sha, extractPath, outputDir string, formatJSON bool, out io.Writer) error {
164164+ url := fmt.Sprintf("https://github.com/%s/archive/%s.tar.gz", repo, sha)
165165+166166+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
167167+ if err != nil {
168168+ return err
169169+ }
170170+171171+ client := &http.Client{Timeout: 5 * time.Minute}
172172+ resp, err := client.Do(req)
173173+ if err != nil {
174174+ return err
175175+ }
176176+ defer resp.Body.Close()
177177+178178+ if resp.StatusCode != http.StatusOK {
179179+ return fmt.Errorf("failed to download archive: status %d", resp.StatusCode)
180180+ }
181181+182182+ gzr, err := gzip.NewReader(resp.Body)
183183+ if err != nil {
184184+ return fmt.Errorf("failed to create gzip reader: %w", err)
185185+ }
186186+ defer gzr.Close()
187187+188188+ tr := tar.NewReader(gzr)
189189+190190+ repoName := strings.Split(repo, "/")[1]
191191+ prefix := fmt.Sprintf("%s-%s/%s", repoName, sha, extractPath)
192192+193193+ fmt.Fprintf(out, "Extracting files from %s\n", prefix)
194194+195195+ fileCount := 0
196196+ for {
197197+ header, err := tr.Next()
198198+ if err == io.EOF {
199199+ break
200200+ }
201201+ if err != nil {
202202+ return fmt.Errorf("failed to read tar header: %w", err)
203203+ }
204204+205205+ if header.Typeflag != tar.TypeReg {
206206+ continue
207207+ }
208208+209209+ if !strings.HasPrefix(header.Name, prefix) {
210210+ continue
211211+ }
212212+213213+ if !strings.HasSuffix(header.Name, ".json") {
214214+ continue
215215+ }
216216+217217+ relativePath := strings.TrimPrefix(header.Name, prefix)
218218+ outputPath := filepath.Join(outputDir, relativePath)
219219+220220+ if err := os.MkdirAll(filepath.Dir(outputPath), 0o755); err != nil {
221221+ return fmt.Errorf("failed to create directory for %s: %w", outputPath, err)
222222+ }
223223+224224+ data, err := io.ReadAll(tr)
225225+ if err != nil {
226226+ return fmt.Errorf("failed to read file %s: %w", header.Name, err)
227227+ }
228228+229229+ if formatJSON {
230230+ var jsonData any
231231+ if err := json.Unmarshal(data, &jsonData); err != nil {
232232+ return fmt.Errorf("failed to parse JSON in %s: %w", header.Name, err)
233233+ }
234234+235235+ formattedData, err := json.MarshalIndent(jsonData, "", " ")
236236+ if err != nil {
237237+ return fmt.Errorf("failed to format JSON in %s: %w", header.Name, err)
238238+ }
239239+ data = append(formattedData, '\n')
240240+ }
241241+242242+ if err := os.WriteFile(outputPath, data, 0o644); err != nil {
243243+ return fmt.Errorf("failed to write file %s: %w", outputPath, err)
244244+ }
245245+246246+ fileCount++
247247+ }
248248+249249+ fmt.Fprintf(out, "Extracted %d files\n", fileCount)
250250+ return nil
251251+}
+68
website/TODO.md
···11+# Noteleaf Documentation TODO
22+33+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.
44+55+## Integration and Workflows
66+77+- [x] External Integrations
88+ - [x] Open Library API
99+ - [x] Leaflet.pub API
1010+ - [x] ATProto authentication
1111+- [ ] Workflows and Examples
1212+ - [ ] Daily task review workflow
1313+ - [ ] Note-taking for research
1414+ - [ ] Reading list management
1515+ - [ ] Publishing a blog post to leaflet.pub
1616+ - [ ] Linking tasks, notes, and media
1717+- [x] Import/Export
1818+ - [x] Exporting data
1919+ - [x] Backup and restore
2020+ - [x] Migration from other tools
2121+2222+## Development
2323+2424+- [x] Building Noteleaf
2525+ - [x] Development vs production builds
2626+ - [x] Build tags
2727+ - [x] Task automation (Taskfile)
2828+- [x] Testing
2929+ - [x] Running tests
3030+ - [x] Coverage reports
3131+ - [x] Test patterns and scaffolding
3232+- [ ] Contributing
3333+ - [ ] Code organization
3434+ - [ ] Adding new commands
3535+ - [ ] UI components
3636+ - [ ] Testing requirements
3737+- [ ] Architecture Deep Dive
3838+ - [ ] Repository pattern
3939+ - [ ] Handler architecture
4040+ - [ ] Service layer
4141+ - [ ] Data models
4242+ - [ ] UI component system
4343+4444+## Examples and Tutorials
4545+4646+- [ ] Getting Started Tutorial
4747+ - [ ] First 15 minutes
4848+ - [ ] Essential workflows
4949+- [ ] Task Management Tutorials
5050+ - [ ] GTD workflow
5151+ - [ ] Time blocking
5252+ - [ ] Project planning
5353+- [ ] Note-Taking Tutorials
5454+ - [ ] Zettelkasten method
5555+ - [ ] Research notes
5656+ - [ ] Meeting notes
5757+5858+## Appendices
5959+6060+- [ ] Glossary
6161+- [ ] Keyboard Shortcuts Reference
6262+- [ ] Configuration Options Reference
6363+- [ ] API Reference (leaflet schema)
6464+- [ ] Color Palette Reference
6565+- [ ] Migration Guides
6666+ - [ ] From TaskWarrior
6767+ - [ ] From todo.txt
6868+ - [ ] From other note-taking apps
+101-8
website/docs/Configuration.md
···11+---
22+id: configuration
33+title: Configuration
44+sidebar_label: Configuration
55+sidebar_position: 6
66+description: Reference for configuration locations, defaults, and options.
77+---
88+19# Configuration
210311Noteleaf stores its configuration in a TOML file. The configuration file location depends on your operating system and can be overridden with environment variables.
···3139```sh
3240export NOTELEAF_CONFIG=/path/to/custom/config.toml
3341```
4242+4343+### File Structure
4444+4545+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:
4646+4747+```toml
4848+date_format = "2006-01-02"
4949+color_scheme = "default"
5050+```
5151+5252+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.
34533554## Configuration Options
3655···318337**Type:** String (ISO8601)
319338**Default:** None
320339340340+## Editor Integration
341341+342342+The `editor` key wires Noteleaf into your preferred text editor. Resolution order:
343343+344344+1. `editor` inside `.noteleaf.conf.toml`
345345+2. `$EDITOR` environment variable
346346+3. System default (usually `vi` on Unix)
347347+348348+Where it is used:
349349+350350+- `noteleaf note edit <id>` always opens the configured editor.
351351+- `noteleaf note create -e` or `--editor` lets you capture inline text and immediately refine it in the editor.
352352+- Interactive creation (`noteleaf note create -i`) respects the same setting when you choose to open the note.
353353+354354+Example configuration:
355355+356356+```toml
357357+editor = "nvim"
358358+```
359359+360360+If you frequently switch editors, leave the config empty and export `$EDITOR` before launching Noteleaf:
361361+362362+```sh
363363+EDITOR="zed" noteleaf note edit 5
364364+```
365365+321366## Managing Configuration
322367323368### View Current Configuration
···389434390435## Environment Variables
391436392392-Noteleaf respects the following environment variables:
437437+Environment overrides are resolved before configuration values. Set them when you need temporary behavior (CI jobs, alternate workspaces, etc.).
393438394394-- `NOTELEAF_CONFIG` - Custom path to configuration file
395395-- `NOTELEAF_DATA_DIR` - Custom path to data directory
396396-- `EDITOR` - Default text editor (fallback if `editor` config not set)
439439+| Variable | Purpose | Notes |
440440+|----------|---------|-------|
441441+| `NOTELEAF_CONFIG` | Absolute path to the TOML file | Overrides platform defaults. Parent directories are created automatically. |
442442+| `NOTELEAF_DATA_DIR` | Root directory for the SQLite DB, notes, articles, and attachments | Useful for portable installs (USB drive, synced folder). |
443443+| `EDITOR` | Fallback editor when the `editor` config key is empty | Checked by all note-related commands. |
397444398398-Example:
445445+Usage example:
399446400447```sh
401401-export NOTELEAF_CONFIG=~/.config/noteleaf/config.toml
402402-export NOTELEAF_DATA_DIR=~/Documents/noteleaf-data
403403-export EDITOR=nvim
448448+export NOTELEAF_CONFIG=~/.config/noteleaf/work.conf.toml
449449+export NOTELEAF_DATA_DIR=~/Sync/workspace-data
450450+export EDITOR=helix
404451```
452452+453453+Because `NOTELEAF_DATA_DIR` cascades to the article and note directories, a single export is all you need to relocate the entire knowledge base.
454454+455455+## Customization
456456+457457+### Themes and Colors
458458+459459+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`.
460460+461461+```toml
462462+color_scheme = "default" # leave blank to adopt upcoming auto-mode
463463+```
464464+465465+### Keyboard Shortcuts
466466+467467+All interactive views share the same key map:
468468+469469+| Keys | Action |
470470+|------|--------|
471471+| `โ / k`, `โ / j` | Move selection |
472472+| `enter` | Open the selected row |
473473+| `v` | View details in a side panel (where supported) |
474474+| `/` | Search/filter (live) |
475475+| `r` | Reload data |
476476+| `?` | Show full help, including custom actions for the current view |
477477+| `q`, `ctrl+c` | Quit the view |
478478+| `esc`, `backspace` | Exit search/help/detail panels |
479479+| `1-9` | Jump directly to the corresponding row index |
480480+481481+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.
482482+483483+### Output Formats
484484+485485+- `export_format` sets the default for future export commands (currently `json`).
486486+- Task commands support JSON today: `noteleaf todo view 12 --json` or `noteleaf todo list --static --json`.
487487+- The `--format` flag on `noteleaf todo view` switches between `detailed` and `brief` layouts, which is handy when scripting.
488488+489489+Examples:
490490+491491+```sh
492492+noteleaf todo view 12 --format brief --json | jq '.status'
493493+noteleaf todo list --static --json > tasks.json
494494+noteleaf config set export_format "csv" # prepare for upcoming exporters
495495+```
496496+497497+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
···11+---
22+id: quickstart
33+title: Quickstart Guide
44+sidebar_label: Quickstart
55+sidebar_position: 1
66+description: Install Noteleaf and learn the essentials in minutes.
77+---
88+19# Quickstart Guide
210311This 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
···11+{
22+ "label": "Articles",
33+ "position": 6,
44+ "link": {
55+ "type": "generated-index",
66+ "title": "Article Archive",
77+ "description": "Save, read, and organize web articles locally."
88+ }
99+}
+75
website/docs/articles/management.md
···11+---
22+title: Article Management
33+sidebar_label: Management
44+description: Save URLs, inspect metadata, and read articles without leaving the CLI.
55+sidebar_position: 2
66+---
77+88+# Article Management
99+1010+## Save Articles from URLs
1111+1212+```sh
1313+noteleaf article add https://example.com/long-form-piece
1414+```
1515+1616+What happens:
1717+1818+1. The CLI checks the database to ensure the URL was not imported already.
1919+2. It fetches the page with a reader-friendly User-Agent (`curl/8.4.0`) and English `Accept-Language` headers to avoid blocked responses.
2020+3. Parsed content is written to Markdown and HTML files under `articles_dir`.
2121+4. A database record is inserted with all metadata and file paths.
2222+2323+If parsing fails (unsupported domain, network issue, etc.) nothing is written to disk, so partial entries never appear in your archive.
2424+2525+## Parsing and Extraction
2626+2727+The parser uses a two-layer strategy:
2828+2929+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.
3030+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.
3131+3232+During saving, the Markdown file gets a generated header:
3333+3434+```markdown
3535+# Article Title
3636+3737+**Author:** Jane Smith
3838+3939+**Date:** 2024-01-02
4040+4141+**Source:** https://example.com/long-form-piece
4242+4343+**Saved:** 2024-02-05 10:45:12
4444+```
4545+4646+Everything after the `---` separator is the cleaned article content.
4747+4848+## Reading in the Terminal
4949+5050+There are two ways to inspect what you saved:
5151+5252+- `noteleaf article view <id>` shows metadata, verifies whether the files still exist, and prints the first ~20 lines as a preview.
5353+- `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.
5454+5555+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.
5656+5757+## Article Metadata Reference
5858+5959+Use `noteleaf article list` to see titles and authors:
6060+6161+```sh
6262+noteleaf article list # newest first
6363+noteleaf article list "sqlite" # full-text filter on titles
6464+noteleaf article list --author "Kim" # author filter
6565+noteleaf article list -l 5 # top 5 results
6666+```
6767+6868+Each entry includes the created timestamp. The `view` command provides the raw paths so you can script around them, for example:
6969+7070+```sh
7171+md=$(noteleaf article view 12 | rg 'Markdown:' | awk '{print $3}')
7272+$EDITOR "$md"
7373+```
7474+7575+All metadata lives in the SQLite `articles` table, making it easy to run your own reports with `sqlite3` if needed.
+71
website/docs/articles/organization.md
···11+---
22+title: Article Organization
33+sidebar_label: Organization
44+description: Filter your archive, add lightweight tags, and keep backups tidy.
55+sidebar_position: 3
66+---
77+88+# Article Organization
99+1010+## Filter by Author or Title
1111+1212+`noteleaf article list` accepts both a free-form query (matches the title) and dedicated flags:
1313+1414+```sh
1515+# Anything with "SQLite" in the title
1616+noteleaf article list SQLite
1717+1818+# Limit to a single author
1919+noteleaf article list --author "Ada Palmer"
2020+2121+# Cap the output for quick reviews
2222+noteleaf article list --author "Ada Palmer" --limit 3
2323+```
2424+2525+Because the database stores created timestamps, results come back with the newest article first, making it easy to run weekly reviews.
2626+2727+## Tagging Articles
2828+2929+There is no first-class tagging UI yet, but Markdown files are yours to edit. Common patterns:
3030+3131+```markdown
3232+---
3333+tags: [distributed-systems, reference]
3434+project: moonshot
3535+---
3636+```
3737+3838+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.
3939+4040+## Read vs Unread
4141+4242+Opening an article in the terminal does not flip a status flag. Use one of these lightweight conventions instead:
4343+4444+- Prefix the Markdown filename with `read-` once you are done.
4545+- Keep a running checklist note (e.g., โArticles Inboxโ) that references IDs and mark them off as you read them.
4646+- Create a task linked to the article ID (`todo add "Summarize article #14"`), then close the task when you finish.
4747+4848+All three approaches work today and will map cleanly to future built-in read/unread tracking.
4949+5050+## Archiving and Backups
5151+5252+The archive lives under `articles_dir`. By default that is `<data_dir>/articles`, where `<data_dir>` depends on your OS:
5353+5454+| Platform | Default |
5555+|----------|---------|
5656+| Linux | `~/.local/share/noteleaf/articles` |
5757+| macOS | `~/Library/Application Support/noteleaf/articles` |
5858+| Windows | `%LOCALAPPDATA%\noteleaf\articles` |
5959+6060+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).
6161+6262+Because every import produces Markdown + HTML, the directory is perfect for version control:
6363+6464+```sh
6565+cd ~/.local/share/noteleaf/articles
6666+git init
6767+git add .
6868+git commit -m "Initial snapshot of article archive"
6969+```
7070+7171+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.
+54
website/docs/articles/overview.md
···11+---
22+title: Article Overview
33+sidebar_label: Overview
44+description: How the article parser saves content for offline reading.
55+sidebar_position: 1
66+---
77+88+# Article Overview
99+1010+The `noteleaf article` command turns any supported URL into two files on disk:
1111+1212+- A clean Markdown document (great for terminal reading).
1313+- A rendered HTML copy (handy for rich export or sharing).
1414+1515+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.
1616+1717+## How Parsing Works
1818+1919+1. **Domain rules first**: Each supported site has a small XPath rule file (`internal/articles/rules/*.txt`).
2020+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.
2121+3. **Metadata extraction**: The parser also looks for OpenGraph/JSON-LD tags to capture author names and publish dates.
2222+2323+You can see the currently loaded rule set by running:
2424+2525+```sh
2626+noteleaf article --help
2727+```
2828+2929+The help output prints the supported domains and the storage directory that is currently in use.
3030+3131+## Saved Metadata
3232+3333+Every article record contains:
3434+3535+- URL and canonical title
3636+- Author (if present in metadata)
3737+- Publication date (stored as plain text, e.g., `2024-01-02`)
3838+- Markdown file path
3939+- HTML file path
4040+- Created/modified timestamps
4141+4242+These fields make it easy to build reading logs, cite sources in notes, or reference articles from tasks.
4343+4444+## Commands at a Glance
4545+4646+| Command | Purpose |
4747+|----------------------------------|---------|
4848+| `noteleaf article add <url>` | Parse, save, and index a URL |
4949+| `noteleaf article list [query]` | Show saved items; filter with `--author` or `--limit` |
5050+| `noteleaf article view <id>` | Inspect metadata + a short preview |
5151+| `noteleaf article read <id>` | Render the Markdown nicely in your terminal |
5252+| `noteleaf article remove <id>` | Delete the DB entry and the files |
5353+5454+The CLI automatically prevents duplicate imports by checking the URL before parsing.
···11+---
22+title: Architecture Overview
33+sidebar_label: Architecture
44+description: Application structure, storage, and UI layers.
55+sidebar_position: 3
66+---
77+88+# Architecture Overview
99+1010+## Architecture Overview
1111+1212+### Application Structure
1313+1414+Noteleaf follows a clean architecture pattern with clear separation of concerns:
1515+1616+```
1717+cmd/ - CLI commands and user interface
1818+internal/
1919+ handlers/ - Business logic and orchestration
2020+ repo/ - Database access layer
2121+ ui/ - Terminal UI components (Bubble Tea)
2222+ models/ - Domain models
2323+ public/ - Leaflet.pub integration
2424+```
2525+2626+Each layer has defined responsibilities with minimal coupling between them.
2727+2828+### Storage and Database
2929+3030+**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).
3131+3232+**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.
3333+3434+**Database Schema**: Tables for tasks, notes, articles, books, movies, TV shows, publications, and linking tables for tags and relationships. Migrations handle schema evolution.
3535+3636+### TUI Framework (Bubble Tea)
3737+3838+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:
3939+4040+- **Model**: Application state (current view, selected item, filters)
4141+- **Update**: State transitions based on user input
4242+- **View**: Render the current state to the terminal
4343+4444+This architecture makes the UI predictable, testable, and composable. Each screen is an independent component that can be developed and tested in isolation.
+119
website/docs/concepts/cli-reference.md
···11+---
22+title: CLI Reference
33+sidebar_label: CLI Reference
44+description: Overview of Noteleafโs command hierarchy, flags, and developer utilities.
55+sidebar_position: 7
66+---
77+88+# CLI Reference
99+1010+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.
1111+1212+## Command Structure
1313+1414+### Global flags
1515+1616+| Flag | Description |
1717+| ------------------------- | ----------------------------------------------------------------- |
1818+| `--help`, `-h` | Show help for any command or subcommand |
1919+| `--version` | Print the Noteleaf build string (includes git SHA when available) |
2020+| `--color <auto\|on\|off>` | Optional Fang flag to control ANSI colors |
2121+2222+Environment variables such as `NOTELEAF_CONFIG`, `NOTELEAF_DATA_DIR`, and `EDITOR` affect how commands behave but are not flags.
2323+2424+### Command hierarchy
2525+2626+- Root command: `noteleaf`
2727+- Task commands live under the `todo` alias (e.g., `noteleaf todo add`).
2828+- Media commands are grouped and require a subtype: `noteleaf media book`, `noteleaf media movie`, `noteleaf media tv`.
2929+- Publishing flows live under `noteleaf pub`.
3030+- Management helpers (`config`, `setup`, `status`, `reset`) sit at the top level.
3131+3232+### Help system
3333+3434+Every command inherits Fangโs colorized help plus Noteleaf-specific additions:
3535+3636+- `noteleaf article --help` prints the supported parser domains and storage directory by calling into the handler.
3737+- Interactive commands show the keyboard shortcuts inside their help output.
3838+- You can always drill down: `noteleaf todo add --help`, `noteleaf media book list --help`, etc.
3939+4040+## Commands by Category
4141+4242+### `todo` / `task`
4343+4444+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.
4545+4646+### `note`
4747+4848+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.
4949+5050+### `media`
5151+5252+Umbrella group for personal queues:
5353+5454+- `noteleaf media book` โ Search Open Library, add books, update status (`queued`/`reading`/`finished`), edit progress percentages, and remove titles.
5555+- `noteleaf media movie` โ Search Rotten Tomatoes, queue movies, mark them watched, or remove them.
5656+- `noteleaf media tv` โ Same as movies but with watching/watched states and optional season/episode tracking.
5757+5858+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).
5959+6060+### `article`
6161+6262+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.
6363+6464+### `pub`
6565+6666+Leaflet.pub commands for AT Protocol publishing:
6767+6868+- `pull` / `push` to sync notes with the remote publication.
6969+- `status`, `list`, and `diff` to inspect what is linked.
7070+- Support for working drafts, batch pushes, and file-based imports (`--file`) when publishing is combined with local markdown.
7171+7272+### `config`
7373+7474+Inspect and mutate `~/.noteleaf.conf.toml`:
7575+7676+- `noteleaf config show` (or `get <key>`) prints values.
7777+- `noteleaf config set <key> <value>` writes back to disk.
7878+- `noteleaf config path` reveals the file location.
7979+- `noteleaf config reset` rewinds to defaults.
8080+8181+### `setup`
8282+8383+`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).
8484+8585+### `status`
8686+8787+`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.
8888+8989+## Development Tools
9090+9191+`noteleaf tools ...` is available in development builds (`task build:dev`, `go run ./cmd`). It bundles maintenance utilities:
9292+9393+### Documentation generation
9494+9595+```
9696+noteleaf tools docgen --format docusaurus --out website/docs/manual
9797+noteleaf tools docgen --format man --out docs/manual
9898+```
9999+100100+Generates reference docs straight from the command definitions, keeping terminal help and published docs in sync.
101101+102102+### Lexicon fetching
103103+104104+```
105105+noteleaf tools fetch lexicons
106106+noteleaf tools fetch lexicons --sha <commit>
107107+```
108108+109109+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.
110110+111111+### Database utilities
112112+113113+```
114114+noteleaf tools fetch gh-repo --repo owner/repo --path schemas --output tmp/schemas
115115+```
116116+117117+Provides generic fetchers plus helpers used by CI and local testing to refresh schema files, warm caches, or introspect the SQLite database.
118118+119119+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
···11+---
22+title: Unified Data Model
33+sidebar_label: Data Model
44+description: How tasks, notes, and media connect inside Noteleaf.
55+sidebar_position: 2
66+---
77+88+# Unified Data Model
99+1010+## Philosophy
1111+1212+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:
1313+1414+- Link notes to tasks to document your work
1515+- Tag books and articles with the same taxonomy as your tasks
1616+- Track reading lists alongside project work
1717+- Connect media items to research notes
1818+1919+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
···11+---
22+title: Design System
33+sidebar_label: Design System
44+description: Color palette guidance that keeps the terminal UI cohesive.
55+sidebar_position: 4
66+---
77+88+# Design System
99+1010+## Color Palette and Design System
1111+1212+Noteleaf uses a carefully chosen color palette defined in `internal/ui/palette.go`:
1313+1414+**Brand Colors**:
1515+1616+- **Malibu** (`#00A4FF`): Primary blue for accents and highlights
1717+- **Julep** (`#00FFB2`): Success green for completed items
1818+- **Sriracha** (`#EB4268`): Warning red for urgent/error states
1919+- **Tang** (`#FF985A`): Orange for warnings and attention
2020+- **Lichen** (`#5CDFEA`): Teal for informational elements
2121+2222+**Neutral Palette** (Dark to Light):
2323+2424+- **Pepper** (`#201F26`): Dark background
2525+- **BBQ** (`#2d2c35`): Secondary background
2626+- **Charcoal** (`#3A3943`): Tertiary background
2727+- **Iron** (`#4D4C57`): Borders and subtle elements
2828+- **Oyster** (`#605F6B`): Muted text
2929+- **Smoke** (`#BFBCC8`): Secondary text
3030+- **Salt** (`#F1EFEF`): Primary text in dark mode
3131+- **Butter** (`#FFFAF1`): Light background
3232+3333+This palette ensures consistency across all UI components and provides excellent contrast for readability in terminal environments.
+111
website/docs/concepts/getting-started.md
···11+---
22+title: Getting Started
33+sidebar_label: Getting Started
44+description: Installation steps, configuration overview, and ways to find help.
55+sidebar_position: 5
66+---
77+88+# Getting Started
99+1010+## Installation and Setup
1111+1212+### System Requirements
1313+1414+- Go 1.24 or higher
1515+- SQLite 3.35 or higher (usually bundled)
1616+- Terminal with 256-color support
1717+- Unix-like OS (Linux, macOS, WSL)
1818+1919+### Building from Source
2020+2121+Clone the repository and build:
2222+2323+```sh
2424+git clone https://github.com/stormlightlabs/noteleaf
2525+cd noteleaf
2626+go build -o ./tmp/noteleaf ./cmd
2727+```
2828+2929+Install to your GOPATH:
3030+3131+```sh
3232+go install
3333+```
3434+3535+### Database Initialization
3636+3737+Run setup to create the database and configuration file:
3838+3939+```sh
4040+noteleaf setup
4141+```
4242+4343+This creates:
4444+4545+- Database at platform-specific application data directory
4646+- Configuration file at platform-specific config directory
4747+- Default settings for editor, priorities, and display options
4848+4949+### Seeding Sample Data
5050+5151+For exploration and testing, populate the database with example data:
5252+5353+```sh
5454+noteleaf setup seed
5555+```
5656+5757+This creates sample tasks, notes, books, and other items to help you understand the system's capabilities.
5858+5959+## Configuration Overview
6060+6161+Configuration lives in `config.toml` at the platform-specific config directory.
6262+6363+**Editor Settings**:
6464+6565+```toml
6666+[editor]
6767+command = "nvim"
6868+args = []
6969+```
7070+7171+**Task Defaults**:
7272+7373+```toml
7474+[task]
7575+default_priority = "medium"
7676+default_status = "pending"
7777+```
7878+7979+**Display Options**:
8080+8181+```toml
8282+[display]
8383+date_format = "2006-01-02"
8484+time_format = "15:04"
8585+```
8686+8787+View current configuration:
8888+8989+```sh
9090+noteleaf config show
9191+```
9292+9393+Update settings:
9494+9595+```sh
9696+noteleaf config set editor vim
9797+```
9898+9999+See the [Configuration](../Configuration.md) guide for complete options.
100100+101101+## Getting Help
102102+103103+Every command includes help text:
104104+105105+```sh
106106+noteleaf --help
107107+noteleaf task --help
108108+noteleaf task add --help
109109+```
110110+111111+For detailed command reference, run `noteleaf --help` and drill into the subcommand-specific help pages.
+26
website/docs/concepts/overview.md
···11+---
22+title: Overview
33+sidebar_label: Overview
44+description: Noteleaf philosophy and reasons for a terminal-first approach.
55+sidebar_position: 1
66+---
77+88+# Overview
99+1010+## What is Noteleaf?
1111+1212+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.
1313+1414+## Why the Terminal?
1515+1616+Terminal applications offer several advantages for focused productivity work:
1717+1818+**Keyboard-First Interface**: Navigate and manage information without context-switching to a mouse. Every action is a keystroke away, making workflows faster once learned.
1919+2020+**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.
2121+2222+**Distraction-Free**: Terminal UIs remove visual clutter and web-based distractions, keeping you focused on the task at hand.
2323+2424+**Performance**: Native applications built with Go start instantly and consume minimal resources compared to Electron-based alternatives.
2525+2626+**Data Ownership**: Your data lives in a local SQLite database and markdown files. No cloud dependencies, no vendor lock-in, no privacy concerns.
+92
website/docs/concepts/tui.md
···11+---
22+title: Terminal UI
33+sidebar_label: Terminal UI
44+description: Navigate Noteleafโs Bubble Tea interfaces and their script-friendly counterparts.
55+sidebar_position: 6
66+---
77+88+# Terminal UI
99+1010+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.
1111+1212+## Interactive Mode
1313+1414+### Navigation
1515+1616+- Launch the TUI with the default command (`noteleaf todo list`, `noteleaf note list`, `noteleaf media book add -i`, etc.).
1717+- 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.
1818+- Search is always availableโpress `/` and start typing to filter titles, tags, projects, or notes in real time.
1919+2020+### Keyboard shortcuts
2121+2222+All interactive components reuse the same key map defined in `internal/ui/data_list.go` and `internal/ui/data_table.go`:
2323+2424+| Keys | Action |
2525+|------|--------|
2626+| `j` / `โ` | Move down |
2727+| `k` / `โ` | Move up |
2828+| `enter` | Select the highlighted row |
2929+| `v` | Open the detail preview (when supported) |
3030+| `/` | Start search |
3131+| `r` | Refresh data from the database |
3232+| `1-9` | Jump directly to a row index |
3333+| `q`, `ctrl+c` | Quit the view |
3434+3535+The shortcuts appear in the on-screen help so you never have to memorize them all.
3636+3737+### Selection and actions
3838+3939+- Press `enter` to activate the primary action (open a note, view a task, confirm a media selection, etc.).
4040+- Some screens expose extra actions on letter keys (e.g., `a` to archive, `e` to edit). They are listed alongside the contextual help (`?`).
4141+- Interactive prompts such as `noteleaf media movie add` use the same selection model, so keyboard muscle memory carries over.
4242+4343+### Help screens
4444+4545+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.
4646+4747+## Static Mode
4848+4949+### Command-line output
5050+5151+Add `--static` (or remove `-i`) to force plain text output. Examples:
5252+5353+```sh
5454+noteleaf todo list --static
5555+noteleaf note list --static --tag meeting
5656+noteleaf media book list --all --static
5757+```
5858+5959+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`.
6060+6161+### Scripting with Noteleaf
6262+6363+Static output is predictable, making it straightforward to combine with familiar utilities:
6464+6565+```sh
6666+noteleaf todo list --static --project docs | rg "pending"
6767+noteleaf note list --static | fzf
6868+```
6969+7070+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.).
7171+7272+### Output formatting
7373+7474+The task viewer supports the `--format` flag for quick summaries:
7575+7676+```sh
7777+noteleaf todo view 12 --format brief
7878+noteleaf todo view 12 --format detailed # default
7979+```
8080+8181+Brief mode hides timestamps and auxiliary metadata, which keeps CI logs or chat snippets short. Future commands will inherit the same pattern.
8282+8383+### JSON output
8484+8585+Use `--json` wherever it exists (currently on task views/lists) for structured output:
8686+8787+```sh
8888+noteleaf todo view 12 --json | jq '.status'
8989+noteleaf todo list --static --json | jq '.[] | select(.status=="pending")'
9090+```
9191+9292+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
···11-# System Architecture
22-33-Noteleaf is a CLI/TUI application for task and content management built on Go with SQLite persistence and terminal-based interfaces.
44-55-## Core Architecture
66-77-### Application Structure
88-99-The application follows a layered architecture with clear separation between presentation, business logic, and data access layers.
1010-1111-**Entry Point** - `cmd/main.go` initializes the application with dependency injection, creates handlers, and configures the Cobra command tree using the CommandGroup pattern.
1212-1313-**CLI Framework** - Built on `spf13/cobra` with `charmbracelet/fang` providing enhanced CLI features including color schemes, versioning, and improved help formatting.
1414-1515-**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`.
1616-1717-### Data Layer
1818-1919-**Database** - SQLite with schema migrations in `internal/store/sql/migrations/`. The `internal/store` package manages database connections and configuration.
2020-2121-**Repository Pattern** - Data access abstracts through repository interfaces in `internal/repo/` with validation logic ensuring data integrity at the persistence boundary.
2222-2323-**Models** - Entity definitions in `internal/models/` implement standardized Model interfaces with common fields (ID, Created, Modified).
2424-2525-### Business Logic
2626-2727-**Handlers** - Business logic resides in `internal/handlers/` with one handler per domain (TaskHandler, NoteHandler, ArticleHandler, etc.).
2828-Handlers receive repository dependencies through constructor injection.
2929-3030-**Services** - Domain-specific operations in `internal/services/` handle complex business workflows and external integrations.
3131-3232-**Validation** - Schema-based validation at repository level with custom ValidationError types providing detailed field-level error messages.
3333-3434-## Domain Features
3535-3636-### Content Management
3737-3838-**Articles** - Web scraping using `gocolly/colly` with domain-specific extraction rules stored in `internal/articles/rules/`.
3939-Articles are parsed to markdown and stored with dual file references (markdown + HTML).
4040-4141-**Tasks** - Todo/task management inspired by TaskWarrior with filtering, status tracking, and interactive TUI views.
4242-4343-**Notes** - Simple note management with markdown support and glamour-based terminal rendering.
4444-4545-**Media Queues** - Separate queues for books, movies, and TV shows with status tracking and metadata management.
4646-4747-### User Interface
4848-4949-**Command Groups** - Commands organized into core functionality (task, note, article, media) and management operations (setup, config, status) using the CommandGroup interface pattern.
5050-5151-**Interactive Views** - Bubbletea-based TUI components for list navigation, item selection, and data entry with consistent styling through the lipgloss color system.
5252-5353-**Terminal Output** - Markdown rendering through `charmbracelet/glamour` for rich text display in terminal environments.
5454-5555-## Dependencies
5656-5757-**CLI/TUI** - Cobra command framework, Bubbletea state management, Lipgloss styling, Fang CLI enhancements.
5858-5959-**Data** - SQLite driver (`mattn/go-sqlite3`), TOML configuration parsing.
6060-6161-**Content Processing** - Colly web scraping, HTML/XML query libraries, Glamour markdown rendering, text processing utilities.
6262-6363-**Utilities** - UUID generation, time handling, logging through `charmbracelet/log`.
6464-6565-## Design Decisions and Tradeoffs
6666-6767-### Technology Choices
6868-6969-**Go over Rust** - Go was selected for its simplicity, excellent CLI ecosystem (Cobra, Charm libraries), and faster development velocity.
7070-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.
7171-7272-**SQLite over PostgreSQL** - SQLite provides zero-configuration deployment and sufficient performance for single-user CLI applications.
7373-The embedded database eliminates setup complexity while supporting full SQL features needed for filtering and querying.
7474-PostgreSQL would add deployment overhead without meaningful benefits for this use case.
7575-7676-**Repository Pattern over Active Record** - Repository interfaces enable clean separation between business logic and data access, facilitating testing through dependency injection.
7777-This pattern scales better than Active Record for complex domain logic while maintaining clear boundaries between layers.
7878-7979-### Architectural Tradeoffs
8080-8181-**CommandGroup Interface** - Centralizes command registration while enabling modular command organization.
8282-The pattern requires additional abstraction but provides consistent dependency injection and testing capabilities across all command groups.
8383-8484-**Handler-based Business Logic** - Business logic in handlers rather than rich domain models keeps the codebase simple and avoids over-engineering.
8585-While this approach may not scale to complex business rules, it provides clear separation of concerns for the current feature set.
8686-8787-**Dual Storage for Articles** - Articles store both markdown and HTML versions to balance processing speed with format flexibility.
8888-This doubles storage requirements but eliminates runtime conversion overhead and preserves original formatting.
8989-9090-### Component Interactions
9191-9292-**Handler โ Repository โ Database** - Request flow follows a linear path from CLI commands through business logic to data persistence.
9393-This pattern ensures consistent validation and error handling while maintaining clear separation of concerns.
9494-9595-**TUI State Management** - Bubbletea's unidirectional data flow provides predictable state updates for interactive components.
9696-The model-view-update pattern ensures consistent UI behavior across different terminal environments.
9797-9898-**Configuration and Migration** - Application startup validates configuration and runs database migrations before initializing handlers.
9999-This fail-fast approach prevents runtime errors and ensures consistent database schema across deployments.
-292
website/docs/development/TESTING.md
···11-# Testing Documentation
22-33-This document outlines the testing patterns and practices used in the `noteleaf` application.
44-55-## Overview
66-77-The codebase follows Go's standard testing practices with specialized testing utilities for complex scenarios.
88-Tests use the standard library along with carefully selected dependencies like faker for data generation and BubbleTea for TUI testing.
99-This approach keeps dependencies minimal while providing robust testing infrastructure for interactive components and complex integrations.
1010-1111-### Organization
1212-1313-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.
1414-The codebase includes four main test utility files that provide specialized testing infrastructure:
1515-1616-- `internal/services/test_utilities.go` - HTTP mocking and media service testing
1717-- `internal/repo/test_utilities.go` - Database testing and data generation
1818-- `internal/ui/test_utilities.go` - TUI testing framework and interactive component testing
1919-- `internal/handlers/test_utilities.go` - Handler testing with database isolation and input simulation
2020-2121-## Patterns
2222-2323-### Handler Creation
2424-2525-Tests create real handler instances using temporary databases to ensure test isolation.
2626-Factory functions handle both database setup and handler initialization, returning both the handler and a cleanup function.
2727-2828-### Database Isolation
2929-3030-Tests use temporary directories and environment variable manipulation to create isolated database instances.
3131-Each test gets its own temporary SQLite database that is automatically cleaned up after the test completes.
3232-3333-The `setupCommandTest` function creates a temporary directory, sets `XDG_CONFIG_HOME` to point to it, and initializes the database schema.
3434-This ensures tests don't interfere with each other or with development data.
3535-3636-### Resource Management
3737-3838-Tests properly manage resources using cleanup functions returned by factory methods.
3939-The cleanup function handles both handler closure and temporary directory removal.
4040-This pattern ensures complete resource cleanup even if tests fail.
4141-4242-### Error Handling
4343-4444-Tests use `t.Fatal` for setup errors that prevent test execution and `t.Error` for test assertion failures.
4545-Fatal errors stop test execution while errors allow tests to continue checking other conditions.
4646-4747-### Context Cancellation
4848-4949-Error case testing frequently uses context cancellation to simulate database and network failures.
5050-The pattern creates a context, immediately cancels it, then calls the function under test to verify error handling.
5151-This provides a reliable way to test error paths without requiring complex mock setups or external failure injection.
5252-5353-### Command Structure
5454-5555-Command group tests verify cobra command structure including use strings, aliases, short descriptions, and subcommand presence.
5656-Tests check that commands are properly configured without executing their logic.
5757-5858-### Interface Compliance
5959-6060-Tests verify interface compliance using compile-time checks with blank identifier assignments.
6161-This ensures structs implement expected interfaces without runtime overhead.
6262-6363-## Test Infrastructure
6464-6565-### Test Utility Frameworks
6666-6767-The codebase provides comprehensive testing utilities organized by layer and functionality.
6868-Each test utility file contains specialized helpers, mocks, and test infrastructure for its respective domain.
6969-7070-#### Database Testing Utilities
7171-7272-`internal/repo/test_utilities.go` provides comprehensive database testing infrastructure:
7373-7474-- **In-Memory Database Creation**: `CreateTestDB` creates isolated SQLite databases with full schema
7575-- **Sample Data Factories**: Functions like `CreateSampleTask`, `CreateSampleBook` generate realistic test data
7676-- **Faker Integration**: Uses jaswdr/faker for generating realistic fake data with `CreateFakeArticle`
7777-- **Test Setup Helpers**: `SetupTestData` creates a full set of sample data across all models
7878-- **Custom Assertions**: Generic assertion helpers like `AssertEqual`, `AssertContains`, `AssertNoError`
7979-8080-#### HTTP Service Testing
8181-8282-`internal/services/test_utilities.go` provides HTTP mocking and media service testing:
8383-8484-- **Mock Configuration**: `MockConfig` structure for configuring service behavior
8585-- **Function Replacement**: `SetupMediaMocks` replaces service functions with controllable mocks
8686-- **Sample Data Access**: Helper functions that use embedded HTML samples for realistic testing
8787-- **Specialized Scenarios**: Pre-configured mock setups for success and failure scenarios
8888-- **Assertion Helpers**: Domain-specific assertions for movies, TV shows, and error conditions
8989-9090-#### TUI Testing Framework
9191-9292-`internal/ui/test_utilities.go` provides a comprehensive BubbleTea testing framework:
9393-9494-- **TUITestSuite**: Complete testing infrastructure for interactive TUI components
9595-- **Controlled I/O**: `ControlledOutput` and `ControlledInput` for deterministic testing
9696-- **Message Simulation**: Key press simulation, message queuing, and timing control
9797-- **State Verification**: Model state checking and view content assertions
9898-- **Timeout Handling**: Configurable timeouts for async operations
9999-- **Mock Repository**: Test doubles for repository interfaces
100100-101101-#### Handler Testing Infrastructure
102102-103103-`internal/handlers/test_utilities.go` provides end-to-end handler testing:
104104-105105-- **Environment Isolation**: `HandlerTestHelper` creates isolated test environments
106106-- **Input Simulation**: `InputSimulator` for testing interactive components that use `fmt.Scanf`
107107-- **HTTP Mocking**: Comprehensive HTTP server mocking for external API testing
108108-- **Database Helpers**: Database corruption and error scenario testing
109109-- **Editor Mocking**: `MockEditor` for testing file editing workflows
110110-- **Assertion Helpers**: Handler-specific assertions and verification functions
111111-112112-### Advanced Testing Patterns
113113-114114-#### Input Simulation for Interactive Components
115115-116116-Interactive handlers that use `fmt.Scanf` require special testing infrastructure with an `io.Reader` implementation.
117117-118118-The `InputSimulator` provides controlled input sequences that prevent tests from hanging while maintaining coverage of interactive code paths.
119119-120120-#### TUI Testing with BubbleTea Framework
121121-122122-The TUI testing framework addresses the fundamental challenge of testing interactive terminal applications in a deterministic, concurrent environment.
123123-BubbleTea's message-passing architecture creates unique testing requirements that standard Go testing patterns cannot adequately address.
124124-125125-The framework implements a controlled execution environment that replaces BubbleTea's typical program loop with a deterministic testing harness.
126126-Rather than running an actual terminal program, the "testing suite" directly manages model state transitions by simulating the Update/View cycle.
127127-This approach eliminates the non-deterministic behavior inherent in real terminal interactions while preserving the exact message flow patterns that production code experiences.
128128-129129-State verification relies on function composition patterns where test conditions are expressed as closures that capture specific model states.
130130-The `WaitFor` mechanism uses polling with configurable timeouts, addressing the async nature of BubbleTea model updates without creating race conditions.
131131-This pattern bridges imperative test assertions with BubbleTea's declarative update model.
132132-This is inspired by front-end/TS/JS testing patterns.
133133-134134-The framework's I/O abstraction layer replaces terminal input/output with controlled buffers that implement standard Go interfaces.
135135-This design maintains interface compatibility while providing complete control over timing and content.
136136-The controlled I/O system captures all output for later verification and injects precise input sequences, enabling complex interaction testing without external dependencies.
137137-138138-Concurrency management uses channels and context propagation to coordinate between the testing framework and the model under test.
139139-The suite manages goroutine lifecycle and ensures proper cleanup, preventing test interference and resource leaks.
140140-This architecture supports testing of models that perform background operations or handle async events.
141141-142142-#### HTTP Service Mocking
143143-144144-Service testing uses HTTP mocking with request capture. A `MockServer` is instantiated, and its URL is used in test scoped services.
145145-146146-#### Database Schema Testing
147147-148148-Database tests use comprehensive schema setup with (automatic) cleanup
149149-150150-#### Environment Manipulation
151151-152152-Environment testing utilities provide controlled environment manipulation. Environment variables are restored after instantiation.
153153-154154-## Test Organization Patterns
155155-156156-### Single Root Test
157157-158158-The preferred test organization pattern uses a single root test function with nested subtests using `t.Run`.
159159-This provides clear hierarchical organization and allows running specific test sections while maintaining shared setup and context.
160160-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.
161161-162162-### Integration vs Unit Testing
163163-164164-The codebase emphasizes integration testing over heavy mocking by using real handlers and services to verify actual behavior rather than mocked interactions.
165165-The goal is to catch integration issues while maintaining test reliability.
166166-167167-### Static Output
168168-169169-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.
170170-171171-### Standard Output Redirection
172172-173173-For testing functions that write to stdout, tests use a pipe redirection pattern with goroutines to capture output.
174174-The pattern saves the original stdout, redirects to a pipe, captures output in a separate goroutine, and restores stdout after the test.
175175-This ensures clean output capture without interfering with the testing framework.
176176-177177-## Utilities
178178-179179-### Test Data Generation
180180-181181-The codebase uses sophisticated data generation strategies:
182182-183183-- **Factory Functions**: Each package provides factory functions for creating valid test data
184184-- **Faker Integration**: Uses `jaswdr/faker` for generating realistic fake data with proper randomization
185185-- **Sample Data Creators**: Functions like `CreateSampleTask`, `CreateSampleBook` provide consistent test data
186186-- **Embedded Resources**: Services use embedded HTML samples from real API responses for realistic testing
187187-188188-### Assertion Helpers
189189-190190-Custom assertion functions provide clear error messages and reduce test code duplication:
191191-192192-- **Generic Assertions**: `AssertEqual`, `AssertNoError`, `AssertContains` for common checks
193193-- **Domain-Specific Assertions**: `AssertMovieInResults`, `AssertNoteExists` for specialized verification
194194-- **TUI Assertions**: `AssertViewContains`, `AssertModelState` for BubbleTea model testing
195195-- **HTTP Assertions**: `AssertRequestMade` for verifying HTTP interactions
196196-197197-### Mock Infrastructure
198198-199199-Each layer provides specialized mocking capabilities:
200200-201201-- **Service Mocking**: Function replacement with configurable behavior and embedded test data
202202-- **HTTP Mocking**: `HTTPMockServer` with request capture and response customization
203203-- **Input Mocking**: `InputSimulator` for deterministic interactive component testing
204204-- **Editor Mocking**: `MockEditor` for file editing workflow testing
205205-- **Repository Mocking**: `MockTaskRepository` for TUI component testing
206206-207207-### Environment and Resource Management
208208-209209-Testing utilities provide comprehensive resource management:
210210-211211-- **Environment Isolation**: `EnvironmentTestHelper` for controlled environment variable manipulation
212212-- **Database Isolation**: Temporary SQLite databases with automatic cleanup
213213-- **File System Isolation**: Temporary directories with automatic cleanup
214214-- **Process Isolation**: Handler helpers that create completely isolated test environments
215215-216216-## Testing CLI Commands
217217-218218-Command group tests focus on structure verification rather than execution testing.
219219-Tests check command configuration, subcommand presence, and interface compliance. This approach ensures command trees are properly constructed without requiring complex execution mocking.
220220-221221-### CommandGroup Interface Testing
222222-223223-The CommandGroup interface enables testable CLI architecture. Tests verify that command groups implement the interface correctly and return properly configured cobra commands.
224224-This pattern separates command structure from command execution.
225225-226226-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.
227227-228228-## Performance Considerations
229229-230230-Tests avoid expensive operations in setup functions. Handler creation uses real instances but tests focus on structure verification rather than full execution paths.
231231-This keeps test suites fast while maintaining coverage of critical functionality.
232232-233233-The single root test pattern allows for efficient resource management where setup costs can be amortized across multiple related test cases.
234234-235235-## Interactive Component Testing
236236-237237-The codebase provides comprehensive testing infrastructure for interactive components, including both terminal UI applications and command-line interfaces that require user input.
238238-239239-### Input Simulation Framework
240240-241241-Interactive handlers that use `fmt.Scanf` require specialized testing infrastructure:
242242-243243-- **InputSimulator**: Provides controlled input sequences that implement `io.Reader`
244244-- **Menu Selection Helpers**: `MenuSelection`, `MenuCancel`, `MenuSequence` for common interaction patterns
245245-- **Handler Integration**: Handlers can accept `io.Reader` for input, enabling deterministic testing
246246-- **Cleanup Management**: Automatic cleanup prevents resource leaks in test environments
247247-248248-### TUI Testing with BubbleTea
249249-250250-The TUI testing framework provides complete testing infrastructure for interactive terminal interfaces:
251251-252252-- **TUITestSuite**: Comprehensive testing framework for BubbleTea models
253253-- **Message Simulation**: Key press simulation, window resize events, and custom message handling
254254-- **State Verification**: Model state checking with custom condition functions
255255-- **View Assertions**: Content verification and output capture
256256-- **Timing Control**: Configurable timeouts and delay handling for async operations
257257-- **Mock Integration**: Repository mocking for isolated component testing
258258-259259-### Interactive Test Scenarios
260260-261261-Interactive handlers should test comprehensive scenarios:
262262-263263-- **Valid user selections** - User chooses valid menu options and inputs
264264-- **Cancellation flows** - User chooses to cancel operations (option 0 or escape keys)
265265-- **Invalid choices** - User selects out-of-range options or provides invalid input
266266-- **Navigation patterns** - Keyboard navigation, scrolling, and multi-step interactions
267267-- **Error handling** - Network errors, service failures, and data validation errors
268268-- **Empty states** - Search returns no results, empty lists, and missing data
269269-- **Edge cases** - Boundary conditions, malformed input, and resource constraints
270270-271271-### TUI Component Testing Patterns
272272-273273-BubbleTea components use specialized testing patterns:
274274-275275-- **Key Sequence Testing**: Simulate complex user interactions with timing
276276-- **State Transition Testing**: Verify model state changes through user actions
277277-- **View Content Testing**: Assert specific content appears in rendered output
278278-- **Async Operation Testing**: Handle loading states and network operations
279279-- **Responsive Design Testing**: Test different terminal sizes and window resize handling
280280-281281-This comprehensive testing approach ensures interactive components work reliably in automated environments while maintaining full coverage of user interaction paths.
282282-283283-## Errors
284284-285285-Error coverage follows a systematic approach to identify and test failure scenarios:
286286-287287-1. **Context Cancellation** - Primary method for testing database and network timeout scenarios
288288-2. **Invalid Input** - Malformed data, empty inputs, boundary conditions
289289-3. **Resource Exhaustion** - Database connection failures, memory limits
290290-4. **Constraint Violations** - Duplicate keys, foreign key failures
291291-5. **State Validation** - Testing functions with invalid system states
292292-6. **Interactive Input** - Invalid user choices, cancellation handling, input simulation errors
+167
website/docs/development/building.md
···11+---
22+title: Building Noteleaf
33+sidebar_label: Building
44+sidebar_position: 1
55+description: Build configurations and development workflows.
66+---
77+88+# Building Noteleaf
99+1010+Noteleaf uses [Task](https://taskfile.dev) for build automation, providing consistent workflows across development, testing, and releases.
1111+1212+## Prerequisites
1313+1414+- Go 1.21 or later
1515+- [Task](https://taskfile.dev) (install via `brew install go-task/tap/go-task` on macOS)
1616+- Git (for version information)
1717+1818+## Build Types
1919+2020+### Development Build
2121+2222+Quick build without version injection for local development:
2323+2424+```sh
2525+task build
2626+```
2727+2828+Output: `./tmp/noteleaf`
2929+3030+### Development Build with Version
3131+3232+Build with git commit hash and development tools enabled:
3333+3434+```sh
3535+task build:dev
3636+```
3737+3838+Version format: `git describe` output (e.g., `v0.1.0-15-g1234abc`)
3939+Output: `./tmp/noteleaf`
4040+4141+### Release Candidate Build
4242+4343+Build with `-rc` tag, excludes development tools:
4444+4545+```sh
4646+git tag v1.0.0-rc1
4747+task build:rc
4848+```
4949+5050+Requirements:
5151+5252+- Clean git tag with `-rc` suffix
5353+- Tag format: `v1.0.0-rc1`, `v2.1.0-rc2`, etc.
5454+5555+### Production Build
5656+5757+Build for release with strict validation:
5858+5959+```sh
6060+git tag v1.0.0
6161+task build:prod
6262+```
6363+6464+Requirements:
6565+6666+- Clean semver git tag (e.g., `v1.0.0`, `v2.1.3`)
6767+- No uncommitted changes
6868+- No prerelease suffix
6969+7070+## Build Tags
7171+7272+Production builds use the `prod` build tag to exclude development and seed commands:
7373+7474+```go
7575+//go:build !prod
7676+```
7777+7878+Commands excluded from production:
7979+8080+- `noteleaf dev` - Development utilities
8181+- `noteleaf seed` - Test data generation
8282+8383+## Version Information
8484+8585+Build process injects version metadata via ldflags:
8686+8787+```go
8888+// internal/version/version.go
8989+var (
9090+ Version = "dev" // Git tag or "dev"
9191+ Commit = "none" // Git commit hash
9292+ BuildDate = "unknown" // Build timestamp
9393+)
9494+```
9595+9696+View version information:
9797+9898+```sh
9999+task version:show
100100+noteleaf version
101101+```
102102+103103+## Build Artifacts
104104+105105+All binaries are built to `./tmp/` directory:
106106+107107+```
108108+tmp/
109109+โโโ noteleaf # Binary for current platform
110110+```
111111+112112+## Development Workflow
113113+114114+Full development cycle with linting and testing:
115115+116116+```sh
117117+task dev
118118+```
119119+120120+Runs:
121121+122122+1. Clean build artifacts
123123+2. Run linters (vet, fmt)
124124+3. Execute all tests
125125+4. Build binary
126126+127127+## Manual Build
128128+129129+Build directly with Go (bypasses Task automation):
130130+131131+```sh
132132+go build -o ./tmp/noteleaf ./cmd
133133+```
134134+135135+With version injection:
136136+137137+```sh
138138+go build -ldflags "-X github.com/stormlightlabs/noteleaf/internal/version.Version=v1.0.0" -o ./tmp/noteleaf ./cmd
139139+```
140140+141141+## Cross-Platform Builds
142142+143143+Build for specific platforms:
144144+145145+```sh
146146+# Linux
147147+GOOS=linux GOARCH=amd64 go build -o ./tmp/noteleaf-linux ./cmd
148148+149149+# Windows
150150+GOOS=windows GOARCH=amd64 go build -o ./tmp/noteleaf.exe ./cmd
151151+152152+# macOS (ARM)
153153+GOOS=darwin GOARCH=arm64 go build -o ./tmp/noteleaf-darwin-arm64 ./cmd
154154+```
155155+156156+## Clean Build
157157+158158+Remove all build artifacts:
159159+160160+```sh
161161+task clean
162162+```
163163+164164+Removes:
165165+166166+- `./tmp/` directory
167167+- `coverage.out` and `coverage.html`
+331
website/docs/development/taskfile.md
···11+---
22+title: Task Automation
33+sidebar_label: Taskfile
44+sidebar_position: 3
55+description: Using Taskfile for development workflows.
66+---
77+88+# Task Automation
99+1010+Noteleaf uses [Task](https://taskfile.dev) to automate common development workflows.
1111+1212+## Installation
1313+1414+### macOS
1515+1616+```sh
1717+brew install go-task/tap/go-task
1818+```
1919+2020+### Linux
2121+2222+```sh
2323+sh -c "$(curl -fsSL https://taskfile.dev/install.sh)"
2424+```
2525+2626+### Go Install
2727+2828+```sh
2929+go install github.com/go-task/task/v3/cmd/task@latest
3030+```
3131+3232+## Available Tasks
3333+3434+View all tasks:
3535+3636+```sh
3737+task
3838+# or
3939+task --list
4040+```
4141+4242+## Common Tasks
4343+4444+### Build Commands
4545+4646+**task build** - Quick development build
4747+4848+```sh
4949+task build
5050+```
5151+5252+Output: `./tmp/noteleaf`
5353+5454+**task build:dev** - Build with version information
5555+5656+```sh
5757+task build:dev
5858+```
5959+6060+Includes git commit hash and build date.
6161+6262+**task build:rc** - Release candidate build
6363+6464+```sh
6565+git tag v1.0.0-rc1
6666+task build:rc
6767+```
6868+6969+Requires git tag with `-rc` suffix.
7070+7171+**task build:prod** - Production build
7272+7373+```sh
7474+git tag v1.0.0
7575+task build:prod
7676+```
7777+7878+Requires clean semver tag and no uncommitted changes.
7979+8080+### Testing Commands
8181+8282+**task test** - Run all tests
8383+8484+```sh
8585+task test
8686+```
8787+8888+**task coverage** - Generate HTML coverage report
8989+9090+```sh
9191+task coverage
9292+open coverage.html # View report
9393+```
9494+9595+**task cov** - Terminal coverage summary
9696+9797+```sh
9898+task cov
9999+```
100100+101101+**task check** - Lint and coverage
102102+103103+```sh
104104+task check
105105+```
106106+107107+Runs linters and generates coverage report.
108108+109109+### Development Commands
110110+111111+**task dev** - Full development workflow
112112+113113+```sh
114114+task dev
115115+```
116116+117117+Runs:
118118+119119+1. `task clean`
120120+2. `task lint`
121121+3. `task test`
122122+4. `task build`
123123+124124+**task lint** - Run linters
125125+126126+```sh
127127+task lint
128128+```
129129+130130+Runs `go vet` and `go fmt`.
131131+132132+**task run** - Build and run
133133+134134+```sh
135135+task run
136136+```
137137+138138+Builds then executes the binary.
139139+140140+### Maintenance Commands
141141+142142+**task clean** - Remove build artifacts
143143+144144+```sh
145145+task clean
146146+```
147147+148148+Removes:
149149+150150+- `./tmp/` directory
151151+- Coverage files
152152+153153+**task deps** - Download and tidy dependencies
154154+155155+```sh
156156+task deps
157157+```
158158+159159+Runs `go mod download` and `go mod tidy`.
160160+161161+### Documentation Commands
162162+163163+**task docs:generate** - Generate all documentation
164164+165165+```sh
166166+task docs:generate
167167+```
168168+169169+Generates:
170170+171171+- Docusaurus docs (website/docs/manual)
172172+- Man pages (docs/manual)
173173+174174+**task docs:man** - Generate man pages
175175+176176+```sh
177177+task docs:man
178178+```
179179+180180+**task docs:serve** - Start documentation server
181181+182182+```sh
183183+task docs:serve
184184+```
185185+186186+Starts Docusaurus development server at <http://localhost:3000>.
187187+188188+### Version Commands
189189+190190+**task version:show** - Display version info
191191+192192+```sh
193193+task version:show
194194+```
195195+196196+Shows:
197197+198198+- Git tag
199199+- Git commit
200200+- Git describe output
201201+- Build date
202202+203203+**task version:validate** - Validate git tag
204204+205205+```sh
206206+task version:validate
207207+```
208208+209209+Checks tag format for releases.
210210+211211+### Utility Commands
212212+213213+**task status** - Show Go environment
214214+215215+```sh
216216+task status
217217+```
218218+219219+Displays:
220220+221221+- Go version
222222+- Module information
223223+- Dependencies
224224+225225+## Taskfile Variables
226226+227227+Variables injected during build:
228228+229229+```yaml
230230+BINARY_NAME: noteleaf
231231+BUILD_DIR: ./tmp
232232+VERSION_PKG: github.com/stormlightlabs/noteleaf/internal/version
233233+GIT_COMMIT: $(git rev-parse --short HEAD)
234234+GIT_TAG: $(git describe --tags --exact-match)
235235+BUILD_DATE: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
236236+```
237237+238238+## Task Dependencies
239239+240240+Some tasks automatically trigger others:
241241+242242+```sh
243243+task run
244244+# Automatically runs: task build
245245+```
246246+247247+```sh
248248+task dev
249249+# Runs in sequence:
250250+# 1. task clean
251251+# 2. task lint
252252+# 3. task test
253253+# 4. task build
254254+```
255255+256256+## Custom Workflows
257257+258258+### Pre-commit Workflow
259259+260260+```sh
261261+task lint && task test
262262+```
263263+264264+### Release Preparation
265265+266266+```sh
267267+task check && \
268268+git tag v1.0.0 && \
269269+task build:prod && \
270270+./tmp/noteleaf version
271271+```
272272+273273+### Documentation Preview
274274+275275+```sh
276276+task docs:generate
277277+task docs:serve
278278+```
279279+280280+### Full CI Simulation
281281+282282+```sh
283283+task clean && \
284284+task deps && \
285285+task lint && \
286286+task test && \
287287+task coverage && \
288288+task build:dev
289289+```
290290+291291+## Taskfile Structure
292292+293293+Location: `Taskfile.yml` (project root)
294294+295295+Key sections:
296296+297297+- **vars**: Build variables and git information
298298+- **tasks**: Command definitions with descriptions
299299+- **deps**: Task dependencies
300300+- **preconditions**: Validation before execution
301301+302302+## Configuration
303303+304304+Customize via `Taskfile.yml` or environment variables:
305305+306306+```yaml
307307+vars:
308308+ BINARY_NAME: noteleaf
309309+ BUILD_DIR: ./tmp
310310+```
311311+312312+Override at runtime:
313313+314314+```sh
315315+BINARY_NAME=custom-noteleaf task build
316316+```
317317+318318+## Why Task Over Make?
319319+320320+- Cross-platform (Windows, macOS, Linux)
321321+- YAML syntax (more readable than Makefile)
322322+- Built-in variable interpolation
323323+- Better dependency management
324324+- Precondition validation
325325+- Native Go integration
326326+327327+## Further Reading
328328+329329+- [Task Documentation](https://taskfile.dev)
330330+- [Taskfile Schema](https://taskfile.dev/api/)
331331+- Project Taskfile: `Taskfile.yml`
+268
website/docs/development/testing.md
···11+---
22+title: Testing
33+sidebar_label: Testing
44+sidebar_position: 2
55+description: Running tests and understanding test patterns.
66+---
77+88+# Testing
99+1010+Noteleaf maintains comprehensive test coverage using Go's built-in testing framework with consistent patterns across the codebase.
1111+1212+## Running Tests
1313+1414+### All Tests
1515+1616+```sh
1717+task test
1818+# or
1919+go test ./...
2020+```
2121+2222+### Coverage Report
2323+2424+Generate HTML coverage report:
2525+2626+```sh
2727+task coverage
2828+```
2929+3030+Output: `coverage.html` (opens in browser)
3131+3232+### Terminal Coverage
3333+3434+View coverage in terminal:
3535+3636+```sh
3737+task cov
3838+```
3939+4040+Shows function-level coverage percentages.
4141+4242+### Package-Specific Tests
4343+4444+Test specific package:
4545+4646+```sh
4747+go test ./internal/repo
4848+go test ./internal/handlers
4949+go test ./cmd
5050+```
5151+5252+### Verbose Output
5353+5454+```sh
5555+go test -v ./...
5656+```
5757+5858+## Test Organization
5959+6060+Tests follow a hierarchical 3-level structure:
6161+6262+```go
6363+func TestRepositoryName(t *testing.T) {
6464+ // Setup once
6565+ db := CreateTestDB(t)
6666+ repos := SetupTestData(t, db)
6767+6868+ t.Run("Feature", func(t *testing.T) {
6969+ t.Run("scenario description", func(t *testing.T) {
7070+ // Test logic
7171+ })
7272+ })
7373+}
7474+```
7575+7676+Levels:
7777+7878+1. Package (top function)
7979+2. Feature (first t.Run)
8080+3. Scenario (nested t.Run)
8181+8282+## Test Patterns
8383+8484+### Repository Tests
8585+8686+Repository tests use scaffolding from `internal/repo/test_utilities.go`:
8787+8888+```go
8989+func TestTaskRepository(t *testing.T) {
9090+ db := CreateTestDB(t)
9191+ repos := SetupTestData(t, db)
9292+ ctx := context.Background()
9393+9494+ t.Run("Create", func(t *testing.T) {
9595+ t.Run("creates task successfully", func(t *testing.T) {
9696+ task := NewTaskBuilder().
9797+ WithDescription("Test task").
9898+ Build()
9999+100100+ created, err := repos.Tasks.Create(ctx, task)
101101+ AssertNoError(t, err, "create should succeed")
102102+ AssertEqual(t, "Test task", created.Description, "description should match")
103103+ })
104104+ })
105105+}
106106+```
107107+108108+### Handler Tests
109109+110110+Handler tests use `internal/handlers/handler_test_suite.go`:
111111+112112+```go
113113+func TestHandlerName(t *testing.T) {
114114+ suite := NewHandlerTestSuite(t)
115115+ defer suite.cleanup()
116116+ handler := CreateHandler(t, NewHandlerFunc)
117117+118118+ t.Run("Feature", func(t *testing.T) {
119119+ t.Run("scenario", func(t *testing.T) {
120120+ AssertNoError(t, handler.Method(), "operation should succeed")
121121+ })
122122+ })
123123+}
124124+```
125125+126126+## Test Utilities
127127+128128+### Assertion Helpers
129129+130130+Located in `internal/repo/test_utilities.go` and `internal/handlers/test_utilities.go`:
131131+132132+```go
133133+// Error checking
134134+AssertNoError(t, err, "operation should succeed")
135135+AssertError(t, err, "operation should fail")
136136+137137+// Value comparison
138138+AssertEqual(t, expected, actual, "values should match")
139139+AssertTrue(t, condition, "should be true")
140140+AssertFalse(t, condition, "should be false")
141141+142142+// Nil checking
143143+AssertNil(t, value, "should be nil")
144144+AssertNotNil(t, value, "should not be nil")
145145+146146+// String operations
147147+AssertContains(t, str, substr, "should contain substring")
148148+```
149149+150150+### Test Data Builders
151151+152152+Create test data with builders:
153153+154154+```go
155155+task := NewTaskBuilder().
156156+ WithDescription("Test task").
157157+ WithStatus("pending").
158158+ WithPriority("high").
159159+ WithProject("test-project").
160160+ Build()
161161+162162+book := NewBookBuilder().
163163+ WithTitle("Test Book").
164164+ WithAuthor("Test Author").
165165+ Build()
166166+167167+note := NewNoteBuilder().
168168+ WithTitle("Test Note").
169169+ WithContent("Test content").
170170+ Build()
171171+```
172172+173173+### Test Database
174174+175175+In-memory SQLite for isolated tests:
176176+177177+```go
178178+db := CreateTestDB(t) // Automatic cleanup via t.Cleanup()
179179+```
180180+181181+### Sample Data
182182+183183+Pre-populated test data:
184184+185185+```go
186186+repos := SetupTestData(t, db)
187187+// Creates tasks, notes, books, movies, TV shows
188188+```
189189+190190+## Test Naming
191191+192192+Use direct descriptions without "should":
193193+194194+```go
195195+t.Run("creates task successfully", func(t *testing.T) { }) // Good
196196+t.Run("should create task", func(t *testing.T) { }) // Bad
197197+t.Run("returns error for invalid input", func(t *testing.T) { }) // Good
198198+```
199199+200200+## Test Independence
201201+202202+Each test must be independent:
203203+204204+- Use `CreateTestDB(t)` for isolated database
205205+- Don't rely on test execution order
206206+- Clean up resources with `t.Cleanup()`
207207+- Avoid package-level state
208208+209209+## Coverage Targets
210210+211211+Maintain high coverage for:
212212+213213+- Repository layer (data access)
214214+- Handler layer (business logic)
215215+- Services (external integrations)
216216+- Models (data validation)
217217+218218+Current coverage visible via:
219219+220220+```sh
221221+task cov
222222+```
223223+224224+## Continuous Integration
225225+226226+Tests run automatically on:
227227+228228+- Pull requests
229229+- Main branch commits
230230+- Release builds
231231+232232+CI configuration validates:
233233+234234+- All tests pass
235235+- No race conditions
236236+- Coverage thresholds met
237237+238238+## Debugging Tests
239239+240240+### Run Single Test
241241+242242+```sh
243243+go test -run TestTaskRepository ./internal/repo
244244+go test -run TestTaskRepository/Create ./internal/repo
245245+```
246246+247247+### Race Detector
248248+249249+```sh
250250+go test -race ./...
251251+```
252252+253253+### Verbose with Stack Traces
254254+255255+```sh
256256+go test -v -race ./internal/repo 2>&1 | grep -A 10 "FAIL"
257257+```
258258+259259+## Best Practices
260260+261261+1. Write tests for all public APIs
262262+2. Use builders for complex test data
263263+3. Apply semantic assertion helpers
264264+4. Keep tests focused and readable
265265+5. Test both success and error paths
266266+6. Avoid brittle time-based tests
267267+7. Mock external dependencies
268268+8. Use table-driven tests for variations
···11-# Media Examples
22-33-Examples of managing your reading lists and watch queues using Noteleaf.
44-55-## Books
66-77-### Adding Books
88-99-Search and add from Open Library:
1010-1111-```sh
1212-noteleaf media book add "The Name of the Wind"
1313-noteleaf media book add "Project Hail Mary"
1414-noteleaf media book add "Dune"
1515-```
1616-1717-Add by author:
1818-1919-```sh
2020-noteleaf media book add "Foundation by Isaac Asimov"
2121-```
2222-2323-Add with specific year:
2424-2525-```sh
2626-noteleaf media book add "1984 by George Orwell 1949"
2727-```
2828-2929-### Viewing Books
3030-3131-List all books:
3232-3333-```sh
3434-noteleaf media book list
3535-```
3636-3737-Filter by status:
3838-3939-```sh
4040-noteleaf media book list --status queued
4141-noteleaf media book list --status reading
4242-noteleaf media book list --status finished
4343-```
4444-4545-### Managing Reading Status
4646-4747-Start reading:
4848-4949-```sh
5050-noteleaf media book reading 1
5151-```
5252-5353-Mark as finished:
5454-5555-```sh
5656-noteleaf media book finished 1
5757-```
5858-5959-### Tracking Progress
6060-6161-Update reading progress (percentage):
6262-6363-```sh
6464-noteleaf media book progress 1 25
6565-noteleaf media book progress 1 50
6666-noteleaf media book progress 1 75
6767-```
6868-6969-Update with page numbers:
7070-7171-```sh
7272-noteleaf media book progress 1 150 --total 400
7373-```
7474-7575-### Book Details
7676-7777-View book details:
7878-7979-```sh
8080-noteleaf media book view 1
8181-```
8282-8383-### Updating Book Information
8484-8585-Update book notes:
8686-8787-```sh
8888-noteleaf media book update 1 --notes "Excellent worldbuilding and magic system"
8989-```
9090-9191-Add rating:
9292-9393-```sh
9494-noteleaf media book update 1 --rating 5
9595-```
9696-9797-### Removing Books
9898-9999-Remove from list:
100100-101101-```sh
102102-noteleaf media book remove 1
103103-```
104104-105105-## Movies
106106-107107-### Adding Movies
108108-109109-Add movie:
110110-111111-```sh
112112-noteleaf media movie add "The Matrix"
113113-noteleaf media movie add "Inception"
114114-noteleaf media movie add "Interstellar"
115115-```
116116-117117-Add with year:
118118-119119-```sh
120120-noteleaf media movie add "Blade Runner 1982"
121121-```
122122-123123-### Viewing Movies
124124-125125-List all movies:
126126-127127-```sh
128128-noteleaf media movie list
129129-```
130130-131131-Filter by status:
132132-133133-```sh
134134-noteleaf media movie list --status queued
135135-noteleaf media movie list --status watched
136136-```
137137-138138-### Managing Watch Status
139139-140140-Mark as watched:
141141-142142-```sh
143143-noteleaf media movie watched 1
144144-```
145145-146146-### Movie Details
147147-148148-View movie details:
149149-150150-```sh
151151-noteleaf media movie view 1
152152-```
153153-154154-### Updating Movie Information
155155-156156-Add notes and rating:
157157-158158-```sh
159159-noteleaf media movie update 1 --notes "Mind-bending sci-fi" --rating 5
160160-```
161161-162162-### Removing Movies
163163-164164-Remove from list:
165165-166166-```sh
167167-noteleaf media movie remove 1
168168-```
169169-170170-## TV Shows
171171-172172-### Adding TV Shows
173173-174174-Add TV show:
175175-176176-```sh
177177-noteleaf media tv add "Breaking Bad"
178178-noteleaf media tv add "The Wire"
179179-noteleaf media tv add "Better Call Saul"
180180-```
181181-182182-### Viewing TV Shows
183183-184184-List all shows:
185185-186186-```sh
187187-noteleaf media tv list
188188-```
189189-190190-Filter by status:
191191-192192-```sh
193193-noteleaf media tv list --status queued
194194-noteleaf media tv list --status watching
195195-noteleaf media tv list --status watched
196196-```
197197-198198-### Managing Watch Status
199199-200200-Start watching:
201201-202202-```sh
203203-noteleaf media tv watching 1
204204-```
205205-206206-Mark as finished:
207207-208208-```sh
209209-noteleaf media tv watched 1
210210-```
211211-212212-Put on hold:
213213-214214-```sh
215215-noteleaf media tv update 1 --status on-hold
216216-```
217217-218218-### TV Show Details
219219-220220-View show details:
221221-222222-```sh
223223-noteleaf media tv view 1
224224-```
225225-226226-### Updating TV Show Information
227227-228228-Update current episode:
229229-230230-```sh
231231-noteleaf media tv update 1 --season 2 --episode 5
232232-```
233233-234234-Add notes and rating:
235235-236236-```sh
237237-noteleaf media tv update 1 --notes "Intense character development" --rating 5
238238-```
239239-240240-### Removing TV Shows
241241-242242-Remove from list:
243243-244244-```sh
245245-noteleaf media tv remove 1
246246-```
247247-248248-## Common Workflows
249249-250250-### Weekend Watch List
251251-252252-Plan your weekend viewing:
253253-254254-```sh
255255-# Add movies
256256-noteleaf media movie add "The Shawshank Redemption"
257257-noteleaf media movie add "Pulp Fiction"
258258-noteleaf media movie add "Forrest Gump"
259259-260260-# View queue
261261-noteleaf media movie list --status queued
262262-```
263263-264264-### Reading Challenge
265265-266266-Track annual reading goal:
267267-268268-```sh
269269-# Add books to queue
270270-noteleaf media book add "The Lord of the Rings"
271271-noteleaf media book add "The Hobbit"
272272-noteleaf media book add "Mistborn"
273273-274274-# Check progress
275275-noteleaf media book list --status finished
276276-noteleaf media book list --status reading
277277-```
278278-279279-### Binge Watching Tracker
280280-281281-Track TV series progress:
282282-283283-```sh
284284-# Start series
285285-noteleaf media tv add "Game of Thrones"
286286-noteleaf media tv watching 1
287287-288288-# Update progress
289289-noteleaf media tv update 1 --season 1 --episode 1
290290-noteleaf media tv update 1 --season 1 --episode 2
291291-292292-# View current shows
293293-noteleaf media tv list --status watching
294294-```
295295-296296-### Media Recommendations
297297-298298-Keep track of recommendations:
299299-300300-```sh
301301-# Add recommended items
302302-noteleaf media book add "Sapiens" --notes "Recommended by John"
303303-noteleaf media movie add "Parasite" --notes "Won Best Picture 2020"
304304-noteleaf media tv add "Succession" --notes "From Reddit recommendations"
305305-306306-# View recommendations
307307-noteleaf media book list --static | grep "Recommended"
308308-```
309309-310310-### Review and Rating
311311-312312-After finishing, add review:
313313-314314-```sh
315315-# Book review
316316-noteleaf media book finished 1
317317-noteleaf media book update 1 \
318318- --rating 5 \
319319- --notes "Masterful storytelling. The magic system is one of the best in fantasy."
320320-321321-# Movie review
322322-noteleaf media movie watched 2
323323-noteleaf media movie update 2 \
324324- --rating 4 \
325325- --notes "Great cinematography but slow pacing in second act."
326326-327327-# TV show review
328328-noteleaf media tv watched 3
329329-noteleaf media tv update 3 \
330330- --rating 5 \
331331- --notes "Best character development I've seen. Final season was perfect."
332332-```
333333-334334-### Genre Organization
335335-336336-Organize by genre using notes:
337337-338338-```sh
339339-noteleaf media book add "Snow Crash" --notes "Genre: Cyberpunk"
340340-noteleaf media book add "Neuromancer" --notes "Genre: Cyberpunk"
341341-noteleaf media book add "The Expanse" --notes "Genre: Space Opera"
342342-343343-# Find by genre
344344-noteleaf media book list --static | grep "Cyberpunk"
345345-```
346346-347347-### Currently Consuming
348348-349349-See what you're currently reading/watching:
350350-351351-```sh
352352-noteleaf media book list --status reading
353353-noteleaf media tv list --status watching
354354-```
355355-356356-### Completed This Month
357357-358358-View completed items:
359359-360360-```sh
361361-noteleaf media book list --status finished
362362-noteleaf media movie list --status watched
363363-noteleaf media tv list --status watched
364364-```
365365-366366-### Clear Finished Items
367367-368368-Archive or remove completed media:
369369-370370-```sh
371371-# Remove watched movies
372372-noteleaf media movie remove 1 2 3
373373-374374-# Remove finished books
375375-noteleaf media book remove 4 5 6
376376-```
377377-378378-## Statistics and Reports
379379-380380-### Reading Statistics
381381-382382-Count books by status:
383383-384384-```sh
385385-echo "Queued: $(noteleaf media book list --status queued --static | wc -l)"
386386-echo "Reading: $(noteleaf media book list --status reading --static | wc -l)"
387387-echo "Finished: $(noteleaf media book list --status finished --static | wc -l)"
388388-```
389389-390390-### Viewing Habits
391391-392392-Track watch queue size:
393393-394394-```sh
395395-echo "Movies to watch: $(noteleaf media movie list --status queued --static | wc -l)"
396396-echo "Shows in progress: $(noteleaf media tv list --status watching --static | wc -l)"
397397-```
-294
website/docs/examples/notes.md
···11-# Note Examples
22-33-Examples of note-taking workflows using Noteleaf.
44-55-## Creating Notes
66-77-### Create Note from Command Line
88-99-```sh
1010-noteleaf note create "Meeting Notes" "Discussed Q4 roadmap and priorities"
1111-```
1212-1313-### Create Note with Tags
1414-1515-```sh
1616-noteleaf note create "API Design Ideas" "REST vs GraphQL considerations" --tags api,design
1717-```
1818-1919-### Create Note from File
2020-2121-```sh
2222-noteleaf note create --file notes.md
2323-```
2424-2525-### Create Note Interactively
2626-2727-Opens your editor for composition:
2828-2929-```sh
3030-noteleaf note create --interactive
3131-```
3232-3333-Specify editor:
3434-3535-```sh
3636-EDITOR=vim noteleaf note create --interactive
3737-```
3838-3939-### Create Note with Multiple Paragraphs
4040-4141-```sh
4242-noteleaf note create "Project Retrospective" "
4343-What went well:
4444-- Good team collaboration
4545-- Met all deadlines
4646-- Quality code reviews
4747-4848-What to improve:
4949-- Better documentation
5050-- More automated tests
5151-- Earlier stakeholder feedback
5252-"
5353-```
5454-5555-## Viewing Notes
5656-5757-### List All Notes
5858-5959-Interactive mode:
6060-6161-```sh
6262-noteleaf note list
6363-```
6464-6565-Static output:
6666-6767-```sh
6868-noteleaf note list --static
6969-```
7070-7171-### Filter by Tags
7272-7373-```sh
7474-noteleaf note list --tags meeting
7575-noteleaf note list --tags api,design
7676-```
7777-7878-### View Archived Notes
7979-8080-```sh
8181-noteleaf note list --archived
8282-```
8383-8484-### Read a Note
8585-8686-Display note content:
8787-8888-```sh
8989-noteleaf note read 1
9090-```
9191-9292-### Search Notes
9393-9494-```sh
9595-noteleaf note search "API design"
9696-noteleaf note search "meeting notes"
9797-```
9898-9999-## Editing Notes
100100-101101-### Edit Note in Editor
102102-103103-Opens note in your editor:
104104-105105-```sh
106106-noteleaf note edit 1
107107-```
108108-109109-With specific editor:
110110-111111-```sh
112112-EDITOR=nvim noteleaf note edit 1
113113-```
114114-115115-### Update Note Title
116116-117117-```sh
118118-noteleaf note update 1 --title "Updated Meeting Notes"
119119-```
120120-121121-### Add Tags to Note
122122-123123-```sh
124124-noteleaf note tag 1 --add important,todo
125125-```
126126-127127-### Remove Tags from Note
128128-129129-```sh
130130-noteleaf note tag 1 --remove draft
131131-```
132132-133133-## Organizing Notes
134134-135135-### Archive a Note
136136-137137-```sh
138138-noteleaf note archive 1
139139-```
140140-141141-### Unarchive a Note
142142-143143-```sh
144144-noteleaf note unarchive 1
145145-```
146146-147147-### Delete a Note
148148-149149-```sh
150150-noteleaf note remove 1
151151-```
152152-153153-With confirmation:
154154-155155-```sh
156156-noteleaf note remove 1 --confirm
157157-```
158158-159159-## Common Workflows
160160-161161-### Quick Meeting Notes
162162-163163-```sh
164164-noteleaf note create "Team Standup $(date +%Y-%m-%d)" --interactive --tags meeting,standup
165165-```
166166-167167-### Project Documentation
168168-169169-```sh
170170-noteleaf note create "Project Architecture" "$(cat architecture.md)" --tags docs,architecture
171171-```
172172-173173-### Research Notes
174174-175175-Create research note:
176176-177177-```sh
178178-noteleaf note create "GraphQL Research" --interactive --tags research,api
179179-```
180180-181181-List all research notes:
182182-183183-```sh
184184-noteleaf note list --tags research
185185-```
186186-187187-### Code Snippets
188188-189189-```sh
190190-noteleaf note create "Useful Git Commands" "
191191-# Rebase last 3 commits
192192-git rebase -i HEAD~3
193193-194194-# Undo last commit
195195-git reset --soft HEAD~1
196196-197197-# Show files changed in commit
198198-git show --name-only <commit>
199199-" --tags git,snippets,reference
200200-```
201201-202202-### Daily Journal
203203-204204-```sh
205205-noteleaf note create "Journal $(date +%Y-%m-%d)" --interactive --tags journal
206206-```
207207-208208-### Ideas and Brainstorming
209209-210210-```sh
211211-noteleaf note create "Product Ideas" --interactive --tags ideas,product
212212-```
213213-214214-List all ideas:
215215-216216-```sh
217217-noteleaf note list --tags ideas
218218-```
219219-220220-## Exporting Notes
221221-222222-### Export Single Note
223223-224224-```sh
225225-noteleaf note export 1 --format markdown > note.md
226226-noteleaf note export 1 --format html > note.html
227227-```
228228-229229-### Export All Notes
230230-231231-```sh
232232-noteleaf note export --all --format markdown --output notes/
233233-```
234234-235235-### Export Notes by Tag
236236-237237-```sh
238238-noteleaf note export --tags meeting --format markdown --output meetings/
239239-```
240240-241241-## Advanced Usage
242242-243243-### Template-based Notes
244244-245245-Create a note template file:
246246-247247-```sh
248248-cat > ~/templates/meeting.md << 'EOF'
249249-# Meeting: [TITLE]
250250-Date: [DATE]
251251-Attendees: [NAMES]
252252-253253-## Agenda
254254--
255255-256256-## Discussion
257257--
258258-259259-## Action Items
260260-- [ ]
261261-262262-## Next Meeting
263263-Date:
264264-EOF
265265-```
266266-267267-Use template:
268268-269269-```sh
270270-noteleaf note create --file ~/templates/meeting.md
271271-```
272272-273273-### Linking Notes
274274-275275-Reference other notes in content:
276276-277277-```sh
278278-noteleaf note create "Implementation Plan" "
279279-Based on the design in Note #5, we will:
280280-1. Set up database schema (see Note #12)
281281-2. Implement API endpoints
282282-3. Add frontend components
283283-284284-Related: Note #5 (Design), Note #12 (Schema)
285285-" --tags implementation,plan
286286-```
287287-288288-### Note Statistics
289289-290290-View note count by tag:
291291-292292-```sh
293293-noteleaf note list --static | grep -c "tag:meeting"
294294-```
-482
website/docs/examples/publication.md
···11-# Publication Examples
22-33-Examples of publishing notes to leaflet.pub using the AT Protocol integration.
44-55-## Overview
66-77-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.
88-99-## Authentication
1010-1111-### Initial Authentication
1212-1313-Authenticate with your BlueSky account:
1414-1515-```sh
1616-noteleaf pub auth username.bsky.social
1717-```
1818-1919-This will prompt for your app password interactively.
2020-2121-### Authenticate with Password Flag
2222-2323-Provide credentials directly:
2424-2525-```sh
2626-noteleaf pub auth username.bsky.social --password "your-app-password"
2727-```
2828-2929-### Creating an App Password
3030-3131-1. Visit [bsky.app/settings/app-passwords](https://bsky.app/settings/app-passwords)
3232-2. Create a new app password named "noteleaf"
3333-3. Use that password (not your main password) for authentication
3434-3535-### Check Authentication Status
3636-3737-```sh
3838-noteleaf pub status
3939-```
4040-4141-## Pulling Documents from Leaflet
4242-4343-### Pull All Documents
4444-4545-Fetch all drafts and published documents:
4646-4747-```sh
4848-noteleaf pub pull
4949-```
5050-5151-This will:
5252-- Connect to your leaflet account
5353-- Fetch all documents in your repository
5454-- Create new notes for documents not yet synced
5555-- Update existing notes that have changed
5656-5757-### After Pulling
5858-5959-List the synced notes:
6060-6161-```sh
6262-noteleaf pub list
6363-```
6464-6565-View synced notes interactively:
6666-6767-```sh
6868-noteleaf pub list --interactive
6969-```
7070-7171-## Publishing Local Notes
7272-7373-### Publish a Note
7474-7575-Create a new document on leaflet from a local note:
7676-7777-```sh
7878-noteleaf pub post 123
7979-```
8080-8181-### Publish as Draft
8282-8383-Create as draft instead of publishing immediately:
8484-8585-```sh
8686-noteleaf pub post 123 --draft
8787-```
8888-8989-### Preview Before Publishing
9090-9191-See what would be posted without actually posting:
9292-9393-```sh
9494-noteleaf pub post 123 --preview
9595-```
9696-9797-### Validate Conversion
9898-9999-Check if markdown conversion will work:
100100-101101-```sh
102102-noteleaf pub post 123 --validate
103103-```
104104-105105-## Updating Published Documents
106106-107107-### Update an Existing Document
108108-109109-Update a previously published note:
110110-111111-```sh
112112-noteleaf pub patch 123
113113-```
114114-115115-### Preview Update
116116-117117-See what would be updated:
118118-119119-```sh
120120-noteleaf pub patch 123 --preview
121121-```
122122-123123-### Validate Update
124124-125125-Check conversion before updating:
126126-127127-```sh
128128-noteleaf pub patch 123 --validate
129129-```
130130-131131-## Batch Operations
132132-133133-### Publish Multiple Notes
134134-135135-Create or update multiple documents at once:
136136-137137-```sh
138138-noteleaf pub push 1 2 3 4 5
139139-```
140140-141141-This will:
142142-- Create new documents for notes never published
143143-- Update existing documents for notes already on leaflet
144144-145145-### Batch Publish as Drafts
146146-147147-```sh
148148-noteleaf pub push 10 11 12 --draft
149149-```
150150-151151-## Viewing Publications
152152-153153-### List All Synced Notes
154154-155155-```sh
156156-noteleaf pub list
157157-```
158158-159159-Aliases:
160160-```sh
161161-noteleaf pub ls
162162-```
163163-164164-### Filter by Status
165165-166166-Published documents only:
167167-```sh
168168-noteleaf pub list --published
169169-```
170170-171171-Drafts only:
172172-```sh
173173-noteleaf pub list --draft
174174-```
175175-176176-All documents:
177177-```sh
178178-noteleaf pub list --all
179179-```
180180-181181-### Interactive Browser
182182-183183-Browse with TUI interface:
184184-185185-```sh
186186-noteleaf pub list --interactive
187187-noteleaf pub list -i
188188-```
189189-190190-With filters:
191191-```sh
192192-noteleaf pub list --published --interactive
193193-noteleaf pub list --draft -i
194194-```
195195-196196-## Common Workflows
197197-198198-### Initial Setup and Pull
199199-200200-Set up leaflet integration and pull existing documents:
201201-202202-```sh
203203-# Authenticate
204204-noteleaf pub auth username.bsky.social
205205-206206-# Check status
207207-noteleaf pub status
208208-209209-# Pull all documents
210210-noteleaf pub pull
211211-212212-# View synced notes
213213-noteleaf pub list --interactive
214214-```
215215-216216-### Publishing Workflow
217217-218218-Write locally, then publish to leaflet:
219219-220220-```sh
221221-# Create a note
222222-noteleaf note create "My Blog Post" --interactive
223223-224224-# List notes to get ID
225225-noteleaf note list
226226-227227-# Publish as draft first
228228-noteleaf pub post 42 --draft
229229-230230-# Review draft on leaflet.pub
231231-# Make edits locally
232232-noteleaf note edit 42
233233-234234-# Update the draft
235235-noteleaf pub patch 42
236236-237237-# When ready, republish without --draft flag
238238-noteleaf pub post 42
239239-```
240240-241241-### Sync Workflow
242242-243243-Keep local notes in sync with leaflet:
244244-245245-```sh
246246-# Pull latest changes from leaflet
247247-noteleaf pub pull
248248-249249-# Make local edits
250250-noteleaf note edit 123
251251-252252-# Push changes back
253253-noteleaf pub patch 123
254254-255255-# Check sync status
256256-noteleaf pub list --published
257257-```
258258-259259-### Draft Management
260260-261261-Work with drafts before publishing:
262262-263263-```sh
264264-# Create drafts
265265-noteleaf pub post 10 --draft
266266-noteleaf pub post 11 --draft
267267-noteleaf pub post 12 --draft
268268-269269-# View all drafts
270270-noteleaf pub list --draft
271271-272272-# Edit a draft locally
273273-noteleaf note edit 10
274274-275275-# Update on leaflet
276276-noteleaf pub patch 10
277277-278278-# Promote draft to published (re-post without --draft)
279279-noteleaf pub post 10
280280-```
281281-282282-### Batch Publishing
283283-284284-Publish multiple notes at once:
285285-286286-```sh
287287-# Create several notes
288288-noteleaf note create "Post 1" "Content 1"
289289-noteleaf note create "Post 2" "Content 2"
290290-noteleaf note create "Post 3" "Content 3"
291291-292292-# Get note IDs
293293-noteleaf note list --static
294294-295295-# Publish all at once
296296-noteleaf pub push 50 51 52
297297-298298-# Or as drafts
299299-noteleaf pub push 50 51 52 --draft
300300-```
301301-302302-### Review Before Publishing
303303-304304-Always preview and validate before publishing:
305305-306306-```sh
307307-# Validate markdown conversion
308308-noteleaf pub post 99 --validate
309309-310310-# Preview the output
311311-noteleaf pub post 99 --preview
312312-313313-# If everything looks good, publish
314314-noteleaf pub post 99
315315-```
316316-317317-### Cross-Platform Editing
318318-319319-Edit on leaflet.pub, sync to local:
320320-321321-```sh
322322-# Pull changes from leaflet
323323-noteleaf pub pull
324324-325325-# View what changed
326326-noteleaf pub list --interactive
327327-328328-# Make additional edits locally
329329-noteleaf note edit 123
330330-331331-# Push updates back
332332-noteleaf pub patch 123
333333-```
334334-335335-### Status Monitoring
336336-337337-Check authentication and publication status:
338338-339339-```sh
340340-# Check auth status
341341-noteleaf pub status
342342-343343-# List published documents
344344-noteleaf pub list --published
345345-346346-# Count publications
347347-noteleaf pub list --published --static | wc -l
348348-```
349349-350350-## Troubleshooting
351351-352352-### Re-authenticate
353353-354354-If authentication expires:
355355-356356-```sh
357357-noteleaf pub auth username.bsky.social
358358-```
359359-360360-### Check Status
361361-362362-Verify connection:
363363-364364-```sh
365365-noteleaf pub status
366366-```
367367-368368-### Force Pull
369369-370370-Re-sync all documents:
371371-372372-```sh
373373-noteleaf pub pull
374374-```
375375-376376-### Validate Before Publishing
377377-378378-If publishing fails, validate first:
379379-380380-```sh
381381-noteleaf pub post 123 --validate
382382-```
383383-384384-Check for markdown formatting issues that might not convert properly.
385385-386386-## Integration with Notes
387387-388388-### Publishing Flow
389389-390390-```sh
391391-# Create note locally
392392-noteleaf note create "Article Title" --interactive
393393-394394-# Add tags for organization
395395-noteleaf note tag 1 --add published,blog
396396-397397-# Publish to leaflet
398398-noteleaf pub post 1
399399-400400-# Continue editing locally
401401-noteleaf note edit 1
402402-403403-# Sync updates
404404-noteleaf pub patch 1
405405-```
406406-407407-### Import from Leaflet
408408-409409-```sh
410410-# Pull from leaflet
411411-noteleaf pub pull
412412-413413-# View imported notes
414414-noteleaf pub list
415415-416416-# Edit locally
417417-noteleaf note edit 123
418418-419419-# Continue working with standard note commands
420420-noteleaf note read 123
421421-noteleaf note tag 123 --add imported
422422-```
423423-424424-## Advanced Usage
425425-426426-### Selective Publishing
427427-428428-Publish only specific notes with a tag:
429429-430430-```sh
431431-# Tag notes for publication
432432-noteleaf note tag 10 --add ready-to-publish
433433-noteleaf note tag 11 --add ready-to-publish
434434-435435-# List tagged notes
436436-noteleaf note list --tags ready-to-publish
437437-438438-# Publish those notes
439439-noteleaf pub push 10 11
440440-```
441441-442442-### Draft Review Cycle
443443-444444-```sh
445445-# Publish drafts
446446-noteleaf pub push 1 2 3 --draft
447447-448448-# Review on leaflet.pub in browser
449449-# Make edits locally based on feedback
450450-451451-# Update drafts
452452-noteleaf pub push 1 2 3
453453-454454-# When ready, publish (create as non-drafts)
455455-noteleaf pub post 1
456456-noteleaf pub post 2
457457-noteleaf pub post 3
458458-```
459459-460460-### Publication Archive
461461-462462-Keep track of published work:
463463-464464-```sh
465465-# Tag published notes
466466-noteleaf note tag 123 --add published,2024,blog
467467-468468-# List all published notes
469469-noteleaf note list --tags published
470470-471471-# Archive old publications
472472-noteleaf note archive 123
473473-```
474474-475475-## Notes
476476-477477-- Authentication tokens are stored in the configuration file
478478-- Notes are matched by their leaflet record key (rkey)
479479-- The `push` command intelligently chooses between `post` and `patch`
480480-- Draft status is preserved when patching existing documents
481481-- Use `--preview` and `--validate` flags to test before publishing
482482-- Pull regularly to stay synced with changes made on leaflet.pub
-288
website/docs/examples/tasks.md
···11-# Task Examples
22-33-Examples of common task management workflows using Noteleaf.
44-55-## Basic Task Management
66-77-### Create a Simple Task
88-99-```sh
1010-noteleaf task add "Buy groceries"
1111-```
1212-1313-### Create Task with Priority
1414-1515-```sh
1616-noteleaf task add "Fix critical bug" --priority urgent
1717-noteleaf task add "Update documentation" --priority low
1818-```
1919-2020-### Create Task with Project
2121-2222-```sh
2323-noteleaf task add "Design new homepage" --project website
2424-noteleaf task add "Refactor auth service" --project backend
2525-```
2626-2727-### Create Task with Due Date
2828-2929-```sh
3030-noteleaf task add "Submit report" --due 2024-12-31
3131-noteleaf task add "Review PRs" --due tomorrow
3232-```
3333-3434-### Create Task with Tags
3535-3636-```sh
3737-noteleaf task add "Write blog post" --tags writing,blog
3838-noteleaf task add "Server maintenance" --tags ops,backend,infra
3939-```
4040-4141-### Create Task with Context
4242-4343-```sh
4444-noteleaf task add "Call client" --context phone
4545-noteleaf task add "Deploy to production" --context office
4646-```
4747-4848-### Create Task with All Attributes
4949-5050-```sh
5151-noteleaf task add "Launch marketing campaign" \
5252- --project marketing \
5353- --priority high \
5454- --due 2024-06-15 \
5555- --tags campaign,social \
5656- --context office
5757-```
5858-5959-## Viewing Tasks
6060-6161-### List All Tasks
6262-6363-Interactive mode:
6464-6565-```sh
6666-noteleaf task list
6767-```
6868-6969-Static output:
7070-7171-```sh
7272-noteleaf task list --static
7373-```
7474-7575-### Filter by Status
7676-7777-```sh
7878-noteleaf task list --status pending
7979-noteleaf task list --status completed
8080-```
8181-8282-### Filter by Priority
8383-8484-```sh
8585-noteleaf task list --priority high
8686-noteleaf task list --priority urgent
8787-```
8888-8989-### Filter by Project
9090-9191-```sh
9292-noteleaf task list --project website
9393-noteleaf task list --project backend
9494-```
9595-9696-### Filter by Tags
9797-9898-```sh
9999-noteleaf task list --tags urgent,bug
100100-```
101101-102102-### View Task Details
103103-104104-```sh
105105-noteleaf task view 1
106106-```
107107-108108-## Updating Tasks
109109-110110-### Mark Task as Done
111111-112112-```sh
113113-noteleaf task done 1
114114-```
115115-116116-### Update Task Priority
117117-118118-```sh
119119-noteleaf task update 1 --priority high
120120-```
121121-122122-### Update Task Project
123123-124124-```sh
125125-noteleaf task update 1 --project website
126126-```
127127-128128-### Add Tags to Task
129129-130130-```sh
131131-noteleaf task update 1 --add-tags backend,api
132132-```
133133-134134-### Remove Tags from Task
135135-136136-```sh
137137-noteleaf task update 1 --remove-tags urgent
138138-```
139139-140140-### Edit Task Interactively
141141-142142-Opens task in your editor:
143143-144144-```sh
145145-noteleaf task edit 1
146146-```
147147-148148-## Time Tracking
149149-150150-### Start Time Tracking
151151-152152-```sh
153153-noteleaf task start 1
154154-```
155155-156156-### Stop Time Tracking
157157-158158-```sh
159159-noteleaf task stop 1
160160-```
161161-162162-### View Timesheet
163163-164164-All entries:
165165-166166-```sh
167167-noteleaf task timesheet
168168-```
169169-170170-Filtered by date:
171171-172172-```sh
173173-noteleaf task timesheet --from 2024-01-01 --to 2024-01-31
174174-```
175175-176176-Filtered by project:
177177-178178-```sh
179179-noteleaf task timesheet --project website
180180-```
181181-182182-## Project Management
183183-184184-### List All Projects
185185-186186-```sh
187187-noteleaf task projects
188188-```
189189-190190-### View Tasks in Project
191191-192192-```sh
193193-noteleaf task list --project website
194194-```
195195-196196-## Tag Management
197197-198198-### List All Tags
199199-200200-```sh
201201-noteleaf task tags
202202-```
203203-204204-### View Tasks with Tag
205205-206206-```sh
207207-noteleaf task list --tags urgent
208208-```
209209-210210-## Context Management
211211-212212-### List All Contexts
213213-214214-```sh
215215-noteleaf task contexts
216216-```
217217-218218-### View Tasks in Context
219219-220220-```sh
221221-noteleaf task list --context office
222222-```
223223-224224-## Advanced Workflows
225225-226226-### Daily Planning
227227-228228-View today's tasks:
229229-230230-```sh
231231-noteleaf task list --due today
232232-```
233233-234234-View overdue tasks:
235235-236236-```sh
237237-noteleaf task list --due overdue
238238-```
239239-240240-### Weekly Review
241241-242242-View completed tasks this week:
243243-244244-```sh
245245-noteleaf task list --status completed --from monday
246246-```
247247-248248-View pending high-priority tasks:
249249-250250-```sh
251251-noteleaf task list --status pending --priority high
252252-```
253253-254254-### Project Focus
255255-256256-List all tasks for a project, sorted by priority:
257257-258258-```sh
259259-noteleaf task list --project website --sort priority
260260-```
261261-262262-### Bulk Operations
263263-264264-Mark multiple tasks as done:
265265-266266-```sh
267267-noteleaf task done 1 2 3 4
268268-```
269269-270270-Delete multiple tasks:
271271-272272-```sh
273273-noteleaf task delete 5 6 7
274274-```
275275-276276-## Task Deletion
277277-278278-### Delete a Task
279279-280280-```sh
281281-noteleaf task delete 1
282282-```
283283-284284-### Delete with Confirmation
285285-286286-```sh
287287-noteleaf task delete 1 --confirm
288288-```
+204
website/docs/integrations/openlibrary.md
···11+---
22+title: Open Library API
33+sidebar_label: Open Library
44+sidebar_position: 1
55+description: Book metadata via Open Library API integration.
66+---
77+88+# Open Library API
99+1010+Noteleaf integrates with [Open Library](https://openlibrary.org) to fetch book metadata, search for books, and enrich your reading list.
1111+1212+## Overview
1313+1414+Open Library provides:
1515+1616+- Book search by title, author, ISBN
1717+- Work and edition metadata
1818+- Author information
1919+- Cover images
2020+- Subject classifications
2121+- Publication details
2222+2323+## Configuration
2424+2525+No API key required. Open Library is a free, open API service.
2626+2727+Optional user agent configuration is handled automatically:
2828+2929+```toml
3030+# .noteleaf.conf.toml
3131+# No configuration needed for Open Library
3232+```
3333+3434+## Rate Limiting
3535+3636+Open Library enforces rate limits:
3737+3838+- 180 requests per minute
3939+- 3 requests per second
4040+- Burst limit: 5 requests
4141+4242+Noteleaf automatically manages rate limiting to stay within these boundaries.
4343+4444+## Book Search
4545+4646+Search for books from the command line:
4747+4848+```sh
4949+noteleaf book search "Design Patterns"
5050+noteleaf book search "Neal Stephenson"
5151+```
5252+5353+Interactive selection shows:
5454+5555+- Title
5656+- Author(s)
5757+- First publication year
5858+- Edition count
5959+- Publisher information
6060+6161+## Book Metadata
6262+6363+When adding a book, Noteleaf fetches:
6464+6565+- Title
6666+- Author names
6767+- Publication year
6868+- Edition information
6969+- Subjects/genres
7070+- Description (when available)
7171+- Cover ID
7272+7373+## API Endpoints
7474+7575+### Search Endpoint
7676+7777+```
7878+GET https://openlibrary.org/search.json
7979+```
8080+8181+Parameters:
8282+8383+- `q`: Search query
8484+- `offset`: Pagination offset
8585+- `limit`: Results per page
8686+- `fields`: Requested fields
8787+8888+### Work Endpoint
8989+9090+```
9191+GET https://openlibrary.org/works/{work_key}.json
9292+```
9393+9494+Returns detailed work information including authors, description, subjects, and covers.
9595+9696+## Data Mapping
9797+9898+Open Library data maps to Noteleaf book fields:
9999+100100+| Open Library | Noteleaf Field |
101101+|--------------|----------------|
102102+| title | Title |
103103+| author_name | Author |
104104+| first_publish_year | Notes (included) |
105105+| edition_count | Notes (included) |
106106+| publisher | Notes (included) |
107107+| subject | Notes (included) |
108108+| cover_i | Notes (cover ID) |
109109+110110+## Example API Response
111111+112112+Search result document:
113113+114114+```json
115115+{
116116+ "key": "/works/OL45804W",
117117+ "title": "Design Patterns",
118118+ "author_name": ["Erich Gamma", "Richard Helm"],
119119+ "first_publish_year": 1994,
120120+ "edition_count": 23,
121121+ "isbn": ["0201633612", "9780201633610"],
122122+ "publisher": ["Addison-Wesley"],
123123+ "subject": ["Software design", "Object-oriented programming"],
124124+ "cover_i": 8644882
125125+}
126126+```
127127+128128+## Limitations
129129+130130+### No Direct Page Count
131131+132132+Open Library doesn't consistently provide page counts in search results. Use the interactive editor to add page counts manually if needed.
133133+134134+### Author Keys vs Names
135135+136136+Work endpoints return author keys (`/authors/OL123A`) rather than full names. Noteleaf displays available author names from search results.
137137+138138+### Cover Images
139139+140140+Cover IDs are stored but not automatically downloaded. Future versions may support local cover image caching.
141141+142142+## Error Handling
143143+144144+### Network Issues
145145+146146+```sh
147147+noteleaf book search "query"
148148+# Error: failed to connect to Open Library
149149+```
150150+151151+Check internet connection and Open Library status.
152152+153153+### Rate Limit Exceeded
154154+155155+Noteleaf automatically waits when approaching rate limits. If you see delays, this is normal behavior.
156156+157157+### No Results
158158+159159+```sh
160160+noteleaf book search "very obscure title"
161161+# No results found
162162+```
163163+164164+Try:
165165+166166+- Different search terms
167167+- Author names instead of titles
168168+- ISBNs for specific editions
169169+170170+## API Service Architecture
171171+172172+Implementation in `internal/services/services.go`:
173173+174174+```go
175175+type BookService struct {
176176+ client *http.Client
177177+ limiter *rate.Limiter
178178+ baseURL string
179179+}
180180+```
181181+182182+Features:
183183+184184+- Automatic rate limiting
185185+- Context-aware requests
186186+- Proper error handling
187187+- Timeout management (30s)
188188+189189+## Custom User Agent
190190+191191+Noteleaf identifies itself to Open Library:
192192+193193+```
194194+User-Agent: Noteleaf/v{version} (contact: info@stormlightlabs.org)
195195+```
196196+197197+This helps Open Library track API usage and contact developers if needed.
198198+199199+## Resources
200200+201201+- [Open Library API Documentation](https://openlibrary.org/dev/docs/api/books)
202202+- [Open Library Search](https://openlibrary.org/dev/docs/api/search)
203203+- [Open Library Covers](https://openlibrary.org/dev/docs/api/covers)
204204+- [Rate Limiting Policy](https://openlibrary.org/developers/api)
+164
website/docs/integrations/overview.md
···11+---
22+title: External Integrations
33+sidebar_label: Overview
44+sidebar_position: 1
55+description: Overview of external service integrations.
66+---
77+88+# External Integrations
99+1010+Noteleaf integrates with external services to enrich your productivity workflow and extend functionality beyond local storage.
1111+1212+## Available Integrations
1313+1414+### Open Library API
1515+1616+Free book metadata service for building your reading list.
1717+1818+**Features:**
1919+2020+- Search books by title, author, ISBN
2121+- Fetch metadata (author, year, subjects)
2222+- Edition and publication information
2323+- No API key required
2424+2525+**Use Cases:**
2626+2727+- Adding books to reading list
2828+- Enriching book metadata
2929+- Discovering related works
3030+3131+See [Open Library API](./openlibrary.md) for details.
3232+3333+### Leaflet.pub
3434+3535+Decentralized publishing platform built on AT Protocol.
3636+3737+**Features:**
3838+3939+- Publish notes as structured documents
4040+- Pull existing documents into local notes
4141+- Update published content
4242+- Manage drafts and publications
4343+4444+**Use Cases:**
4545+4646+- Blog publishing from terminal
4747+- Long-form content management
4848+- Decentralized content ownership
4949+5050+See [Leaflet.pub section](../leaflet/intro.md) for details.
5151+5252+### AT Protocol (Bluesky)
5353+5454+Authentication and identity via AT Protocol network.
5555+5656+**Features:**
5757+5858+- Decentralized identity (DID)
5959+- Session management
6060+- Token refresh
6161+- Secure authentication
6262+6363+**Use Cases:**
6464+6565+- Leaflet.pub authentication
6666+- Portable identity across services
6767+- Content verification
6868+6969+See [Authentication](../leaflet/authentication.md) for details.
7070+7171+## Integration Architecture
7272+7373+### Service Layer
7474+7575+External integrations live in `internal/services/`:
7676+7777+- `services.go` - Open Library API client
7878+- `atproto.go` - AT Protocol authentication
7979+- `http.go` - HTTP utilities and rate limiting
8080+8181+### Rate Limiting
8282+8383+All external services use rate limiting to respect API quotas:
8484+8585+- Open Library: 3 requests/second
8686+- AT Protocol: Per PDS configuration
8787+8888+Rate limiters are built-in and automatic.
8989+9090+### Error Handling
9191+9292+Services implement consistent error handling:
9393+9494+- Network errors
9595+- Rate limit exceeded
9696+- Authentication failures
9797+- Invalid responses
9898+9999+Errors propagate to user with actionable messages.
100100+101101+## Configuration
102102+103103+Integration configuration in `.noteleaf.conf.toml`:
104104+105105+```toml
106106+# Open Library (no configuration needed)
107107+# book_api_key = "" # Reserved for future use
108108+109109+# AT Protocol / Leaflet.pub
110110+atproto_handle = "username.bsky.social"
111111+atproto_did = "did:plc:..."
112112+atproto_pds_url = "https://bsky.social"
113113+atproto_access_jwt = "..."
114114+atproto_refresh_jwt = "..."
115115+```
116116+117117+See [Configuration](../Configuration.md) for all options.
118118+119119+## Offline Support
120120+121121+Noteleaf works fully offline for local data. Integrations are optional enhancements:
122122+123123+- Books can be added manually without Open Library
124124+- Notes exist locally without Leaflet.pub
125125+- Tasks and media work without any external service
126126+127127+External services enhance but don't require connectivity.
128128+129129+## Privacy and Data
130130+131131+### Data Sent
132132+133133+**Open Library:**
134134+135135+- Search queries
136136+- Work/edition IDs
137137+138138+**AT Protocol:**
139139+140140+- Handle/DID
141141+- Published note content
142142+- Authentication credentials
143143+144144+### Data Stored Locally
145145+146146+- API responses (cached)
147147+- Session tokens
148148+- Publication metadata
149149+150150+### No Tracking
151151+152152+Noteleaf does not:
153153+154154+- Track usage
155155+- Send analytics
156156+- Share data with third parties
157157+- Require accounts (except for publishing)
158158+159159+## Resources
160160+161161+- [Open Library API Documentation](https://openlibrary.org/developers/api)
162162+- [AT Protocol Docs](https://atproto.com)
163163+- [Leaflet.pub](https://leaflet.pub)
164164+- [Bluesky](https://bsky.app)
-47
website/docs/intro.md
···11----
22-sidebar_position: 1
33----
44-55-# Tutorial Intro
66-77-Let's discover **Docusaurus in less than 5 minutes**.
88-99-## Getting Started
1010-1111-Get started by **creating a new site**.
1212-1313-Or **try Docusaurus immediately** with **[docusaurus.new](https://docusaurus.new)**.
1414-1515-### What you'll need
1616-1717-- [Node.js](https://nodejs.org/en/download/) version 20.0 or above:
1818- - When installing Node.js, you are recommended to check all checkboxes related to dependencies.
1919-2020-## Generate a new site
2121-2222-Generate a new Docusaurus site using the **classic template**.
2323-2424-The classic template will automatically be added to your project after you run the command:
2525-2626-```bash
2727-npm init docusaurus@latest my-website classic
2828-```
2929-3030-You can type this command into Command Prompt, Powershell, Terminal, or any other integrated terminal of your code editor.
3131-3232-The command also installs all necessary dependencies you need to run Docusaurus.
3333-3434-## Start your site
3535-3636-Run the development server:
3737-3838-```bash
3939-cd my-website
4040-npm run start
4141-```
4242-4343-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.
4444-4545-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/.
4646-4747-Open `docs/intro.md` (this page) and edit some lines: the site **reloads automatically** and displays your changes.
+9
website/docs/leaflet/_category_.json
···11+{
22+ "label": "Leaflet Publishing",
33+ "position": 5,
44+ "link": {
55+ "type": "generated-index",
66+ "title": "Leaflet Publishing",
77+ "description": "Publish and sync documents with leaflet.pub and the AT Protocol."
88+ }
99+}
+41
website/docs/leaflet/authentication.md
···11+---
22+title: Authentication and Identity
33+sidebar_label: Auth & Identity
44+description: AT Protocol authentication, security, and session handling.
55+sidebar_position: 8
66+---
77+88+# Authentication and Identity
99+1010+## AT Protocol Authentication
1111+1212+Noteleaf uses AT Protocol's authentication system:
1313+1414+1. **Handle Resolution**: Your handle (e.g., `username.bsky.social`) is resolved to a DID (Decentralized Identifier)
1515+2. **Session Creation**: Authenticate with your app password to create a session
1616+3. **Session Token**: Noteleaf stores the session token for future requests
1717+4. **Token Refresh**: Sessions are refreshed automatically when they expire
1818+1919+## Security Considerations
2020+2121+**Use app passwords**: Never use your main BlueSky password with third-party tools. App passwords can be revoked without affecting your account.
2222+2323+**Token storage**: Session tokens are stored locally in the Noteleaf database. Protect your database file.
2424+2525+**Revocation**: If compromised, revoke the app password at [bsky.app/settings/app-passwords](https://bsky.app/settings/app-passwords).
2626+2727+## Session Management
2828+2929+**Check status**:
3030+3131+```sh
3232+noteleaf pub status
3333+```
3434+3535+**Re-authenticate**:
3636+3737+```sh
3838+noteleaf pub auth
3939+```
4040+4141+Sessions typically last 2-4 hours before requiring refresh. Noteleaf handles refresh automatically, but if authentication fails, run `pub auth` again.
+85
website/docs/leaflet/examples.md
···11+---
22+title: Publishing Examples
33+sidebar_label: Examples
44+description: End-to-end examples for posting, drafting, and syncing.
55+sidebar_position: 6
66+---
77+88+# Publishing Examples
99+1010+## Publishing a Blog Post
1111+1212+**Write the post locally**:
1313+1414+```sh
1515+noteleaf note create "Understanding AT Protocol" --editor
1616+```
1717+1818+Write in markdown, save, and close editor.
1919+2020+**Preview the conversion**:
2121+2222+```sh
2323+noteleaf pub post <note-id> --preview
2424+```
2525+2626+Review the output to ensure formatting is correct.
2727+2828+**Publish**:
2929+3030+```sh
3131+noteleaf pub post <note-id>
3232+```
3333+3434+**Update later**:
3535+3636+```sh
3737+noteleaf note edit <note-id>
3838+# Make changes
3939+noteleaf pub patch <note-id>
4040+```
4141+4242+## Draft Workflow
4343+4444+**Create draft**:
4545+4646+```sh
4747+noteleaf note create "Work in Progress" --editor
4848+noteleaf pub post <note-id> --draft
4949+```
5050+5151+**Iterate locally**:
5252+5353+```sh
5454+noteleaf note edit <note-id>
5555+noteleaf pub patch <note-id> # Updates draft
5656+```
5757+5858+**Publish when ready**: Use leaflet.pub web interface to change draft to published status (CLI command coming in future versions).
5959+6060+## Syncing Existing Content
6161+6262+**Pull all leaflet documents**:
6363+6464+```sh
6565+noteleaf pub pull
6666+```
6767+6868+**List synced documents**:
6969+7070+```sh
7171+noteleaf pub list
7272+```
7373+7474+**Read a synced document**:
7575+7676+```sh
7777+noteleaf pub read <note-id>
7878+```
7979+8080+**Edit locally and push updates**:
8181+8282+```sh
8383+noteleaf note edit <note-id>
8484+noteleaf pub patch <note-id>
8585+```
+53
website/docs/leaflet/getting-started.md
···11+---
22+title: Getting Started with Leaflet
33+sidebar_label: Getting Started
44+description: Prerequisites, app passwords, and authentication commands.
55+sidebar_position: 2
66+---
77+88+# Getting Started with Leaflet
99+1010+## Prerequisites
1111+1212+- Noteleaf installed and configured
1313+- A BlueSky & [Leaflet](https://leaflet.pub) account (create at [bsky.app](https://bsky.app))
1414+- App password for authentication
1515+1616+## Creating an App Password
1717+1818+For security, Noteleaf uses app passwords instead of your main BlueSky password:
1919+2020+1. Go to [bsky.app/settings/app-passwords](https://bsky.app/settings/app-passwords)
2121+2. Click "Add App Password"
2222+3. Name it "noteleaf" or similar
2323+4. Copy the generated password (you won't see it again)
2424+2525+### Authentication
2626+2727+Authenticate with your BlueSky handle and app password:
2828+2929+```sh
3030+noteleaf pub auth username.bsky.social
3131+```
3232+3333+You'll be prompted for the app password. Alternatively, provide it via flag:
3434+3535+```sh
3636+noteleaf pub auth username.bsky.social --password <app-password>
3737+```
3838+3939+**Re-authentication**: If your session expires, run `pub auth` again. Noteleaf remembers your last authenticated handle, so you can just run:
4040+4141+```sh
4242+noteleaf pub auth
4343+```
4444+4545+### Check Authentication Status
4646+4747+Verify you're authenticated:
4848+4949+```sh
5050+noteleaf pub status
5151+```
5252+5353+Shows your handle and session state.
+36
website/docs/leaflet/intro.md
···11+---
22+title: Leaflet.pub Introduction
33+sidebar_label: Introduction
44+description: Understand leaflet.pub and how Noteleaf integrates with it.
55+sidebar_position: 1
66+---
77+88+# Leaflet.pub Introduction
99+1010+## What is Leaflet.pub?
1111+1212+[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.
1313+1414+## AT Protocol and Decentralized Publishing
1515+1616+AT Protocol provides:
1717+1818+**Portable Identity**: Your identity (DID) is separate from any single service. You own your content and can move it between providers.
1919+2020+**Verifiable Data**: All documents are content-addressed and cryptographically signed, ensuring authenticity and preventing tampering.
2121+2222+**Interoperability**: Content published to leaflet.pub can be discovered and consumed by any AT Protocol-compatible client.
2323+2424+**Decentralized Storage**: Data is stored in personal data repositories (PDSs) under your control, not locked in a proprietary platform.
2525+2626+## How Noteleaf Integrates with Leaflet
2727+2828+Noteleaf can act as a leaflet.pub client, allowing you to:
2929+3030+1. **Authenticate** with your BlueSky/AT Protocol identity
3131+2. **Pull** existing documents from leaflet.pub into local notes
3232+3. **Publish** local notes as new leaflet documents
3333+4. **Update** previously published documents with changes
3434+5. **Manage** drafts and published content from the command line
3535+3636+This integration lets you write locally in markdown, manage content alongside tasks and research notes, and publish to a decentralized platform when ready.
+57
website/docs/leaflet/listing.md
···11+---
22+title: Listing and Reading Publications
33+sidebar_label: Listing & Reading
44+description: Browse leaflet-backed notes and read content locally.
55+sidebar_position: 7
66+---
77+88+# Listing and Reading Publications
99+1010+## List Published Documents
1111+1212+**All leaflet-synced notes**:
1313+1414+```sh
1515+noteleaf pub list
1616+```
1717+1818+**Only published documents**:
1919+2020+```sh
2121+noteleaf pub list --published
2222+```
2323+2424+**Only drafts**:
2525+2626+```sh
2727+noteleaf pub list --draft
2828+```
2929+3030+**Interactive browser**:
3131+3232+```sh
3333+noteleaf pub list --interactive
3434+```
3535+3636+Navigate with arrow keys, press Enter to read, `q` to quit.
3737+3838+## Reading a Publication
3939+4040+**Read specific document**:
4141+4242+```sh
4343+noteleaf pub read 123
4444+```
4545+4646+The identifier can be:
4747+4848+- Note ID (e.g., `123`)
4949+- Leaflet record key (rkey, e.g., `3jxx...`)
5050+5151+**Read newest publication**:
5252+5353+```sh
5454+noteleaf pub read
5555+```
5656+5757+Omitting the identifier shows the most recently published document.
+16
website/docs/leaflet/publications.md
···11+---
22+title: Leaflet Publications
33+sidebar_label: Publications
44+description: How publications work and how Noteleaf interacts with them.
55+sidebar_position: 3
66+---
77+88+# Leaflet Publications
99+1010+## What is a Publication?
1111+1212+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.
1313+1414+Future versions may support:
1515+1616+- Switching between publications
+95
website/docs/leaflet/rich-text.md
···11+---
22+title: Leaflet Rich Text and Blocks
33+sidebar_label: Rich Text
44+description: How markdown maps to leaflet blocks and formatting.
55+sidebar_position: 5
66+---
77+88+# Leaflet Rich Text and Blocks
99+1010+## Document Structure
1111+1212+Leaflet documents consist of blocksโdiscrete content units:
1313+1414+**Text Blocks**: Paragraphs of formatted text
1515+**Header Blocks**: Section titles (level 1-6)
1616+**Code Blocks**: Syntax-highlighted code with language annotation
1717+**Quote Blocks**: Blockquotes for citations
1818+**List Blocks**: Ordered or unordered lists
1919+**Rule Blocks**: Horizontal rules for visual separation
2020+2121+## Text Formatting
2222+2323+Text within blocks can have inline formatting called facets:
2424+2525+**Bold**: `**bold text**` โ Bold facet
2626+**Italic**: `*italic text*` โ Italic facet
2727+**Code**: `` `inline code` `` โ Code facet
2828+**Links**: `[text](url)` โ Link facet with URL
2929+**Strikethrough**: `~~struck~~` โ Strikethrough facet
3030+3131+Multiple formats can be combined:
3232+3333+```markdown
3434+**bold and *italic* text with [a link](https://example.com)**
3535+```
3636+3737+## Code Blocks
3838+3939+Code blocks preserve language information for syntax highlighting:
4040+4141+````markdown
4242+```python
4343+def hello():
4444+ print("Hello, leaflet!")
4545+```
4646+````
4747+4848+Converts to a code block with language="python".
4949+5050+Supported languages: Any language identifier is preserved, but rendering depends on leaflet.pub's syntax highlighter support.
5151+5252+## Blockquotes
5353+5454+Markdown blockquotes become quote blocks:
5555+5656+```markdown
5757+> This is a quote from another source.
5858+> It can span multiple lines.
5959+```
6060+6161+Nested blockquotes are flattened (leaflet doesn't support nesting).
6262+6363+## Lists
6464+6565+Both ordered and unordered lists are supported:
6666+6767+```markdown
6868+- Unordered item 1
6969+- Unordered item 2
7070+ - Nested item
7171+7272+1. Ordered item 1
7373+2. Ordered item 2
7474+ 1. Nested ordered item
7575+```
7676+7777+Nesting is preserved up to leaflet's limits.
7878+7979+## Horizontal Rules
8080+8181+Markdown horizontal rules become rule blocks:
8282+8383+```markdown
8484+---
8585+```
8686+8787+Use for section breaks.
8888+8989+## Images and Media
9090+9191+**Current status**: Image support is not yet implemented in the Noteleaf-to-leaflet converter.
9292+9393+**Future plans**: Images will be uploaded to blob storage and embedded in documents with image blocks.
9494+9595+**Workaround**: For now, images in markdown are either skipped or converted to links.
+147
website/docs/leaflet/workflow.md
···11+---
22+title: Publishing Workflow
33+sidebar_label: Workflow
44+description: Post, patch, drafts, pulling, and syncing documents.
55+sidebar_position: 4
66+---
77+88+# Publishing Workflow
99+1010+## Converting Notes to Leaflet Documents
1111+1212+Noteleaf converts markdown notes to leaflet's rich text block format:
1313+1414+**Supported Markdown Features**:
1515+1616+- Headers (`#`, `##`, `###`, etc.)
1717+- Paragraphs
1818+- Bold (`**bold**`)
1919+- Italic (`*italic*`)
2020+- Code (`inline code`)
2121+- Strikethrough (`~~text~~`)
2222+- Links (`[text](url)`)
2323+- Code blocks (` ```language ... ``` `)
2424+- Blockquotes (`> quote`)
2525+- Lists (ordered and unordered)
2626+- Horizontal rules (`---`)
2727+2828+**Conversion Process**:
2929+3030+1. Parse markdown into AST (abstract syntax tree)
3131+2. Convert AST nodes to leaflet block records
3232+3. Process text formatting into facets
3333+4. Validate document structure
3434+5. Upload to leaflet.pub via AT Protocol
3535+3636+## Creating a New Document
3737+3838+Publish a local note as a new leaflet document:
3939+4040+```sh
4141+noteleaf pub post 123
4242+```
4343+4444+This:
4545+4646+1. Converts the note to leaflet format
4747+2. Creates a new document on leaflet.pub
4848+3. Links the note to the document (stores the rkey)
4949+4. Marks the note as published
5050+5151+**Create as draft**:
5252+5353+```sh
5454+noteleaf pub post 123 --draft
5555+```
5656+5757+Drafts are saved to leaflet but not publicly visible until you publish them.
5858+5959+**Preview before posting**:
6060+6161+```sh
6262+noteleaf pub post 123 --preview
6363+```
6464+6565+Shows what the document will look like without actually posting.
6666+6767+**Validate conversion**:
6868+6969+```sh
7070+noteleaf pub post 123 --validate
7171+```
7272+7373+Checks if the markdown converts correctly to leaflet format without posting.
7474+7575+**Save to file**:
7676+7777+```sh
7878+noteleaf pub post 123 --preview --output document.json
7979+noteleaf pub post 123 --preview --output document.txt --plaintext
8080+```
8181+8282+## Updating Published Documents
8383+8484+Update an existing leaflet document from a local note:
8585+8686+```sh
8787+noteleaf pub patch 123
8888+```
8989+9090+Requirements:
9191+9292+- Note must have been previously posted or pulled from leaflet
9393+- Note must have a leaflet record key (rkey) in the database
9494+9595+**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.
9696+9797+**Preview changes**:
9898+9999+```sh
100100+noteleaf pub patch 123 --preview
101101+```
102102+103103+**Validate before patching**:
104104+105105+```sh
106106+noteleaf pub patch 123 --validate
107107+```
108108+109109+## Managing Drafts
110110+111111+**Create as draft**:
112112+113113+```sh
114114+noteleaf pub post 123 --draft
115115+```
116116+117117+**Update draft**:
118118+119119+```sh
120120+noteleaf pub patch 123
121121+```
122122+123123+**List drafts**:
124124+125125+```sh
126126+noteleaf pub list --draft
127127+```
128128+129129+**Publish a draft**: Edit the draft on leaflet.pub or use the API to change status (command support coming in future versions).
130130+131131+## Pulling Documents from Leaflet
132132+133133+Sync leaflet documents to local notes:
134134+135135+```sh
136136+noteleaf pub pull
137137+```
138138+139139+This:
140140+141141+1. Authenticates with leaflet.pub
142142+2. Fetches all documents in your repository
143143+3. Creates new notes for documents not yet synced
144144+4. Updates existing notes that have changed
145145+146146+**Matching logic**: Notes are matched to leaflet documents by their record key (rkey) stored in the database.
147147+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).
···11----
22-id: articles
33-title: Articles
44-sidebar_position: 3
55-description: Save and archive web articles
66----
77-88-## article
99-1010-Save and archive web articles locally.
1111-1212-Parse articles from supported websites, extract clean content, and save as
1313-both markdown and HTML. Maintains a searchable archive of articles with
1414-metadata including author, title, and publication date.
1515-1616-```bash
1717-noteleaf article
1818-```
1919-2020-### Subcommands
2121-2222-#### add
2323-2424-Parse and save article content from a supported website.
2525-2626-The article will be parsed using domain-specific XPath rules and saved
2727-as both Markdown and HTML files. Article metadata is stored in the database.
2828-2929-**Usage:**
3030-3131-```bash
3232-noteleaf article add <url>
3333-```
3434-3535-#### list
3636-3737-List saved articles with optional filtering.
3838-3939-Use query to filter by title, or use flags for more specific filtering.
4040-4141-**Usage:**
4242-4343-```bash
4444-noteleaf article list [query] [flags]
4545-```
4646-4747-**Options:**
4848-4949-```
5050- --author string Filter by author
5151- -l, --limit int Limit number of results (0 = no limit)
5252-```
5353-5454-**Aliases:** ls
5555-5656-#### view
5757-5858-Display article metadata and summary.
5959-6060-Shows article title, author, publication date, URL, and a brief content
6161-preview. Use 'read' command to view the full article content.
6262-6363-**Usage:**
6464-6565-```bash
6666-noteleaf article view <id>
6767-```
6868-6969-**Aliases:** show
7070-7171-#### read
7272-7373-Read the full markdown content of an article with beautiful formatting.
7474-7575-This displays the complete article content using syntax highlighting and proper formatting.
7676-7777-**Usage:**
7878-7979-```bash
8080-noteleaf article read <id>
8181-```
8282-8383-#### remove
8484-8585-Delete an article and its files permanently.
8686-8787-Removes the article metadata from the database and deletes associated markdown
8888-and HTML files. This operation cannot be undone.
8989-9090-**Usage:**
9191-9292-```bash
9393-noteleaf article remove <id>
9494-```
9595-9696-**Aliases:** rm, delete
9797-
-115
website/docs/manual/books.md
···11----
22-id: books
33-title: Books
44-sidebar_position: 4
55-description: Manage reading list and track progress
66----
77-88-## book
99-1010-Track books and reading progress.
1111-1212-Search Google Books API to add books to your reading list. Track which books
1313-you're reading, update progress percentages, and maintain a history of finished
1414-books.
1515-1616-```bash
1717-noteleaf media book
1818-```
1919-2020-### Subcommands
2121-2222-#### add
2323-2424-Search for books and add them to your reading list.
2525-2626-By default, shows search results in a simple list format where you can select by number.
2727-Use the -i flag for an interactive interface with navigation keys.
2828-2929-**Usage:**
3030-3131-```bash
3232-noteleaf media book add [search query...] [flags]
3333-```
3434-3535-**Options:**
3636-3737-```
3838- -i, --interactive Use interactive interface for book selection
3939-```
4040-4141-#### list
4242-4343-Display books in your reading list with progress indicators.
4444-4545-Shows book titles, authors, and reading progress percentages. Filter by --all,
4646---reading for books in progress, --finished for completed books, or --queued
4747-for books not yet started. Default shows queued books only.
4848-4949-**Usage:**
5050-5151-```bash
5252-noteleaf media book list [--all|--reading|--finished|--queued]
5353-```
5454-5555-#### reading
5656-5757-Mark a book as currently reading. Use this when you start a book from your queue.
5858-5959-**Usage:**
6060-6161-```bash
6262-noteleaf media book reading <id>
6363-```
6464-6565-#### finished
6666-6767-Mark a book as finished with current timestamp. Sets reading progress to 100%.
6868-6969-**Usage:**
7070-7171-```bash
7272-noteleaf media book finished <id>
7373-```
7474-7575-**Aliases:** read
7676-7777-#### remove
7878-7979-Remove a book from your reading list. Use this for books you no longer want to track.
8080-8181-**Usage:**
8282-8383-```bash
8484-noteleaf media book remove <id>
8585-```
8686-8787-**Aliases:** rm
8888-8989-#### progress
9090-9191-Set reading progress for a book.
9292-9393-Specify a percentage value between 0 and 100 to indicate how far you've
9494-progressed through the book. Automatically updates status to 'reading' if not
9595-already set.
9696-9797-**Usage:**
9898-9999-```bash
100100-noteleaf media book progress <id> <percentage>
101101-```
102102-103103-#### update
104104-105105-Change a book's status directly.
106106-107107-Valid statuses are: queued (not started), reading (in progress), finished
108108-(completed), or removed (no longer tracking).
109109-110110-**Usage:**
111111-112112-```bash
113113-noteleaf media book update <id> <status>
114114-```
115115-
-78
website/docs/manual/configuration.md
···11----
22-id: configuration
33-title: Configuration
44-sidebar_position: 7
55-description: Manage application configuration
66----
77-88-## config
99-1010-Manage noteleaf configuration
1111-1212-```bash
1313-noteleaf config
1414-```
1515-1616-### Subcommands
1717-1818-#### get
1919-2020-Display configuration values.
2121-2222-If no key is provided, displays all configuration values.
2323-Otherwise, displays the value for the specified key.
2424-2525-**Usage:**
2626-2727-```bash
2828-noteleaf config get [key]
2929-```
3030-3131-#### set
3232-3333-Update a configuration value.
3434-3535-Available keys:
3636- database_path - Custom database file path
3737- data_dir - Custom data directory
3838- date_format - Date format string (default: 2006-01-02)
3939- color_scheme - Color scheme (default: default)
4040- default_view - Default view mode (default: list)
4141- default_priority - Default task priority
4242- editor - Preferred text editor
4343- articles_dir - Articles storage directory
4444- notes_dir - Notes storage directory
4545- auto_archive - Auto-archive completed items (true/false)
4646- sync_enabled - Enable synchronization (true/false)
4747- sync_endpoint - Synchronization endpoint URL
4848- sync_token - Synchronization token
4949- export_format - Default export format (default: json)
5050- movie_api_key - API key for movie database
5151- book_api_key - API key for book database
5252-5353-**Usage:**
5454-5555-```bash
5656-noteleaf config set <key> <value>
5757-```
5858-5959-#### path
6060-6161-Display the path to the configuration file being used.
6262-6363-**Usage:**
6464-6565-```bash
6666-noteleaf config path
6767-```
6868-6969-#### reset
7070-7171-Reset all configuration values to their defaults.
7272-7373-**Usage:**
7474-7575-```bash
7676-noteleaf config reset
7777-```
7878-
-37
website/docs/manual/index.md
···11----
22-id: index
33-title: CLI Reference
44-sidebar_label: Overview
55-sidebar_position: 0
66-description: Complete command-line reference for noteleaf
77----
88-99-# noteleaf CLI Reference
1010-1111-noteleaf - personal information manager for the command line
1212-1313-A comprehensive CLI tool for managing tasks, notes, articles, and media queues.
1414-Inspired by TaskWarrior, noteleaf combines todo management with reading lists,
1515-watch queues, and a personal knowledge base.
1616-1717-Core features include hierarchical tasks with dependencies, recurring tasks,
1818-time tracking, markdown notes with tags, article archiving, and media queue
1919-management for books, movies, and TV shows.
2020-2121-## Usage
2222-2323-```bash
2424-noteleaf
2525-```
2626-2727-## Command Groups
2828-2929-- **[Task Management](tasks)** - Manage todos, projects, and time tracking
3030-- **[Notes](notes)** - Create and organize markdown notes
3131-- **[Articles](articles)** - Save and archive web articles
3232-- **[Books](books)** - Track reading list and progress
3333-- **[Movies](movies)** - Manage movie watch queue
3434-- **[TV Shows](tv-shows)** - Track TV show watching
3535-- **[Configuration](configuration)** - Manage settings
3636-- **[Management](management)** - Application management
3737-
-61
website/docs/manual/management.md
···11----
22-id: management
33-title: Management
44-sidebar_position: 8
55-description: Application management commands
66----
77-88-## status
99-1010-Display comprehensive application status information.
1111-1212-Shows database location, configuration file path, data directories, and current
1313-settings. Use this command to verify your noteleaf installation and diagnose
1414-configuration issues.
1515-1616-```bash
1717-noteleaf status
1818-```
1919-2020-## setup
2121-2222-Initialize noteleaf for first use.
2323-2424-Creates the database, configuration file, and required data directories. Run
2525-this command after installing noteleaf or when setting up a new environment.
2626-Safe to run multiple times as it will skip existing resources.
2727-2828-```bash
2929-noteleaf setup
3030-```
3131-3232-### Subcommands
3333-3434-#### seed
3535-3636-Add sample tasks, books, and notes to the database for testing and demonstration purposes
3737-3838-**Usage:**
3939-4040-```bash
4141-noteleaf setup seed [flags]
4242-```
4343-4444-**Options:**
4545-4646-```
4747- -f, --force Clear existing data and re-seed
4848-```
4949-5050-## reset
5151-5252-Remove all application data and return to initial state.
5353-5454-This command deletes the database, all media files, notes, and articles. The
5555-configuration file is preserved. Use with caution as this operation cannot be
5656-undone. You will be prompted for confirmation before deletion proceeds.
5757-5858-```bash
5959-noteleaf reset
6060-```
6161-
-77
website/docs/manual/movies.md
···11----
22-id: movies
33-title: Movies
44-sidebar_position: 5
55-description: Track movies in watch queue
66----
77-88-## movie
99-1010-Track movies you want to watch.
1111-1212-Search TMDB for movies and add them to your queue. Mark movies as watched when
1313-completed. Maintains a history of your movie watching activity.
1414-1515-```bash
1616-noteleaf media movie
1717-```
1818-1919-### Subcommands
2020-2121-#### add
2222-2323-Search for movies and add them to your watch queue.
2424-2525-By default, shows search results in a simple list format where you can select by number.
2626-Use the -i flag for an interactive interface with navigation keys.
2727-2828-**Usage:**
2929-3030-```bash
3131-noteleaf media movie add [search query...] [flags]
3232-```
3333-3434-**Options:**
3535-3636-```
3737- -i, --interactive Use interactive interface for movie selection
3838-```
3939-4040-#### list
4141-4242-Display movies in your queue with optional status filters.
4343-4444-Shows movie titles, release years, and current status. Filter by --all to show
4545-everything, --watched for completed movies, or --queued for unwatched items.
4646-Default shows queued movies only.
4747-4848-**Usage:**
4949-5050-```bash
5151-noteleaf media movie list [--all|--watched|--queued]
5252-```
5353-5454-#### watched
5555-5656-Mark a movie as watched with current timestamp. Moves the movie from queued to watched status.
5757-5858-**Usage:**
5959-6060-```bash
6161-noteleaf media movie watched [id]
6262-```
6363-6464-**Aliases:** seen
6565-6666-#### remove
6767-6868-Remove a movie from your watch queue. Use this for movies you no longer want to track.
6969-7070-**Usage:**
7171-7272-```bash
7373-noteleaf media movie remove [id]
7474-```
7575-7676-**Aliases:** rm
7777-
-114
website/docs/manual/notes.md
···11----
22-id: notes
33-title: Notes
44-sidebar_position: 2
55-description: Create and organize markdown notes
66----
77-88-## note
99-1010-Create and organize markdown notes with tags.
1111-1212-Write notes in markdown format, organize them with tags, browse them in an
1313-interactive TUI, and edit them in your preferred editor. Notes are stored as
1414-files on disk with metadata tracked in the database.
1515-1616-```bash
1717-noteleaf note
1818-```
1919-2020-### Subcommands
2121-2222-#### create
2323-2424-Create a new markdown note.
2525-2626-Provide a title and optional content inline, or use --interactive to open an
2727-editor. Use --file to import content from an existing markdown file. Notes
2828-support tags for organization and full-text search.
2929-3030-Examples:
3131- noteleaf note create "Meeting notes" "Discussed project timeline"
3232- noteleaf note create -i
3333- noteleaf note create --file ~/documents/draft.md
3434-3535-**Usage:**
3636-3737-```bash
3838-noteleaf note create [title] [content...] [flags]
3939-```
4040-4141-**Options:**
4242-4343-```
4444- -e, --editor Prompt to open note in editor after creation
4545- -f, --file string Create note from markdown file
4646- -i, --interactive Open interactive editor
4747-```
4848-4949-**Aliases:** new
5050-5151-#### list
5252-5353-Opens interactive TUI browser for navigating and viewing notes
5454-5555-**Usage:**
5656-5757-```bash
5858-noteleaf note list [--archived] [--static] [--tags=tag1,tag2] [flags]
5959-```
6060-6161-**Options:**
6262-6363-```
6464- -a, --archived Show archived notes
6565- -s, --static Show static list instead of interactive TUI
6666- --tags string Filter by tags (comma-separated)
6767-```
6868-6969-**Aliases:** ls
7070-7171-#### read
7272-7373-Display note content with formatted markdown rendering.
7474-7575-Shows the note with syntax highlighting, proper formatting, and metadata.
7676-Useful for quick viewing without opening an editor.
7777-7878-**Usage:**
7979-8080-```bash
8181-noteleaf note read [note-id]
8282-```
8383-8484-**Aliases:** view
8585-8686-#### edit
8787-8888-Open note in your configured text editor.
8989-9090-Uses the editor specified in your noteleaf configuration or the EDITOR
9191-environment variable. Changes are automatically saved when you close the
9292-editor.
9393-9494-**Usage:**
9595-9696-```bash
9797-noteleaf note edit [note-id]
9898-```
9999-100100-#### remove
101101-102102-Delete a note permanently.
103103-104104-Removes both the markdown file and database metadata. This operation cannot be
105105-undone. You will be prompted for confirmation before deletion.
106106-107107-**Usage:**
108108-109109-```bash
110110-noteleaf note remove [note-id]
111111-```
112112-113113-**Aliases:** rm, delete, del
114114-
-861
website/docs/manual/tasks.md
···11----
22-id: task-management
33-title: Task Management
44-sidebar_position: 1
55-description: Manage tasks with TaskWarrior-inspired features
66----
77-88-## todo
99-1010-Manage tasks with TaskWarrior-inspired features.
1111-1212-Track todos with priorities, projects, contexts, and tags. Supports hierarchical
1313-tasks with parent/child relationships, task dependencies, recurring tasks, and
1414-time tracking. Tasks can be filtered by status, priority, project, or context.
1515-1616-```bash
1717-noteleaf todo
1818-```
1919-2020-### Subcommands
2121-2222-#### add
2323-2424-Create a new task with description and optional attributes.
2525-2626-Tasks can be created with priority levels (low, medium, high, urgent), assigned
2727-to projects and contexts, tagged for organization, and configured with due dates
2828-and recurrence rules. Dependencies can be established to ensure tasks are
2929-completed in order.
3030-3131-Examples:
3232- noteleaf todo add "Write documentation" --priority high --project docs
3333- noteleaf todo add "Weekly review" --recur "FREQ=WEEKLY" --due 2024-01-15
3434-3535-**Usage:**
3636-3737-```bash
3838-noteleaf todo add [description] [flags]
3939-```
4040-4141-**Options:**
4242-4343-```
4444- -c, --context string Set task context
4545- --depends-on string Set task dependencies (comma-separated UUIDs)
4646- -d, --due string Set due date (YYYY-MM-DD)
4747- --parent string Set parent task UUID
4848- -p, --priority string Set task priority
4949- --project string Set task project
5050- --recur string Set recurrence rule (e.g., FREQ=DAILY)
5151- -t, --tags strings Add tags to task
5252- --until string Set recurrence end date (YYYY-MM-DD)
5353-```
5454-5555-**Aliases:** create, new
5656-5757-#### list
5858-5959-List tasks with optional filtering and display modes.
6060-6161-By default, shows tasks in an interactive TaskWarrior-like interface.
6262-Use --static to show a simple text list instead.
6363-Use --all to show all tasks, otherwise only pending tasks are shown.
6464-6565-**Usage:**
6666-6767-```bash
6868-noteleaf todo list [flags]
6969-```
7070-7171-**Options:**
7272-7373-```
7474- -a, --all Show all tasks (default: pending only)
7575- --context string Filter by context
7676- -i, --interactive Force interactive mode (default)
7777- --priority string Filter by priority
7878- --project string Filter by project
7979- --static Use static text output instead of interactive
8080- --status string Filter by status
8181-```
8282-8383-**Aliases:** ls
8484-8585-#### view
8686-8787-Display detailed information for a specific task.
8888-8989-Shows all task attributes including description, status, priority, project,
9090-context, tags, due date, creation time, and modification history. Use --json
9191-for machine-readable output or --no-metadata to show only the description.
9292-9393-**Usage:**
9494-9595-```bash
9696-noteleaf todo view [task-id] [flags]
9797-```
9898-9999-**Options:**
100100-101101-```
102102- --format string Output format (detailed, brief) (default "detailed")
103103- --json Output as JSON
104104- --no-metadata Hide creation/modification timestamps
105105-```
106106-107107-#### update
108108-109109-Modify attributes of an existing task.
110110-111111-Update any task property including description, status, priority, project,
112112-context, due date, recurrence rule, or parent task. Add or remove tags and
113113-dependencies. Multiple attributes can be updated in a single command.
114114-115115-Examples:
116116- noteleaf todo update 123 --priority urgent --due tomorrow
117117- noteleaf todo update 456 --add-tag urgent --project website
118118-119119-**Usage:**
120120-121121-```bash
122122-noteleaf todo update [task-id] [flags]
123123-```
124124-125125-**Options:**
126126-127127-```
128128- --add-depends string Add task dependencies (comma-separated UUIDs)
129129- --add-tag strings Add tags to task
130130- -c, --context string Set task context
131131- --description string Update task description
132132- -d, --due string Set due date (YYYY-MM-DD)
133133- --parent string Set parent task UUID
134134- -p, --priority string Set task priority
135135- --project string Set task project
136136- --recur string Set recurrence rule (e.g., FREQ=DAILY)
137137- --remove-depends string Remove task dependencies (comma-separated UUIDs)
138138- --remove-tag strings Remove tags from task
139139- --status string Update task status
140140- -t, --tags strings Add tags to task
141141- --until string Set recurrence end date (YYYY-MM-DD)
142142-```
143143-144144-#### edit
145145-146146-Open interactive editor for task modification.
147147-148148-Provides a user-friendly interface with status picker and priority toggle.
149149-Easier than using multiple command-line flags for complex updates.
150150-151151-**Usage:**
152152-153153-```bash
154154-noteleaf todo edit [task-id]
155155-```
156156-157157-**Aliases:** e
158158-159159-#### delete
160160-161161-Permanently remove a task from the database.
162162-163163-This operation cannot be undone. Consider updating the task status to
164164-'deleted' instead if you want to preserve the record for historical purposes.
165165-166166-**Usage:**
167167-168168-```bash
169169-noteleaf todo delete [task-id]
170170-```
171171-172172-#### projects
173173-174174-Display all projects with task counts.
175175-176176-Shows each project used in your tasks along with the number of tasks in each
177177-project. Use --todo-txt to format output with +project syntax for compatibility
178178-with todo.txt tools.
179179-180180-**Usage:**
181181-182182-```bash
183183-noteleaf todo projects [flags]
184184-```
185185-186186-**Options:**
187187-188188-```
189189- --static Use static text output instead of interactive
190190- --todo-txt Format output with +project prefix for todo.txt compatibility
191191-```
192192-193193-**Aliases:** proj
194194-195195-#### tags
196196-197197-Display all tags used across tasks.
198198-199199-Shows each tag with the number of tasks using it. Tags provide flexible
200200-categorization orthogonal to projects and contexts.
201201-202202-**Usage:**
203203-204204-```bash
205205-noteleaf todo tags [flags]
206206-```
207207-208208-**Options:**
209209-210210-```
211211- --static Use static text output instead of interactive
212212-```
213213-214214-**Aliases:** t
215215-216216-#### contexts
217217-218218-Display all contexts with task counts.
219219-220220-Contexts represent locations or environments where tasks can be completed (e.g.,
221221-@home, @office, @errands). Use --todo-txt to format output with @context syntax
222222-for compatibility with todo.txt tools.
223223-224224-**Usage:**
225225-226226-```bash
227227-noteleaf todo contexts [flags]
228228-```
229229-230230-**Options:**
231231-232232-```
233233- --static Use static text output instead of interactive
234234- --todo-txt Format output with @context prefix for todo.txt compatibility
235235-```
236236-237237-**Aliases:** con, loc, ctx, locations
238238-239239-#### done
240240-241241-Mark a task as completed with current timestamp.
242242-243243-Sets the task status to 'completed' and records the completion time. For
244244-recurring tasks, generates the next instance based on the recurrence rule.
245245-246246-**Usage:**
247247-248248-```bash
249249-noteleaf todo done [task-id]
250250-```
251251-252252-**Aliases:** complete
253253-254254-#### start
255255-256256-Begin tracking time spent on a task.
257257-258258-Records the start time for a work session. Only one task can be actively
259259-tracked at a time. Use --note to add a description of what you're working on.
260260-261261-**Usage:**
262262-263263-```bash
264264-noteleaf todo start [task-id] [flags]
265265-```
266266-267267-**Options:**
268268-269269-```
270270- -n, --note string Add a note to the time entry
271271-```
272272-273273-#### stop
274274-275275-End time tracking for the active task.
276276-277277-Records the end time and calculates duration for the current work session.
278278-Duration is added to the task's total time tracked.
279279-280280-**Usage:**
281281-282282-```bash
283283-noteleaf todo stop [task-id]
284284-```
285285-286286-#### timesheet
287287-288288-Show time tracking summary for tasks.
289289-290290-By default shows time entries for the last 7 days.
291291-Use --task to show timesheet for a specific task.
292292-Use --days to change the date range.
293293-294294-**Usage:**
295295-296296-```bash
297297-noteleaf todo timesheet [flags]
298298-```
299299-300300-**Options:**
301301-302302-```
303303- -d, --days int Number of days to show in timesheet (default 7)
304304- -t, --task string Show timesheet for specific task ID
305305-```
306306-307307-#### recur
308308-309309-Configure recurring task patterns.
310310-311311-Create tasks that repeat on a schedule using iCalendar recurrence rules (RRULE).
312312-Supports daily, weekly, monthly, and yearly patterns with optional end dates.
313313-314314-**Usage:**
315315-316316-```bash
317317-noteleaf todo recur
318318-```
319319-320320-**Aliases:** repeat
321321-322322-##### set
323323-324324-Apply a recurrence rule to create repeating task instances.
325325-326326-Uses iCalendar RRULE syntax (e.g., "FREQ=DAILY" for daily tasks, "FREQ=WEEKLY;BYDAY=MO,WE,FR"
327327-for specific weekdays). When a recurring task is completed, the next instance is
328328-automatically generated.
329329-330330-Examples:
331331- noteleaf todo recur set 123 --rule "FREQ=DAILY"
332332- noteleaf todo recur set 456 --rule "FREQ=WEEKLY;BYDAY=MO" --until 2024-12-31
333333-334334-**Usage:**
335335-336336-```bash
337337-noteleaf todo recur set [task-id] [flags]
338338-```
339339-340340-**Options:**
341341-342342-```
343343- --rule string Recurrence rule (e.g., FREQ=DAILY)
344344- --until string Recurrence end date (YYYY-MM-DD)
345345-```
346346-347347-##### clear
348348-349349-Remove recurrence from a task.
350350-351351-Converts a recurring task to a one-time task. Existing future instances are not
352352-affected.
353353-354354-**Usage:**
355355-356356-```bash
357357-noteleaf todo recur clear [task-id]
358358-```
359359-360360-##### show
361361-362362-Display recurrence rule and schedule information.
363363-364364-Shows the RRULE pattern, next occurrence date, and recurrence end date if
365365-configured.
366366-367367-**Usage:**
368368-369369-```bash
370370-noteleaf todo recur show [task-id]
371371-```
372372-373373-#### depend
374374-375375-Create and manage task dependencies.
376376-377377-Establish relationships where one task must be completed before another can
378378-begin. Useful for multi-step workflows and project management.
379379-380380-**Usage:**
381381-382382-```bash
383383-noteleaf todo depend
384384-```
385385-386386-**Aliases:** dep, deps
387387-388388-##### add
389389-390390-Make a task dependent on another task's completion.
391391-392392-The first task cannot be started until the second task is completed. Use task
393393-UUIDs to specify dependencies.
394394-395395-**Usage:**
396396-397397-```bash
398398-noteleaf todo depend add [task-id] [depends-on-uuid]
399399-```
400400-401401-##### remove
402402-403403-Delete a dependency relationship between two tasks.
404404-405405-**Usage:**
406406-407407-```bash
408408-noteleaf todo depend remove [task-id] [depends-on-uuid]
409409-```
410410-411411-**Aliases:** rm
412412-413413-##### list
414414-415415-Show all tasks that must be completed before this task can be started.
416416-417417-**Usage:**
418418-419419-```bash
420420-noteleaf todo depend list [task-id]
421421-```
422422-423423-**Aliases:** ls
424424-425425-##### blocked-by
426426-427427-Display all tasks that depend on this task's completion.
428428-429429-**Usage:**
430430-431431-```bash
432432-noteleaf todo depend blocked-by [task-id]
433433-```
434434-435435-## todo
436436-437437-Manage tasks with TaskWarrior-inspired features.
438438-439439-Track todos with priorities, projects, contexts, and tags. Supports hierarchical
440440-tasks with parent/child relationships, task dependencies, recurring tasks, and
441441-time tracking. Tasks can be filtered by status, priority, project, or context.
442442-443443-```bash
444444-noteleaf todo
445445-```
446446-447447-### Subcommands
448448-449449-#### add
450450-451451-Create a new task with description and optional attributes.
452452-453453-Tasks can be created with priority levels (low, medium, high, urgent), assigned
454454-to projects and contexts, tagged for organization, and configured with due dates
455455-and recurrence rules. Dependencies can be established to ensure tasks are
456456-completed in order.
457457-458458-Examples:
459459- noteleaf todo add "Write documentation" --priority high --project docs
460460- noteleaf todo add "Weekly review" --recur "FREQ=WEEKLY" --due 2024-01-15
461461-462462-**Usage:**
463463-464464-```bash
465465-noteleaf todo add [description] [flags]
466466-```
467467-468468-**Options:**
469469-470470-```
471471- -c, --context string Set task context
472472- --depends-on string Set task dependencies (comma-separated UUIDs)
473473- -d, --due string Set due date (YYYY-MM-DD)
474474- --parent string Set parent task UUID
475475- -p, --priority string Set task priority
476476- --project string Set task project
477477- --recur string Set recurrence rule (e.g., FREQ=DAILY)
478478- -t, --tags strings Add tags to task
479479- --until string Set recurrence end date (YYYY-MM-DD)
480480-```
481481-482482-**Aliases:** create, new
483483-484484-#### list
485485-486486-List tasks with optional filtering and display modes.
487487-488488-By default, shows tasks in an interactive TaskWarrior-like interface.
489489-Use --static to show a simple text list instead.
490490-Use --all to show all tasks, otherwise only pending tasks are shown.
491491-492492-**Usage:**
493493-494494-```bash
495495-noteleaf todo list [flags]
496496-```
497497-498498-**Options:**
499499-500500-```
501501- -a, --all Show all tasks (default: pending only)
502502- --context string Filter by context
503503- -i, --interactive Force interactive mode (default)
504504- --priority string Filter by priority
505505- --project string Filter by project
506506- --static Use static text output instead of interactive
507507- --status string Filter by status
508508-```
509509-510510-**Aliases:** ls
511511-512512-#### view
513513-514514-Display detailed information for a specific task.
515515-516516-Shows all task attributes including description, status, priority, project,
517517-context, tags, due date, creation time, and modification history. Use --json
518518-for machine-readable output or --no-metadata to show only the description.
519519-520520-**Usage:**
521521-522522-```bash
523523-noteleaf todo view [task-id] [flags]
524524-```
525525-526526-**Options:**
527527-528528-```
529529- --format string Output format (detailed, brief) (default "detailed")
530530- --json Output as JSON
531531- --no-metadata Hide creation/modification timestamps
532532-```
533533-534534-#### update
535535-536536-Modify attributes of an existing task.
537537-538538-Update any task property including description, status, priority, project,
539539-context, due date, recurrence rule, or parent task. Add or remove tags and
540540-dependencies. Multiple attributes can be updated in a single command.
541541-542542-Examples:
543543- noteleaf todo update 123 --priority urgent --due tomorrow
544544- noteleaf todo update 456 --add-tag urgent --project website
545545-546546-**Usage:**
547547-548548-```bash
549549-noteleaf todo update [task-id] [flags]
550550-```
551551-552552-**Options:**
553553-554554-```
555555- --add-depends string Add task dependencies (comma-separated UUIDs)
556556- --add-tag strings Add tags to task
557557- -c, --context string Set task context
558558- --description string Update task description
559559- -d, --due string Set due date (YYYY-MM-DD)
560560- --parent string Set parent task UUID
561561- -p, --priority string Set task priority
562562- --project string Set task project
563563- --recur string Set recurrence rule (e.g., FREQ=DAILY)
564564- --remove-depends string Remove task dependencies (comma-separated UUIDs)
565565- --remove-tag strings Remove tags from task
566566- --status string Update task status
567567- -t, --tags strings Add tags to task
568568- --until string Set recurrence end date (YYYY-MM-DD)
569569-```
570570-571571-#### edit
572572-573573-Open interactive editor for task modification.
574574-575575-Provides a user-friendly interface with status picker and priority toggle.
576576-Easier than using multiple command-line flags for complex updates.
577577-578578-**Usage:**
579579-580580-```bash
581581-noteleaf todo edit [task-id]
582582-```
583583-584584-**Aliases:** e
585585-586586-#### delete
587587-588588-Permanently remove a task from the database.
589589-590590-This operation cannot be undone. Consider updating the task status to
591591-'deleted' instead if you want to preserve the record for historical purposes.
592592-593593-**Usage:**
594594-595595-```bash
596596-noteleaf todo delete [task-id]
597597-```
598598-599599-#### projects
600600-601601-Display all projects with task counts.
602602-603603-Shows each project used in your tasks along with the number of tasks in each
604604-project. Use --todo-txt to format output with +project syntax for compatibility
605605-with todo.txt tools.
606606-607607-**Usage:**
608608-609609-```bash
610610-noteleaf todo projects [flags]
611611-```
612612-613613-**Options:**
614614-615615-```
616616- --static Use static text output instead of interactive
617617- --todo-txt Format output with +project prefix for todo.txt compatibility
618618-```
619619-620620-**Aliases:** proj
621621-622622-#### tags
623623-624624-Display all tags used across tasks.
625625-626626-Shows each tag with the number of tasks using it. Tags provide flexible
627627-categorization orthogonal to projects and contexts.
628628-629629-**Usage:**
630630-631631-```bash
632632-noteleaf todo tags [flags]
633633-```
634634-635635-**Options:**
636636-637637-```
638638- --static Use static text output instead of interactive
639639-```
640640-641641-**Aliases:** t
642642-643643-#### contexts
644644-645645-Display all contexts with task counts.
646646-647647-Contexts represent locations or environments where tasks can be completed (e.g.,
648648-@home, @office, @errands). Use --todo-txt to format output with @context syntax
649649-for compatibility with todo.txt tools.
650650-651651-**Usage:**
652652-653653-```bash
654654-noteleaf todo contexts [flags]
655655-```
656656-657657-**Options:**
658658-659659-```
660660- --static Use static text output instead of interactive
661661- --todo-txt Format output with @context prefix for todo.txt compatibility
662662-```
663663-664664-**Aliases:** con, loc, ctx, locations
665665-666666-#### done
667667-668668-Mark a task as completed with current timestamp.
669669-670670-Sets the task status to 'completed' and records the completion time. For
671671-recurring tasks, generates the next instance based on the recurrence rule.
672672-673673-**Usage:**
674674-675675-```bash
676676-noteleaf todo done [task-id]
677677-```
678678-679679-**Aliases:** complete
680680-681681-#### start
682682-683683-Begin tracking time spent on a task.
684684-685685-Records the start time for a work session. Only one task can be actively
686686-tracked at a time. Use --note to add a description of what you're working on.
687687-688688-**Usage:**
689689-690690-```bash
691691-noteleaf todo start [task-id] [flags]
692692-```
693693-694694-**Options:**
695695-696696-```
697697- -n, --note string Add a note to the time entry
698698-```
699699-700700-#### stop
701701-702702-End time tracking for the active task.
703703-704704-Records the end time and calculates duration for the current work session.
705705-Duration is added to the task's total time tracked.
706706-707707-**Usage:**
708708-709709-```bash
710710-noteleaf todo stop [task-id]
711711-```
712712-713713-#### timesheet
714714-715715-Show time tracking summary for tasks.
716716-717717-By default shows time entries for the last 7 days.
718718-Use --task to show timesheet for a specific task.
719719-Use --days to change the date range.
720720-721721-**Usage:**
722722-723723-```bash
724724-noteleaf todo timesheet [flags]
725725-```
726726-727727-**Options:**
728728-729729-```
730730- -d, --days int Number of days to show in timesheet (default 7)
731731- -t, --task string Show timesheet for specific task ID
732732-```
733733-734734-#### recur
735735-736736-Configure recurring task patterns.
737737-738738-Create tasks that repeat on a schedule using iCalendar recurrence rules (RRULE).
739739-Supports daily, weekly, monthly, and yearly patterns with optional end dates.
740740-741741-**Usage:**
742742-743743-```bash
744744-noteleaf todo recur
745745-```
746746-747747-**Aliases:** repeat
748748-749749-##### set
750750-751751-Apply a recurrence rule to create repeating task instances.
752752-753753-Uses iCalendar RRULE syntax (e.g., "FREQ=DAILY" for daily tasks, "FREQ=WEEKLY;BYDAY=MO,WE,FR"
754754-for specific weekdays). When a recurring task is completed, the next instance is
755755-automatically generated.
756756-757757-Examples:
758758- noteleaf todo recur set 123 --rule "FREQ=DAILY"
759759- noteleaf todo recur set 456 --rule "FREQ=WEEKLY;BYDAY=MO" --until 2024-12-31
760760-761761-**Usage:**
762762-763763-```bash
764764-noteleaf todo recur set [task-id] [flags]
765765-```
766766-767767-**Options:**
768768-769769-```
770770- --rule string Recurrence rule (e.g., FREQ=DAILY)
771771- --until string Recurrence end date (YYYY-MM-DD)
772772-```
773773-774774-##### clear
775775-776776-Remove recurrence from a task.
777777-778778-Converts a recurring task to a one-time task. Existing future instances are not
779779-affected.
780780-781781-**Usage:**
782782-783783-```bash
784784-noteleaf todo recur clear [task-id]
785785-```
786786-787787-##### show
788788-789789-Display recurrence rule and schedule information.
790790-791791-Shows the RRULE pattern, next occurrence date, and recurrence end date if
792792-configured.
793793-794794-**Usage:**
795795-796796-```bash
797797-noteleaf todo recur show [task-id]
798798-```
799799-800800-#### depend
801801-802802-Create and manage task dependencies.
803803-804804-Establish relationships where one task must be completed before another can
805805-begin. Useful for multi-step workflows and project management.
806806-807807-**Usage:**
808808-809809-```bash
810810-noteleaf todo depend
811811-```
812812-813813-**Aliases:** dep, deps
814814-815815-##### add
816816-817817-Make a task dependent on another task's completion.
818818-819819-The first task cannot be started until the second task is completed. Use task
820820-UUIDs to specify dependencies.
821821-822822-**Usage:**
823823-824824-```bash
825825-noteleaf todo depend add [task-id] [depends-on-uuid]
826826-```
827827-828828-##### remove
829829-830830-Delete a dependency relationship between two tasks.
831831-832832-**Usage:**
833833-834834-```bash
835835-noteleaf todo depend remove [task-id] [depends-on-uuid]
836836-```
837837-838838-**Aliases:** rm
839839-840840-##### list
841841-842842-Show all tasks that must be completed before this task can be started.
843843-844844-**Usage:**
845845-846846-```bash
847847-noteleaf todo depend list [task-id]
848848-```
849849-850850-**Aliases:** ls
851851-852852-##### blocked-by
853853-854854-Display all tasks that depend on this task's completion.
855855-856856-**Usage:**
857857-858858-```bash
859859-noteleaf todo depend blocked-by [task-id]
860860-```
861861-
-91
website/docs/manual/tv-shows.md
···11----
22-id: tv-shows
33-title: TV Shows
44-sidebar_position: 6
55-description: Manage TV show watching
66----
77-88-## tv
99-1010-Track TV shows and episodes.
1111-1212-Search TMDB for TV shows and add them to your queue. Track which shows you're
1313-currently watching, mark episodes as watched, and maintain a complete history
1414-of your viewing activity.
1515-1616-```bash
1717-noteleaf media tv
1818-```
1919-2020-### Subcommands
2121-2222-#### add
2323-2424-Search for TV shows and add them to your watch queue.
2525-2626-By default, shows search results in a simple list format where you can select by number.
2727-Use the -i flag for an interactive interface with navigation keys.
2828-2929-**Usage:**
3030-3131-```bash
3232-noteleaf media tv add [search query...] [flags]
3333-```
3434-3535-**Options:**
3636-3737-```
3838- -i, --interactive Use interactive interface for TV show selection
3939-```
4040-4141-#### list
4242-4343-Display TV shows in your queue with optional status filters.
4444-4545-Shows show titles, air dates, and current status. Filter by --all, --queued,
4646---watching for shows in progress, or --watched for completed series. Default
4747-shows queued shows only.
4848-4949-**Usage:**
5050-5151-```bash
5252-noteleaf media tv list [--all|--queued|--watching|--watched]
5353-```
5454-5555-#### watching
5656-5757-Mark a TV show as currently watching. Use this when you start watching a series.
5858-5959-**Usage:**
6060-6161-```bash
6262-noteleaf media tv watching [id]
6363-```
6464-6565-#### watched
6666-6767-Mark TV show episodes or entire series as watched.
6868-6969-Updates episode tracking and completion status. Can mark individual episodes
7070-or complete seasons/series depending on ID format.
7171-7272-**Usage:**
7373-7474-```bash
7575-noteleaf media tv watched [id]
7676-```
7777-7878-**Aliases:** seen
7979-8080-#### remove
8181-8282-Remove a TV show from your watch queue. Use this for shows you no longer want to track.
8383-8484-**Usage:**
8585-8686-```bash
8787-noteleaf media tv remove [id]
8888-```
8989-9090-**Aliases:** rm
9191-
+9
website/docs/media/_category_.json
···11+{
22+ "label": "Media",
33+ "position": 5,
44+ "link": {
55+ "type": "generated-index",
66+ "title": "Media Tracking",
77+ "description": "Track books, movies, and TV shows without leaving the terminal."
88+ }
99+}
+100
website/docs/media/books.md
···11+---
22+title: Books
33+sidebar_label: Books
44+description: Build and maintain your reading list with Open Library metadata.
55+sidebar_position: 2
66+---
77+88+# Books
99+1010+The book workflow revolves around Open Library search results. Each command lives under `noteleaf media book`.
1111+1212+## Add Books
1313+1414+Search Open Library and pick a result:
1515+1616+```sh
1717+noteleaf media book add "Project Hail Mary"
1818+```
1919+2020+Flags:
2121+2222+- `-i, --interactive`: open the TUI browser (currently shows your local listโuseful for triage).
2323+- Plain mode prints the top five matches inline and prompts for a numeric selection.
2424+2525+Behind the scenes Noteleaf records the title, authors, edition details, and any subjects returned by the API. New entries start in the `queued` status.
2626+2727+## Manage the Reading List
2828+2929+List and filter:
3030+3131+```sh
3232+# Everything
3333+noteleaf media book list --all
3434+3535+# Only active reads
3636+noteleaf media book list --reading
3737+3838+# Completed books
3939+noteleaf media book list --finished
4040+```
4141+4242+Each line shows the ID, title, author, status, progress percentage, and any captured metadata (publishers, edition counts, etc.).
4343+4444+Remove items you no longer care about:
4545+4646+```sh
4747+noteleaf media book remove 42
4848+```
4949+5050+## Track Progress
5151+5252+You can explicitly set the status:
5353+5454+```sh
5555+noteleaf media book reading 7
5656+noteleaf media book finished 7
5757+noteleaf media book update 7 queued
5858+```
5959+6060+But the fastest way is to update the percentage:
6161+6262+```sh
6363+noteleaf media book progress 7 45 # Moves status to reading and records start time
6464+noteleaf media book progress 7 100 # Marks finished and records completion time
6565+```
6666+6767+Logic applied automatically:
6868+6969+- `0%` โ resets to `queued` and clears the โstartedโ timestamp.
7070+- `1โ99%` โ flips to `reading` (start time captured).
7171+- `100%` โ marks `finished`, sets end time, and locks progress at 100%.
7272+7373+## Reading Lists and Search
7474+7575+Common workflows:
7676+7777+- **Focus view**: `noteleaf media book list --reading | fzf` to pick the next session book.
7878+- **Backlog grooming**: `noteleaf media book list --queued` to prune items before they go stale.
7979+- **Author sprint**: pipe the list to `rg` to filter by author (`noteleaf media book list --all | rg "Le Guin"`).
8080+8181+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.
8282+8383+## Metadata and Notes
8484+8585+Each record stores:
8686+8787+- Title & authors (comma separated when multiple).
8888+- Edition count, publishers, subject tags, or cover IDs exposed as inline notes.
8989+- Added/started/finished timestamps.
9090+- Optional page count (if Open Library exposes it).
9191+9292+Use those IDs anywhere else (tasks or notes). Example note snippet:
9393+9494+```markdown
9595+## Reading Log
9696+- 2024-02-01 โ Started book #7 ("Project Hail Mary")
9797+- 2024-02-05 โ Captured ideas in note #128 linked back to the book.
9898+```
9999+100100+Because media lives in the same database as tasks and notes, full-text search will surface those references instantly.
+75
website/docs/media/movies.md
···11+---
22+title: Movies
33+sidebar_label: Movies
44+description: Keep track of your movie queue with Rotten Tomatoes metadata.
55+sidebar_position: 3
66+---
77+88+# Movies
99+1010+Movie commands hang off `noteleaf media movie`. Results use Rotten Tomatoes search so you get consistent titles plus critic scores.
1111+1212+## Add Movies
1313+1414+```sh
1515+noteleaf media movie add "The Matrix"
1616+```
1717+1818+What happens:
1919+2020+1. The CLI fetches the first five Rotten Tomatoes matches.
2121+2. You select the right one by number.
2222+3. The chosen movie is inserted into the local queue with status `queued`.
2323+2424+The `-i/--interactive` flag is reserved for a future selector; currently the inline prompt is the quickest path.
2525+2626+## List and Filter
2727+2828+```sh
2929+# Default: queued items only
3030+noteleaf media movie list
3131+3232+# Include everything
3333+noteleaf media movie list --all
3434+3535+# Review history
3636+noteleaf media movie list --watched
3737+```
3838+3939+Each entry shows:
4040+4141+- `ID` and title.
4242+- Release year (if Rotten Tomatoes provided one).
4343+- Status (`queued` or `watched`).
4444+- Critic score snippet (stored inside the Notes column).
4545+- Watched timestamp for completed items.
4646+4747+## Mark Movies as Watched
4848+4949+```sh
5050+noteleaf media movie watched 12
5151+```
5252+5353+The command sets the status to `watched` and records `watched_at` using the current timestamp. Removing an item uses the same ID:
5454+5555+```sh
5656+noteleaf media movie remove 12
5757+```
5858+5959+Use removal for titles you abandoned or added by mistakeโthe CLI deletes the database entry so your queue stays focused.
6060+6161+## Metadata Cheat Sheet
6262+6363+- **Notes field**: includes critic score, whether Rotten Tomatoes marked it โCertified Fresh,โ and the canonical URL.
6464+- **Rating column**: reserved for future personal ratings; right now it mirrors the upstream critic context.
6565+- **Timestamps**: `added` when you saved it, `watched` when you complete it.
6666+6767+To keep a running diary, drop the IDs into a note:
6868+6969+```markdown
7070+### Queue Ideas
7171+- Movie #31 โ Watch before sequel comes out
7272+- Movie #12 โ Pair with article #5 for cyberpunk research
7373+```
7474+7575+This keeps everything searchable without having to leave the terminal.
+74
website/docs/media/organization.md
···11+---
22+title: Media Organization
33+sidebar_label: Organization
44+description: Keep queues manageable with filters, reviews, and note links.
55+sidebar_position: 5
66+---
77+88+# Media Organization
99+1010+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.
1111+1212+## Tags and Categories
1313+1414+Dedicated media tags have not shipped yet. Until they do:
1515+1616+- Use the free-form `Notes` column (populated automatically from Open Library or Rotten Tomatoes) to stash keywords such as โHugo shortlistโ or โDocumentaryโ.
1717+- When you need stricter structure, create a note that tracks an ad-hoc category and reference media IDs inside it:
1818+1919+```markdown
2020+## Cozy backlog
2121+- Book #11 โ comfort reread
2222+- Movie #25 โ rainy-day pick
2323+```
2424+2525+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.
2626+2727+## Custom Lists
2828+2929+You already get status-based filters out of the box:
3030+3131+```sh
3232+noteleaf media book list --reading
3333+noteleaf media movie list --watched
3434+noteleaf media tv list --all | rg "FX" # filter with ripgrep
3535+```
3636+3737+For more bespoke dashboards:
3838+3939+1. Use `noteleaf status` to grab the SQLite path.
4040+2. Query it with tools like `sqlite-utils` or `datasette` to build spreadsheets or dashboards.
4141+3. Export subsets via `sqlite3 noteleaf.db "SELECT * FROM books WHERE status='reading'" > reading.csv`.
4242+4343+That approach keeps the CLI fast while still letting you slice the data any way you need.
4444+4545+## Ratings and Reviews
4646+4747+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.
4848+4949+Until then, keep reviews as regular notes:
5050+5151+```sh
5252+noteleaf note create "Thoughts on Book #7"
5353+```
5454+5555+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.
5656+5757+## Linking Media to Notes
5858+5959+There is no special โlinkโ command yet, but the following pattern works well:
6060+6161+1. Create a dedicated note per book/movie/show (or per collection).
6262+2. Add a heading with the media ID and paste the generated markdown path from `noteleaf article view` or the queue list.
6363+3. Optionally embed checklists or quotes gathered while reading/watching.
6464+6565+Example snippet:
6666+6767+```markdown
6868+### Book #7 โ Project Hail Mary
6969+- Status: reading (45%)
7070+- Tasks: todo #128 covers the experiment described in chapter 12
7171+- Next action: finish Part II before Friday
7272+```
7373+7474+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.
+53
website/docs/media/overview.md
···11+---
22+title: Media Overview
33+sidebar_label: Overview
44+description: Manage reading lists and watch queues from the CLI.
55+sidebar_position: 1
66+---
77+88+# Media Tracking Overview
99+1010+Noteleaf keeps book, movie, and TV data next to your tasks and notes so you do not need a separate โwatch listโ app.
1111+All media commands hang off a single entry point:
1212+1313+```sh
1414+noteleaf media <book|movie|tv> <subcommand>
1515+```
1616+1717+- **Books** pull metadata from the Open Library API.
1818+- **Movies/TV** scrape Rotten Tomatoes search results to capture critic scores and canonical titles.
1919+- 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).
2020+2121+## Lifecycle Statuses
2222+2323+| Type | Statuses | Notes |
2424+| ------ | ------------------------------------------ | ------------------------------------------------------------------------------------------------- |
2525+| Books | `queued`, `reading`, `finished`, `removed` | Progress updates automatically bump status (0% โ `queued`, 1-99% โ `reading`, 100% โ `finished`). |
2626+| Movies | `queued`, `watched`, `removed` | Marking as watched stores the completion timestamp. |
2727+| TV | `queued`, `watching`, `watched`, `removed` | Watching/watched commands also record the last watched time. |
2828+2929+Statuses control list filtering and show up beside each item in the TUI.
3030+3131+## Metadata That Gets Saved
3232+3333+- **Books**: title, authors, Open Library notes (editions, publishers, subjects), started/finished timestamps, progress percentage.
3434+- **Movies**: release year when available, Rotten Tomatoes critic score details inside the notes field, watched timestamp.
3535+- **TV**: show title plus critic score details, optional season/episode numbers, last watched timestamp.
3636+3737+You can safely edit the generated markdown/notes in your favorite editorโthe records keep pointing to the updated files.
3838+3939+## Interactive vs Static Workflows
4040+4141+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:
4242+4343+- `j/k` or arrow keys move between entries.
4444+- `/` starts search across titles, authors, and metadata.
4545+- `v` opens a focused preview.
4646+- `?` shows all shortcuts.
4747+4848+If you prefer scripts, combine the static lists with tools like `rg` or `jq`.
4949+5050+## Storage Layout
5151+5252+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.
5353+Use `noteleaf status` to see the exact paths for your database, data directory, and configuration file.
+64
website/docs/media/tv.md
···11+---
22+title: TV Shows
33+sidebar_label: TV Shows
44+description: Track long-form series with simple queue management.
55+sidebar_position: 4
66+---
77+88+# TV Shows
99+1010+TV commands live under `noteleaf media tv`. Like movies, they use Rotten Tomatoes search so you can trust the spelling and canonical links.
1111+1212+## Add Shows
1313+1414+```sh
1515+noteleaf media tv add "Breaking Bad"
1616+```
1717+1818+- Inline mode shows up to five matches and asks you to choose.
1919+- `-i/--interactive` is wired up for the future list selector.
2020+2121+Every new show starts as `queued`.
2222+2323+## List the Queue
2424+2525+```sh
2626+noteleaf media tv list # queued shows
2727+noteleaf media tv list --watching # in-progress series
2828+noteleaf media tv list --watched # finished shows
2929+noteleaf media tv list --all # everything
3030+```
3131+3232+Output includes the ID, title, optional season/episode numbers (once those fields are set), status, critic-score snippet, and timestamps.
3333+3434+## Update Status
3535+3636+Use semantic verbs instead of editing the status manually:
3737+3838+```sh
3939+noteleaf media tv watching 8 # Moved to โcurrently watchingโ
4040+noteleaf media tv watched 8 # Mark completed
4141+noteleaf media tv remove 8 # Drop from the queue entirely
4242+```
4343+4444+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:
4545+4646+```markdown
4747+### TV checklist
4848+- TV #8 โ resume Season 3 Episode 5
4949+- TV #15 โ waiting for new season announcement
5050+```
5151+5252+## Organization Tips
5353+5454+- Use `noteleaf media tv list --watching | fzf` to pick tonightโs episode.
5555+- Pipe `--all` into `rg "HBO"` to filter on the metadata snippet that contains the network/URL.
5656+- Include `TV #ID` references in your weekly review note so you can jump back with a single ID lookup.
5757+5858+## What Gets Stored
5959+6060+- Rotten Tomatoes critic info plus canonical URL (inside the Notes column).
6161+- Optional season/episode integers for future episode tracking (already part of the schema).
6262+- Added timestamps and โlast watchedโ timestamps.
6363+6464+Because shows can last months, keeping the queue short (just what you plan to watch soon) makes the `list` output far easier to scan.
···11+---
22+title: Advanced Note Features
33+sidebar_label: Advanced
44+description: Search, exports, backlinks, and automation tips.
55+sidebar_position: 5
66+---
77+88+# Advanced Note Features
99+1010+## Full-Text Search
1111+1212+While not exposed as a dedicated command, you can search note content using the database:
1313+1414+**Search with grep** (searches file content):
1515+1616+```sh
1717+grep -r "search term" ~/.local/share/noteleaf/notes/
1818+```
1919+2020+**Search titles and metadata**:
2121+2222+```sh
2323+noteleaf note list --static | grep "keyword"
2424+```
2525+2626+Future versions may include built-in full-text search with relevance ranking.
2727+2828+## Note Exports
2929+3030+Export notes to different formats using standard markdown tools:
3131+3232+**Convert to HTML with pandoc**:
3333+3434+```sh
3535+noteleaf note view 1 --format=raw | pandoc -o output.html
3636+```
3737+3838+**Convert to PDF**:
3939+4040+```sh
4141+noteleaf note view 1 --format=raw | pandoc -o output.pdf
4242+```
4343+4444+**Batch export all notes**:
4545+4646+```sh
4747+for note in ~/.local/share/noteleaf/notes/*.md; do
4848+ pandoc "$note" -o "${note%.md}.html"
4949+done
5050+```
5151+5252+## Backlinks and References
5353+5454+Manually create backlinks between notes using markdown links:
5555+5656+```markdown
5757+See also: [[Research on Authentication]] for background
5858+Related: [[API Design Principles]]
5959+```
6060+6161+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.
+57
website/docs/notes/basics.md
···11+---
22+title: Note Basics
33+sidebar_label: Basics
44+description: Creating notes, metadata, and storage model.
55+sidebar_position: 2
66+---
77+88+# Note Basics
99+1010+## Creation
1111+1212+**Quick note from command line**:
1313+1414+```sh
1515+noteleaf note create "Meeting Notes" "Discussed Q4 roadmap and hiring plans"
1616+```
1717+1818+**Interactive creation** (opens editor):
1919+2020+```sh
2121+noteleaf note create --interactive
2222+```
2323+2424+**From existing file**:
2525+2626+```sh
2727+noteleaf note create --file ~/Documents/draft.md
2828+```
2929+3030+**Create and immediately edit**:
3131+3232+```sh
3333+noteleaf note create "Research Notes" --editor
3434+```
3535+3636+## Structure
3737+3838+Notes consist of:
3939+4040+**Title**: Short descriptor shown in lists and searches. Can be updated later.
4141+4242+**Content**: Full markdown text. Supports all standard markdown features including code blocks, lists, tables, and links.
4343+4444+**Tags**: Categorization labels for organizing and filtering notes. Multiple tags per note.
4545+4646+**Dates**: Creation and modification timestamps tracked automatically.
4747+4848+**File Path**: Location of the markdown file on disk, managed by Noteleaf.
4949+5050+## Storage
5151+5252+**File Location**: Notes are stored as individual `.md` files in your notes directory (typically `~/.local/share/noteleaf/notes` or `~/Library/Application Support/noteleaf/notes`).
5353+5454+**Naming**: Files are named with a UUID to ensure uniqueness. The title is stored in the database, not the filename.
5555+5656+**Portability**: Since notes are plain markdown, you can read them with any text editor or markdown viewer.
5757+The database provides additional functionality like tagging and search, but the files remain standalone.
+28
website/docs/notes/best-practices.md
···11+---
22+title: Note Tips and Best Practices
33+sidebar_label: Best Practices
44+description: Guidelines for keeping notes useful over time.
55+sidebar_position: 8
66+---
77+88+# Note Tips and Best Practices
99+1010+**Write in plain language**: Notes are for your future self. Avoid jargon you might forget.
1111+1212+**Tag consistently**: Establish a tagging taxonomy early and stick to it. Review tags periodically with `noteleaf note tags`.
1313+1414+**Link liberally**: Reference related notes, tasks, and articles using markdown links and references.
1515+1616+**Short, focused notes**: Better to have many small notes than few giant ones. Easier to link and reuse.
1717+1818+**Regular review**: Schedule time to review notes, add tags, create links, and archive outdated content.
1919+2020+**Edit immediately**: If you notice incomplete or unclear notes, edit them now. Stale notes lose value.
2121+2222+**Use your editor**: Configure your favorite editor with markdown plugins for better syntax highlighting and live preview.
2323+2424+**Backup regularly**: While notes are files, backup both the notes directory and the database to preserve metadata.
2525+2626+**Experiment with formats**: Try different note structures (journal, zettelkasten, topic-based) to find what works for you.
2727+2828+For CLI command reference, run `noteleaf note --help` or open the contextual help inside the TUI.
···11+---
22+title: Note Operations
33+sidebar_label: Operations
44+description: List, read, edit, and delete notes from the CLI.
55+sidebar_position: 3
66+---
77+88+# Note Operations
99+1010+### Listing Notes
1111+1212+**Interactive TUI** (default):
1313+```sh
1414+noteleaf note list
1515+```
1616+1717+Navigate with arrow keys, press Enter to read, `e` to edit, `q` to quit.
1818+1919+**Static list**:
2020+```sh
2121+noteleaf note list --static
2222+```
2323+2424+**Filter by tags**:
2525+```sh
2626+noteleaf note list --tags research,technical
2727+```
2828+2929+**Show archived notes**:
3030+```sh
3131+noteleaf note list --archived
3232+```
3333+3434+### Reading Notes
3535+3636+View note content with formatted rendering:
3737+3838+```sh
3939+noteleaf note read 1
4040+```
4141+4242+Aliases: `noteleaf note view 1`
4343+4444+The viewer renders markdown with syntax highlighting for code blocks, proper formatting for headers and lists, and displays metadata (title, tags, dates).
4545+4646+### Editing Notes
4747+4848+Open note in your configured editor:
4949+5050+```sh
5151+noteleaf note edit 1
5252+```
5353+5454+Noteleaf uses the editor specified in your configuration or the `$EDITOR` environment variable. Common choices: `vim`, `nvim`, `nano`, `code`, `emacs`.
5555+5656+**Configure editor**:
5757+```sh
5858+noteleaf config set editor nvim
5959+```
6060+6161+Changes are saved automatically when you close the editor. The modification timestamp updates to track when notes were last changed.
6262+6363+### Deleting Notes
6464+6565+Remove a note permanently:
6666+6767+```sh
6868+noteleaf note remove 1
6969+```
7070+7171+Aliases: `rm`, `delete`, `del`
7272+7373+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.
+116
website/docs/notes/organization.md
···11+---
22+title: Note Organization
33+sidebar_label: Organization
44+description: Tagging, linking, and template workflows for notes.
55+sidebar_position: 4
66+---
77+88+# Note Organization
99+1010+## Tagging
1111+1212+Tags provide flexible categorization without hierarchical constraints.
1313+1414+**Add tags during creation**:
1515+1616+```sh
1717+noteleaf note create "API Design" --tags architecture,reference
1818+```
1919+2020+**Add tags to existing note**:
2121+2222+```sh
2323+noteleaf note update 1 --add-tag reference
2424+```
2525+2626+**Remove tags**:
2727+2828+```sh
2929+noteleaf note update 1 --remove-tag draft
3030+```
3131+3232+**List all tags**:
3333+3434+```sh
3535+noteleaf note tags
3636+```
3737+3838+Shows each tag with the count of notes using it.
3939+4040+**Tag naming conventions**: Use lowercase, hyphens for compound tags. Examples: `research`, `meeting-notes`, `how-to`, `reference`, `technical`, `personal`.
4141+4242+## Linking
4343+4444+While not a first-class feature in the current UI, notes can reference tasks by ID or description:
4545+4646+```markdown
4747+# Implementation Plan
4848+4949+Related task: #42 (Deploy authentication service)
5050+5151+## Next Steps
5252+- Complete testing (task #43)
5353+- Write documentation (task #44)
5454+```
5555+5656+Future versions may support automatic linking between notes and tasks in the database.
5757+5858+## Templates
5959+6060+Create reusable note structures using shell functions or scripts:
6161+6262+**In ~/.bashrc or ~/.zshrc**:
6363+6464+```sh
6565+meeting_note() {
6666+ local title="Meeting: $1"
6767+ local date=$(date +%Y-%m-%d)
6868+ local content="# $title
6969+7070+**Date**: $date
7171+7272+## Attendees
7373+-
7474+7575+## Agenda
7676+-
7777+7878+## Discussion
7979+-
8080+8181+## Action Items
8282+- [ ]
8383+8484+## Next Meeting
8585+- "
8686+8787+ echo "$content" | noteleaf note create "$title" --tags meeting --editor
8888+}
8989+9090+daily_note() {
9191+ local date=$(date +%Y-%m-%d)
9292+ local title="Daily: $date"
9393+ local content="# $title
9494+9595+## Completed Today
9696+-
9797+9898+## In Progress
9999+-
100100+101101+## Tomorrow's Focus
102102+-
103103+104104+## Notes
105105+- "
106106+107107+ echo "$content" | noteleaf note create "$title" --tags daily --editor
108108+}
109109+```
110110+111111+Usage:
112112+113113+```sh
114114+meeting_note "Q4 Planning"
115115+daily_note
116116+```
+11
website/docs/notes/overview.md
···11+---
22+title: Notes Overview
33+sidebar_label: Overview
44+description: How Noteleaf manages markdown-based notes.
55+sidebar_position: 1
66+---
77+88+# Notes Overview
99+1010+Noteleaf provides a markdown-based note-taking system integrated with your tasks, articles, and media tracking.
1111+Notes are stored as individual markdown files with metadata tracked in the database, giving you both structure and portability.
+85
website/docs/notes/workflows.md
···11+---
22+title: Note-Taking Workflows
33+sidebar_label: Workflows
44+description: Zettelkasten, meeting notes, daily notes, and more.
55+sidebar_position: 7
66+---
77+88+# Note-Taking Workflows
99+1010+## Zettelkasten
1111+1212+Zettelkasten emphasizes atomic notes with heavy linking:
1313+1414+1. **Create atomic notes**: Each note covers one concept
1515+2. **Add descriptive tags**: Use tags for categorization
1616+3. **Link related notes**: Reference other notes by title
1717+4. **Develop ideas over time**: Expand notes with new insights
1818+1919+Example:
2020+2121+```sh
2222+noteleaf note create "Dependency Injection" --tags architecture,patterns
2323+noteleaf note create "Inversion of Control" --tags architecture,patterns
2424+# In each note, reference the other
2525+```
2626+2727+### Research
2828+2929+For academic or technical research:
3030+3131+1. **Source note per paper/article**: Create note for each source
3232+2. **Extract key points**: Summarize in your own words
3333+3. **Tag by topic**: Use consistent tags across research area
3434+4. **Link to related work**: Reference other sources
3535+3636+Example:
3737+3838+```sh
3939+noteleaf note create "Paper: Microservices Patterns" \
4040+ --tags research,architecture,microservices
4141+```
4242+4343+### Meeting
4444+4545+Capture discussions and action items:
4646+4747+1. **Template-based**: Use meeting_note function from earlier
4848+2. **Consistent structure**: Attendees, agenda, discussion, actions
4949+3. **Action items**: Extract as tasks for follow-up
5050+4. **Link to projects**: Tag with project name
5151+5252+Example:
5353+5454+```sh
5555+meeting_note "Sprint Planning"
5656+# Then extract action items as tasks
5757+noteleaf task add "Implement auth endpoint" --project web-service
5858+```
5959+6060+### Daily
6161+6262+Journal-style daily entries:
6363+6464+1. **Daily template**: Use daily_note function
6565+2. **Reflect on work**: What was accomplished, what's next
6666+3. **Capture ideas**: Random thoughts for later processing
6767+4. **Review weekly**: Scan week's notes for patterns
6868+6969+Example:
7070+7171+```sh
7272+daily_note
7373+# Creates note tagged with 'daily' and today's date
7474+```
7575+7676+### Personal Knowledge Base
7777+7878+Build a reference library:
7979+8080+1. **How-to guides**: Document procedures and commands
8181+2. **Troubleshooting notes**: Solutions to problems encountered
8282+3. **Concept explanations**: Notes on topics you're learning
8383+4. **Snippets**: Code examples and configurations
8484+8585+Use tags like: `how-to`, `troubleshooting`, `reference`, `snippet`
···11+---
22+title: Advanced Task Features
33+sidebar_label: Advanced
44+description: Recurring tasks, dependencies, hierarchies, and custom fields.
55+sidebar_position: 6
66+---
77+88+# Advanced Task Features
99+1010+## Recurrence
1111+1212+Create tasks that repeat on a schedule using iCalendar recurrence rules.
1313+1414+**Daily task**:
1515+1616+```sh
1717+noteleaf task add "Daily standup" --recur "FREQ=DAILY"
1818+```
1919+2020+**Weekly task on specific days**:
2121+2222+```sh
2323+noteleaf task add "Team meeting" --recur "FREQ=WEEKLY;BYDAY=MO,WE"
2424+```
2525+2626+**Monthly task**:
2727+2828+```sh
2929+noteleaf task add "Invoice review" --recur "FREQ=MONTHLY;BYMONTHDAY=1"
3030+```
3131+3232+**With end date**:
3333+3434+```sh
3535+noteleaf task add "Q1 review" \
3636+ --recur "FREQ=WEEKLY" \
3737+ --until 2025-03-31
3838+```
3939+4040+**Manage recurrence**:
4141+4242+Set recurrence on existing task:
4343+4444+```sh
4545+noteleaf task recur set 1 --rule "FREQ=DAILY"
4646+```
4747+4848+View recurrence info:
4949+5050+```sh
5151+noteleaf task recur show 1
5252+```
5353+5454+Remove recurrence:
5555+5656+```sh
5757+noteleaf task recur clear 1
5858+```
5959+6060+When you complete a recurring task, Noteleaf automatically generates the next instance based on the recurrence rule.
6161+6262+## Dependencies
6363+6464+Create relationships where tasks must be completed in order.
6565+6666+**Add dependency** (task 1 depends on task 2):
6767+6868+```sh
6969+noteleaf task depend add 1 <uuid-of-task-2>
7070+```
7171+7272+**List dependencies** (what must be done first):
7373+7474+```sh
7575+noteleaf task depend list 1
7676+```
7777+7878+**List blocked tasks** (what's waiting on this task):
7979+8080+```sh
8181+noteleaf task depend blocked-by 1
8282+```
8383+8484+**Remove dependency**:
8585+8686+```sh
8787+noteleaf task depend remove 1 <uuid-of-task-2>
8888+```
8989+9090+Dependencies use task UUIDs (shown in `task view`) rather than IDs for stability across database changes.
9191+9292+## Hierarchical Tasks
9393+9494+Create parent-child relationships for breaking down large tasks.
9595+9696+**Create child task**:
9797+9898+```sh
9999+noteleaf task add "Write API documentation" --parent <parent-uuid>
100100+```
101101+102102+Parent tasks can have multiple children, creating a tree structure for complex projects.
103103+104104+## Custom Attributes
105105+106106+While not exposed through specific flags, the database schema supports extending tasks with custom attributes for advanced use cases or scripting.
+85
website/docs/tasks/basics.md
···11+---
22+title: Task Basics
33+sidebar_label: Basics
44+description: Create tasks and understand their core attributes.
55+sidebar_position: 2
66+---
77+88+# Task Basics
99+1010+## Creation
1111+1212+Create a simple task:
1313+1414+```sh
1515+noteleaf task add "Write documentation"
1616+```
1717+1818+Create a task with attributes:
1919+2020+```sh
2121+noteleaf task add "Review pull requests" \
2222+ --priority high \
2323+ --project work \
2424+ --tags urgent,code-review \
2525+ --due 2025-01-15
2626+```
2727+2828+## Properties
2929+3030+**Description**: What needs to be done. Can be updated later with `task update`.
3131+3232+**Status**: Task lifecycle state:
3333+3434+- `pending`: Not yet started (default for new tasks)
3535+- `active`: Currently being worked on
3636+- `completed`: Finished successfully
3737+- `deleted`: Removed but preserved for history
3838+- `waiting`: Blocked or postponed
3939+4040+**Priority**: Importance level affects sorting and display:
4141+4242+- `low`: Nice to have, defer if busy
4343+- `medium`: Standard priority (default)
4444+- `high`: Important, should be done soon
4545+- `urgent`: Critical, top of the list
4646+4747+**Project**: Group related tasks together. Examples: `work`, `home`, `side-project`. Projects create organizational boundaries and enable filtering.
4848+4949+**Context**: Location or mode where task can be done. Examples: `@home`, `@office`, `@phone`, `@computer`. Contexts help filter tasks based on current situation.
5050+5151+**Tags**: Flexible categorization orthogonal to projects. Examples: `urgent`, `quick-win`, `research`, `bug`. Multiple tags per task.
5252+5353+**Due Date**: When the task should be completed. Format: `YYYY-MM-DD` or relative (`tomorrow`, `next week`).
5454+5555+### Lifecycle
5656+5757+Tasks move through statuses as work progresses:
5858+5959+```
6060+pending -> active -> completed
6161+ |
6262+ v
6363+ waiting
6464+ |
6565+ v
6666+ deleted
6767+```
6868+6969+**Mark task as active**:
7070+7171+```sh
7272+noteleaf task update 1 --status active
7373+```
7474+7575+**Complete a task**:
7676+7777+```sh
7878+noteleaf task done 1
7979+```
8080+8181+**Delete a task**:
8282+8383+```sh
8484+noteleaf task delete 1
8585+```
+26
website/docs/tasks/batch-operations.md
···11+---
22+title: Batch Operations
33+sidebar_label: Batch Ops
44+description: Use shell scripting patterns for mass task edits.
55+sidebar_position: 8
66+---
77+88+# Batch Operations
99+1010+While Noteleaf doesn't have built-in bulk update commands, you can use shell scripting for batch operations:
1111+1212+**Complete all tasks in a project**:
1313+1414+```sh
1515+noteleaf task list --project old-project --static | \
1616+ awk '{print $1}' | \
1717+ xargs -I {} noteleaf task done {}
1818+```
1919+2020+**Add tag to multiple tasks**:
2121+2222+```sh
2323+for id in 1 2 3 4 5; do
2424+ noteleaf task update $id --add-tag urgent
2525+done
2626+```
+26
website/docs/tasks/best-practices.md
···11+---
22+title: Task Tips and Best Practices
33+sidebar_label: Best Practices
44+description: Practical guidance for staying productive with tasks.
55+sidebar_position: 10
66+---
77+88+# Task Tips and Best Practices
99+1010+**Start with simple workflows**: Don't over-organize initially. Use basic priorities and projects before adding contexts, tags, and dependencies.
1111+1212+**Review regularly**: Use `task list` daily to check pending work. Weekly reviews help catch stale tasks.
1313+1414+**Use contexts for GTD**: If following Getting Things Done, contexts help filter tasks by what you can do right now.
1515+1616+**Project-based work**: For complex initiatives, use projects to group tasks and dependencies to order work.
1717+1818+**Time tracking for accountability**: Even rough time tracking reveals where hours go and helps with estimates.
1919+2020+**Recurrence for habits**: Use recurring tasks for daily/weekly habits, but keep the list short to avoid clutter.
2121+2222+**Tags for cross-cutting concerns**: Use tags for themes that span projects: `urgent`, `blocked`, `waiting-on-feedback`, `quick-win`.
2323+2424+**JSON output for scripts**: Use `--json` flag with scripting to build custom reports and integrations.
2525+2626+For CLI command reference, run `noteleaf task --help` or explore the inline help on each subcommand.
+114
website/docs/tasks/operations.md
···11+---
22+title: Task Operations
33+sidebar_label: Operations
44+description: List, view, and update tasks from the CLI and TUI.
55+sidebar_position: 3
66+---
77+88+# Task Operations
99+1010+## Listing and Filtering
1111+1212+**Interactive list** (default):
1313+1414+```sh
1515+noteleaf task list
1616+```
1717+1818+Navigate with arrow keys, press Enter to view details, `q` to quit.
1919+2020+**Static list** (for scripting):
2121+2222+```sh
2323+noteleaf task list --static
2424+```
2525+2626+**Filter by status**:
2727+2828+```sh
2929+noteleaf task list --status pending
3030+noteleaf task list --status completed
3131+```
3232+3333+**Filter by project**:
3434+3535+```sh
3636+noteleaf task list --project work
3737+```
3838+3939+**Filter by priority**:
4040+4141+```sh
4242+noteleaf task list --priority high
4343+```
4444+4545+**Filter by context**:
4646+4747+```sh
4848+noteleaf task list --context @office
4949+```
5050+5151+**Show all tasks** (including completed):
5252+5353+```sh
5454+noteleaf task list --all
5555+```
5656+5757+## Viewing Task Details
5858+5959+View complete task information:
6060+6161+```sh
6262+noteleaf task view 1
6363+```
6464+6565+JSON output for scripts:
6666+6767+```sh
6868+noteleaf task view 1 --json
6969+```
7070+7171+Brief format without metadata:
7272+7373+```sh
7474+noteleaf task view 1 --format brief
7575+```
7676+7777+## Updating Tasks
7878+7979+Update single attribute:
8080+8181+```sh
8282+noteleaf task update 1 --priority urgent
8383+```
8484+8585+Update multiple attributes:
8686+8787+```sh
8888+noteleaf task update 1 \
8989+ --priority urgent \
9090+ --due tomorrow \
9191+ --add-tag critical
9292+```
9393+9494+Change description:
9595+9696+```sh
9797+noteleaf task update 1 --description "New task description"
9898+```
9999+100100+Add and remove tags:
101101+102102+```sh
103103+noteleaf task update 1 --add-tag urgent --remove-tag later
104104+```
105105+106106+## Interactive Editing
107107+108108+Open interactive editor for complex changes:
109109+110110+```sh
111111+noteleaf task edit 1
112112+```
113113+114114+This provides a TUI with visual pickers for status and priority, making updates faster than command flags.
+64
website/docs/tasks/organization.md
···11+---
22+title: Task Organization
33+sidebar_label: Organization
44+description: Use projects, contexts, and tags to structure work.
55+sidebar_position: 5
66+---
77+88+# Task Organization
99+1010+## Projects
1111+1212+Projects group related tasks. Useful for separating work contexts or major initiatives.
1313+1414+**List all projects**:
1515+1616+```sh
1717+noteleaf task projects
1818+```
1919+2020+Shows each project with task count.
2121+2222+**Filter tasks by project**:
2323+2424+```sh
2525+noteleaf task list --project work
2626+```
2727+2828+**Project naming**: Use lowercase, hyphens for spaces. Examples: `work`, `side-project`, `home-improvement`.
2929+3030+## Contexts
3131+3232+Contexts represent where or how a task can be done. Helps with GTD-style workflow.
3333+3434+**List all contexts**:
3535+3636+```sh
3737+noteleaf task contexts
3838+```
3939+4040+**Filter by context**:
4141+4242+```sh
4343+noteleaf task list --context @home
4444+```
4545+4646+**Context naming**: Prefix with `@` following GTD convention. Examples: `@home`, `@office`, `@phone`, `@errands`.
4747+4848+## Tags
4949+5050+Tags provide flexible categorization. Unlike projects and contexts, tasks can have multiple tags.
5151+5252+**List all tags**:
5353+5454+```sh
5555+noteleaf task tags
5656+```
5757+5858+**Filter by tags** (tasks must have all specified tags):
5959+6060+```sh
6161+noteleaf task list --tags urgent,bug
6262+```
6363+6464+**Tag naming**: Use lowercase, hyphens for compound tags. Examples: `urgent`, `quick-win`, `code-review`, `waiting-on-feedback`.
+11
website/docs/tasks/overview.md
···11+---
22+title: Task Management Overview
33+sidebar_label: Overview
44+description: High-level summary of Noteleaf's task workflow.
55+sidebar_position: 1
66+---
77+88+# Task Management Overview
99+1010+Noteleaf provides TaskWarrior-inspired task management with priorities, projects, contexts, tags, dependencies, and time tracking.
1111+Whether you're managing personal todos or complex projects, Noteleaf helps you organize work and track progress.
+33
website/docs/tasks/queries.md
···11+---
22+title: Task Queries and Filtering
33+sidebar_label: Queries
44+description: Compose filters for precise task lists and reports.
55+sidebar_position: 7
66+---
77+88+# Task Queries and Filtering
99+1010+Combine filters for precise task lists:
1111+1212+**High priority work tasks due this week**:
1313+1414+```sh
1515+noteleaf task list \
1616+ --project work \
1717+ --priority high \
1818+ --status pending
1919+```
2020+2121+**All completed tasks from specific project**:
2222+2323+```sh
2424+noteleaf task list \
2525+ --project side-project \
2626+ --status completed
2727+```
2828+2929+**Quick wins** (tasks tagged as quick):
3030+3131+```sh
3232+noteleaf task list --tags quick-win
3333+```
+34
website/docs/tasks/templates.md
···11+---
22+title: Task Templates
33+sidebar_label: Templates
44+description: Shell helpers for creating consistent task structures.
55+sidebar_position: 9
66+---
77+88+# Task Templates
99+1010+While templates aren't built-in, you can create shell functions for common task patterns:
1111+1212+```sh
1313+# In your ~/.bashrc or ~/.zshrc
1414+bug() {
1515+ noteleaf task add "$1" \
1616+ --project $(git rev-parse --show-toplevel | xargs basename) \
1717+ --tags bug \
1818+ --priority high
1919+}
2020+2121+meeting() {
2222+ noteleaf task add "$1" \
2323+ --project work \
2424+ --context @office \
2525+ --recur "FREQ=WEEKLY;BYDAY=$2"
2626+}
2727+```
2828+2929+Usage:
3030+3131+```sh
3232+bug "Fix login redirect"
3333+meeting "Sprint planning" "MO"
3434+```
+60
website/docs/tasks/time-tracking.md
···11+---
22+title: Time Tracking
33+sidebar_label: Time Tracking
44+description: Track work, review sessions, and generate timesheets.
55+sidebar_position: 4
66+---
77+88+# Time Tracking
99+1010+Track hours spent on tasks for billing, reporting, or personal analytics.
1111+1212+## Starting and Stopping
1313+1414+**Start tracking**:
1515+1616+```sh
1717+noteleaf task start 1
1818+```
1919+2020+With a note about what you're doing:
2121+2222+```sh
2323+noteleaf task start 1 --note "Implementing authentication"
2424+```
2525+2626+**Stop tracking**:
2727+2828+```sh
2929+noteleaf task stop 1
3030+```
3131+3232+Only one task can be actively tracked at a time.
3333+3434+## Viewing Timesheets
3535+3636+**Last 7 days** (default):
3737+3838+```sh
3939+noteleaf task timesheet
4040+```
4141+4242+**Specific time range**:
4343+4444+```sh
4545+noteleaf task timesheet --days 30
4646+```
4747+4848+**For specific task**:
4949+5050+```sh
5151+noteleaf task timesheet --task 1
5252+```
5353+5454+Timesheet shows:
5555+5656+- Date and time range for each session
5757+- Duration
5858+- Notes attached to the session
5959+- Total time per task
6060+- Total time across all tasks
+297
website/docs/workflows/import-export.md
···11+---
22+title: Import and Export
33+sidebar_label: Import & Export
44+sidebar_position: 1
55+description: Data portability, backups, and migration.
66+---
77+88+# Import and Export
99+1010+Noteleaf stores data in open formats for portability: SQLite for structured data and Markdown for notes.
1111+1212+## Data Storage
1313+1414+### SQLite Database
1515+1616+Location varies by platform:
1717+1818+**macOS:**
1919+2020+```
2121+~/Library/Application Support/noteleaf/noteleaf.db
2222+```
2323+2424+**Linux:**
2525+2626+```
2727+~/.local/share/noteleaf/noteleaf.db
2828+```
2929+3030+**Windows:**
3131+3232+```
3333+%LOCALAPPDATA%\noteleaf\noteleaf.db
3434+```
3535+3636+### Markdown Files
3737+3838+Notes are stored as individual markdown files:
3939+4040+**Default location:**
4141+4242+```
4343+<data_dir>/notes/
4444+```
4545+4646+Configure via `notes_dir` in `.noteleaf.conf.toml`.
4747+4848+### Articles
4949+5050+Saved articles are stored as markdown:
5151+5252+**Default location:**
5353+5454+```
5555+<data_dir>/articles/
5656+```
5757+5858+Configure via `articles_dir` in `.noteleaf.conf.toml`.
5959+6060+## JSON Export
6161+6262+### Task Export
6363+6464+Export tasks to JSON format:
6565+6666+```sh
6767+noteleaf todo view 123 --json
6868+noteleaf todo list --static --json
6969+```
7070+7171+Output includes all task attributes:
7272+7373+- Description
7474+- Status, priority
7575+- Project, context, tags
7676+- Due dates, recurrence
7777+- Dependencies, parent tasks
7878+- Timestamps
7979+8080+### Export Format Configuration
8181+8282+Set default export format:
8383+8484+```sh
8585+noteleaf config set export_format "json"
8686+```
8787+8888+Options:
8989+9090+- `json` (default)
9191+- `csv` (planned)
9292+- `markdown` (planned)
9393+9494+## Backup Strategy
9595+9696+### Full Backup
9797+9898+Back up the entire data directory:
9999+100100+```sh
101101+# macOS
102102+cp -r ~/Library/Application\ Support/noteleaf ~/Backups/noteleaf-$(date +%Y%m%d)
103103+104104+# Linux
105105+cp -r ~/.local/share/noteleaf ~/backups/noteleaf-$(date +%Y%m%d)
106106+```
107107+108108+Includes:
109109+110110+- SQLite database
111111+- Notes directory
112112+- Articles directory
113113+- Configuration file
114114+115115+### Database Only
116116+117117+```sh
118118+# macOS
119119+cp ~/Library/Application\ Support/noteleaf/noteleaf.db ~/Backups/
120120+121121+# Linux
122122+cp ~/.local/share/noteleaf/noteleaf.db ~/backups/
123123+```
124124+125125+### Notes Only
126126+127127+```sh
128128+# Copy notes directory
129129+cp -r <data_dir>/notes ~/Backups/notes-$(date +%Y%m%d)
130130+```
131131+132132+Notes are plain markdown files, easily versioned with Git:
133133+134134+```sh
135135+cd <data_dir>/notes
136136+git init
137137+git add .
138138+git commit -m "Initial notes backup"
139139+```
140140+141141+## Restore from Backup
142142+143143+### Full Restore
144144+145145+```sh
146146+# Stop noteleaf
147147+# Replace data directory
148148+cp -r ~/Backups/noteleaf-20240315 ~/Library/Application\ Support/noteleaf
149149+```
150150+151151+### Database Restore
152152+153153+```sh
154154+cp ~/Backups/noteleaf.db ~/Library/Application\ Support/noteleaf/
155155+```
156156+157157+### Notes Restore
158158+159159+```sh
160160+cp -r ~/Backups/notes-20240315 <data_dir>/notes
161161+```
162162+163163+## Direct Database Access
164164+165165+SQLite database is accessible with standard tools:
166166+167167+```sh
168168+# Open database
169169+sqlite3 ~/Library/Application\ Support/noteleaf/noteleaf.db
170170+171171+# List tables
172172+.tables
173173+174174+# Query tasks
175175+SELECT id, description, status FROM tasks WHERE status = 'pending';
176176+177177+# Export to CSV
178178+.mode csv
179179+.output tasks.csv
180180+SELECT * FROM tasks;
181181+.quit
182182+```
183183+184184+## Portable Installation
185185+186186+Use environment variables for portable setup:
187187+188188+```sh
189189+export NOTELEAF_DATA_DIR=/path/to/usb/noteleaf-data
190190+export NOTELEAF_CONFIG=/path/to/usb/noteleaf.conf.toml
191191+noteleaf todo list
192192+```
193193+194194+Useful for:
195195+196196+- USB drive installations
197197+- Synced folders (Dropbox, iCloud)
198198+- Multiple workspaces
199199+- Testing environments
200200+201201+## Migration Strategies
202202+203203+### From TaskWarrior
204204+205205+Manual migration via SQLite:
206206+207207+1. Export TaskWarrior data to JSON
208208+2. Parse JSON and insert into noteleaf database
209209+3. Map TaskWarrior attributes to Noteleaf schema
210210+211211+Custom migration script required (future documentation).
212212+213213+### From todo.txt
214214+215215+Convert todo.txt to Noteleaf tasks:
216216+217217+1. Parse todo.txt format
218218+2. Map projects, contexts, priorities
219219+3. Bulk insert via SQLite
220220+221221+Custom migration script required (future documentation).
222222+223223+### From Other Note Apps
224224+225225+Notes are markdown files:
226226+227227+1. Export notes from source app
228228+2. Convert to plain markdown
229229+3. Copy to `<data_dir>/notes/`
230230+4. Noteleaf will index them on next scan
231231+232232+## Sync and Cloud Storage
233233+234234+### Cloud Sync
235235+236236+Store data directory in synced folder:
237237+238238+```sh
239239+# Use Dropbox
240240+export NOTELEAF_DATA_DIR=~/Dropbox/noteleaf-data
241241+242242+# Use iCloud
243243+export NOTELEAF_DATA_DIR=~/Library/Mobile\ Documents/com~apple~CloudDocs/noteleaf
244244+```
245245+246246+**Warning:** SQLite databases don't handle concurrent writes well. Only run one Noteleaf instance at a time per database.
247247+248248+### Version Control
249249+250250+Notes directory can be versioned:
251251+252252+```sh
253253+cd <data_dir>/notes
254254+git init
255255+git add .
256256+git commit -m "Initial commit"
257257+git remote add origin <repository-url>
258258+git push -u origin main
259259+```
260260+261261+Automatic git commits planned for future release.
262262+263263+## Data Formats
264264+265265+### SQLite Schema
266266+267267+View schema:
268268+269269+```sh
270270+sqlite3 noteleaf.db .schema
271271+```
272272+273273+Tables include:
274274+275275+- `tasks` - Task management
276276+- `notes` - Note metadata
277277+- `articles` - Article metadata
278278+- `books`, `movies`, `tv_shows` - Media tracking
279279+- `publications` - Leaflet.pub publications
280280+- Linking tables for tags, dependencies
281281+282282+### Markdown Format
283283+284284+Notes use standard markdown with YAML frontmatter:
285285+286286+```markdown
287287+---
288288+title: Note Title
289289+created: 2024-03-15T10:30:00Z
290290+modified: 2024-03-15T11:00:00Z
291291+tags: [tag1, tag2]
292292+---
293293+294294+# Note Content
295295+296296+Regular markdown content...
297297+```