Commit a172f177ab44

Vincent Demeester <vincent@sbr.pm>
2025-12-23 13:25:54
feat(org): Add CLI commands and docs for recurring tasks and dependencies (P3)
- Add CLI commands to org-manager: - set-repeater: Set repeater specification for recurring tasks - get-recurring-tasks: List all tasks with repeaters - set-blocker: Set task blocker for dependencies - get-blocker: Get blocker for a task - get-blocked-tasks: List all blocked tasks - set-related: Create task relationships - get-related: Get all relationships for a task - Update SKILL.md with: - Usage examples for recurring tasks - Usage examples for dependencies and relationships - Function documentation in implementation section - Add comprehensive help text in org-manager usage These CLI commands expose the P3 functionality added in the previous commit, enabling full workflow management for recurring tasks and task dependencies. Signed-off-by: Vincent Demeester <vincent@sbr.pm>
1 parent 0743c4c
Changed files (2)
dots
.config
claude
skills
dots/.config/claude/skills/Org/tools/org-manager
@@ -226,6 +226,37 @@ EXPORT & REPORTING:
       Export all TODOs to JSON format
       Creates machine-readable structured export
 
+RECURRING TASKS:
+  set-repeater <file> <heading> <repeater-spec>
+      Set repeater for a task (e.g., +1w for weekly, .+2d for 2 days after completion)
+      Adds or updates SCHEDULED timestamp with repeater syntax
+
+  get-recurring-tasks <file>
+      List all tasks with repeater specifications
+      Shows tasks that recur automatically
+
+DEPENDENCIES & RELATIONSHIPS:
+  set-blocker <file> <heading> <blocker-heading>
+      Set a blocker for a task (task that must be completed first)
+      Uses BLOCKER property to track dependency
+
+  get-blocker <file> <heading>
+      Get the blocker for a specific task
+      Returns the blocking task heading if set
+
+  get-blocked-tasks <file>
+      List all tasks that have blockers set
+      Shows tasks waiting on other tasks
+
+  set-related <file> <heading> <related-heading> <relation-type>
+      Create relationship between tasks
+      Relation types: child, parent, related, depends-on
+      Uses RELATED_* properties
+
+  get-related <file> <heading>
+      Get all relationships for a task
+      Returns all RELATED_* properties
+
 DENOTE COMMANDS:
   denote-create <title> <tags> [--signature=SIG] [--category=CAT] [--directory=DIR] [--content=FILE]
       Create a denote-formatted note with proper naming and frontmatter
@@ -991,6 +1022,127 @@ cmd_export_json() {
     run_elisp "$elisp"
 }
 
+# Recurring tasks commands
+
+cmd_set_repeater() {
+    local file="$1"
+    local heading="$2"
+    local repeater="$3"
+
+    [[ -f "$file" ]] || error "File not found: $file"
+    [[ -n "$heading" ]] || error "Heading required"
+    [[ -n "$repeater" ]] || error "Repeater specification required (e.g., +1w, .+2d)"
+
+    local elisp="(progn
+      (let ((result (org-batch-set-repeater \"$file\" \"$heading\" \"$repeater\")))
+        (if result
+            (org-batch-output-json t (list :repeater-set t :heading \"$heading\" :repeater \"$repeater\"))
+          (org-batch-output-error \"Heading not found: $heading\")))
+      (kill-emacs 0))"
+
+    run_elisp "$elisp"
+}
+
+cmd_get_recurring_tasks() {
+    local file="$1"
+
+    [[ -f "$file" ]] || error "File not found: $file"
+
+    local elisp="(progn
+      (let ((tasks (org-batch-get-recurring-tasks \"$file\")))
+        (org-batch-output-json t tasks))
+      (kill-emacs 0))"
+
+    run_elisp "$elisp"
+}
+
+# Dependencies & relationships commands
+
+cmd_set_blocker() {
+    local file="$1"
+    local heading="$2"
+    local blocker="$3"
+
+    [[ -f "$file" ]] || error "File not found: $file"
+    [[ -n "$heading" ]] || error "Heading required"
+    [[ -n "$blocker" ]] || error "Blocker heading required"
+
+    local elisp="(progn
+      (let ((result (org-batch-set-blocker \"$file\" \"$heading\" \"$blocker\")))
+        (if result
+            (org-batch-output-json t (list :blocker-set t :heading \"$heading\" :blocker \"$blocker\"))
+          (org-batch-output-error \"Heading not found: $heading\")))
+      (kill-emacs 0))"
+
+    run_elisp "$elisp"
+}
+
+cmd_get_blocker() {
+    local file="$1"
+    local heading="$2"
+
+    [[ -f "$file" ]] || error "File not found: $file"
+    [[ -n "$heading" ]] || error "Heading required"
+
+    local elisp="(progn
+      (let ((blocker (org-batch-get-blocker \"$file\" \"$heading\")))
+        (if blocker
+            (org-batch-output-json t (list :heading \"$heading\" :blocker blocker))
+          (org-batch-output-json t nil)))
+      (kill-emacs 0))"
+
+    run_elisp "$elisp"
+}
+
+cmd_get_blocked_tasks() {
+    local file="$1"
+
+    [[ -f "$file" ]] || error "File not found: $file"
+
+    local elisp="(progn
+      (let ((tasks (org-batch-get-blocked-tasks \"$file\")))
+        (org-batch-output-json t tasks))
+      (kill-emacs 0))"
+
+    run_elisp "$elisp"
+}
+
+cmd_set_related() {
+    local file="$1"
+    local heading="$2"
+    local related="$3"
+    local relation_type="$4"
+
+    [[ -f "$file" ]] || error "File not found: $file"
+    [[ -n "$heading" ]] || error "Heading required"
+    [[ -n "$related" ]] || error "Related heading required"
+    [[ -n "$relation_type" ]] || error "Relation type required (child/parent/related/depends-on)"
+
+    local elisp="(progn
+      (let ((result (org-batch-set-related \"$file\" \"$heading\" \"$related\" \"$relation_type\")))
+        (if result
+            (org-batch-output-json t (list :related-set t :heading \"$heading\" :related \"$related\" :type \"$relation_type\"))
+          (org-batch-output-error \"Heading not found: $heading\")))
+      (kill-emacs 0))"
+
+    run_elisp "$elisp"
+}
+
+cmd_get_related() {
+    local file="$1"
+    local heading="$2"
+
+    [[ -f "$file" ]] || error "File not found: $file"
+    [[ -n "$heading" ]] || error "Heading required"
+
+    local elisp="(progn
+      (let ((related (org-batch-get-related \"$file\" \"$heading\")))
+        (org-batch-output-json t (list :heading \"$heading\" :related related)))
+      (kill-emacs 0))"
+
+    run_elisp "$elisp"
+}
+
 # Denote commands
 
 cmd_denote_create() {
@@ -1252,6 +1404,27 @@ main() {
         export-json)
             cmd_export_json "$@"
             ;;
+        set-repeater)
+            cmd_set_repeater "$@"
+            ;;
+        get-recurring-tasks)
+            cmd_get_recurring_tasks "$@"
+            ;;
+        set-blocker)
+            cmd_set_blocker "$@"
+            ;;
+        get-blocker)
+            cmd_get_blocker "$@"
+            ;;
+        get-blocked-tasks)
+            cmd_get_blocked_tasks "$@"
+            ;;
+        set-related)
+            cmd_set_related "$@"
+            ;;
+        get-related)
+            cmd_get_related "$@"
+            ;;
         denote-create)
             cmd_denote_create "$@"
             ;;
dots/.config/claude/skills/Org/SKILL.md
@@ -133,6 +133,33 @@ Provide reliable, programmatic access to org-mode files using Emacs batch mode a
 ./tools/org-manager export-json ~/desktop/org/todos.org /tmp/todos.json
 ```
 
+#### Recurring Tasks
+```bash
+# Set repeater for a task (+1w = weekly, .+2d = 2 days after completion)
+./tools/org-manager set-repeater ~/desktop/org/todos.org "Weekly Review" "+1w"
+
+# Get all recurring tasks
+./tools/org-manager get-recurring-tasks ~/desktop/org/todos.org
+```
+
+#### Dependencies & Relationships
+```bash
+# Set a blocker for a task
+./tools/org-manager set-blocker ~/desktop/org/todos.org "Deploy to production" "Complete testing"
+
+# Get blocker for a specific task
+./tools/org-manager get-blocker ~/desktop/org/todos.org "Deploy to production"
+
+# List all blocked tasks
+./tools/org-manager get-blocked-tasks ~/desktop/org/todos.org
+
+# Create task relationship (child/parent/related/depends-on)
+./tools/org-manager set-related ~/desktop/org/todos.org "Implement feature" "Design review" "depends-on"
+
+# Get all relationships for a task
+./tools/org-manager get-related ~/desktop/org/todos.org "Implement feature"
+```
+
 #### Denote Operations
 ```bash
 # Create denote-formatted note
@@ -209,6 +236,37 @@ All commands return JSON:
 - `org-batch-set-property` - Set property value
 - `org-batch-list-properties` - List all properties of a heading
 
+**Bulk Operations:**
+- `org-batch-bulk-update-state` - Update all tasks matching a state
+- `org-batch-bulk-add-tags` - Add tags to all tasks with specific state
+- `org-batch-bulk-set-priority` - Set priority for all tasks with specific state
+
+**Time Tracking:**
+- `org-batch-clock-in` - Start time tracking on a task
+- `org-batch-clock-out` - Stop time tracking
+- `org-batch-get-active-clock` - Get currently clocked task
+- `org-batch-get-clocked-time` - Get total time spent on a task
+
+**Statistics & Analytics:**
+- `org-batch-get-statistics` - Comprehensive statistics (counts, priorities, tags, overdue)
+- `org-batch-get-priority-distribution` - Priority distribution across tasks
+- `org-batch-get-tag-statistics` - Tag usage statistics
+
+**Export & Reporting:**
+- `org-batch-export-csv` - Export TODOs to CSV format
+- `org-batch-export-json` - Export TODOs to JSON format
+
+**Recurring Tasks:**
+- `org-batch-set-repeater` - Set repeater specification for a task
+- `org-batch-get-recurring-tasks` - List all tasks with repeaters
+
+**Dependencies & Relationships:**
+- `org-batch-set-blocker` - Set task blocker
+- `org-batch-get-blocker` - Get blocker for a task
+- `org-batch-get-blocked-tasks` - List all blocked tasks
+- `org-batch-set-related` - Create task relationships (child/parent/related/depends-on)
+- `org-batch-get-related` - Get all relationships for a task
+
 ### Denote Functions (denote-batch-functions.el)
 
 **Note Creation and Management:**