trak_flow 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/.envrc +3 -0
  3. data/CHANGELOG.md +69 -0
  4. data/COMMITS.md +196 -0
  5. data/Gemfile +8 -0
  6. data/Gemfile.lock +281 -0
  7. data/README.md +479 -0
  8. data/Rakefile +16 -0
  9. data/bin/tf +6 -0
  10. data/bin/tf_mcp +81 -0
  11. data/docs/.keep +0 -0
  12. data/docs/api/database.md +434 -0
  13. data/docs/api/ruby-library.md +349 -0
  14. data/docs/api/task-model.md +341 -0
  15. data/docs/assets/stylesheets/extra.css +53 -0
  16. data/docs/assets/trak_flow.jpg +0 -0
  17. data/docs/cli/admin-commands.md +369 -0
  18. data/docs/cli/dependency-commands.md +321 -0
  19. data/docs/cli/label-commands.md +222 -0
  20. data/docs/cli/overview.md +163 -0
  21. data/docs/cli/plan-commands.md +344 -0
  22. data/docs/cli/task-commands.md +333 -0
  23. data/docs/core-concepts/dependencies.md +232 -0
  24. data/docs/core-concepts/labels.md +217 -0
  25. data/docs/core-concepts/overview.md +178 -0
  26. data/docs/core-concepts/plans-workflows.md +264 -0
  27. data/docs/core-concepts/tasks.md +205 -0
  28. data/docs/getting-started/configuration.md +120 -0
  29. data/docs/getting-started/installation.md +79 -0
  30. data/docs/getting-started/quick-start.md +245 -0
  31. data/docs/index.md +169 -0
  32. data/docs/mcp/integration.md +302 -0
  33. data/docs/mcp/overview.md +206 -0
  34. data/docs/mcp/resources.md +284 -0
  35. data/docs/mcp/tools.md +457 -0
  36. data/examples/basic_usage.rb +365 -0
  37. data/examples/cli_demo.sh +314 -0
  38. data/examples/mcp/Gemfile +9 -0
  39. data/examples/mcp/Gemfile.lock +226 -0
  40. data/examples/mcp/http_demo.rb +232 -0
  41. data/examples/mcp/stdio_demo.rb +146 -0
  42. data/lib/trak_flow/cli/admin_commands.rb +136 -0
  43. data/lib/trak_flow/cli/config_commands.rb +260 -0
  44. data/lib/trak_flow/cli/dep_commands.rb +71 -0
  45. data/lib/trak_flow/cli/label_commands.rb +76 -0
  46. data/lib/trak_flow/cli/main_commands.rb +386 -0
  47. data/lib/trak_flow/cli/plan_commands.rb +185 -0
  48. data/lib/trak_flow/cli/workflow_commands.rb +133 -0
  49. data/lib/trak_flow/cli.rb +110 -0
  50. data/lib/trak_flow/config/defaults.yml +114 -0
  51. data/lib/trak_flow/config/section.rb +74 -0
  52. data/lib/trak_flow/config.rb +276 -0
  53. data/lib/trak_flow/graph/dependency_graph.rb +288 -0
  54. data/lib/trak_flow/id_generator.rb +52 -0
  55. data/lib/trak_flow/mcp/resources/base_resource.rb +25 -0
  56. data/lib/trak_flow/mcp/resources/dependency_graph.rb +31 -0
  57. data/lib/trak_flow/mcp/resources/label_list.rb +21 -0
  58. data/lib/trak_flow/mcp/resources/plan_by_id.rb +27 -0
  59. data/lib/trak_flow/mcp/resources/plan_list.rb +21 -0
  60. data/lib/trak_flow/mcp/resources/task_by_id.rb +31 -0
  61. data/lib/trak_flow/mcp/resources/task_list.rb +21 -0
  62. data/lib/trak_flow/mcp/resources/task_next.rb +30 -0
  63. data/lib/trak_flow/mcp/resources/workflow_by_id.rb +27 -0
  64. data/lib/trak_flow/mcp/resources/workflow_list.rb +21 -0
  65. data/lib/trak_flow/mcp/server.rb +140 -0
  66. data/lib/trak_flow/mcp/tools/base_tool.rb +29 -0
  67. data/lib/trak_flow/mcp/tools/comment_add.rb +33 -0
  68. data/lib/trak_flow/mcp/tools/dep_add.rb +34 -0
  69. data/lib/trak_flow/mcp/tools/dep_remove.rb +25 -0
  70. data/lib/trak_flow/mcp/tools/label_add.rb +28 -0
  71. data/lib/trak_flow/mcp/tools/label_remove.rb +25 -0
  72. data/lib/trak_flow/mcp/tools/plan_add_step.rb +35 -0
  73. data/lib/trak_flow/mcp/tools/plan_create.rb +33 -0
  74. data/lib/trak_flow/mcp/tools/plan_run.rb +58 -0
  75. data/lib/trak_flow/mcp/tools/plan_start.rb +58 -0
  76. data/lib/trak_flow/mcp/tools/task_block.rb +27 -0
  77. data/lib/trak_flow/mcp/tools/task_close.rb +26 -0
  78. data/lib/trak_flow/mcp/tools/task_create.rb +51 -0
  79. data/lib/trak_flow/mcp/tools/task_defer.rb +27 -0
  80. data/lib/trak_flow/mcp/tools/task_start.rb +25 -0
  81. data/lib/trak_flow/mcp/tools/task_update.rb +36 -0
  82. data/lib/trak_flow/mcp/tools/workflow_discard.rb +28 -0
  83. data/lib/trak_flow/mcp/tools/workflow_summarize.rb +34 -0
  84. data/lib/trak_flow/mcp.rb +38 -0
  85. data/lib/trak_flow/models/comment.rb +71 -0
  86. data/lib/trak_flow/models/dependency.rb +96 -0
  87. data/lib/trak_flow/models/label.rb +90 -0
  88. data/lib/trak_flow/models/task.rb +188 -0
  89. data/lib/trak_flow/storage/database.rb +638 -0
  90. data/lib/trak_flow/storage/jsonl.rb +259 -0
  91. data/lib/trak_flow/time_parser.rb +15 -0
  92. data/lib/trak_flow/version.rb +5 -0
  93. data/lib/trak_flow.rb +100 -0
  94. data/mkdocs.yml +143 -0
  95. metadata +392 -0
@@ -0,0 +1,349 @@
1
+ # Ruby Library Reference
2
+
3
+ TrakFlow can be used as a Ruby library for programmatic task management.
4
+
5
+ ## Installation
6
+
7
+ ```ruby
8
+ # Gemfile
9
+ gem 'trak_flow'
10
+ ```
11
+
12
+ ## Quick Start
13
+
14
+ ```ruby
15
+ require 'trak_flow'
16
+
17
+ # Initialize with default configuration
18
+ trak = TrakFlow.new
19
+
20
+ # Create a task
21
+ task = trak.create_task(
22
+ title: "Implement feature X",
23
+ type: "feature",
24
+ priority: 1
25
+ )
26
+ puts "Created: #{task.id}"
27
+
28
+ # List open tasks
29
+ tasks = trak.list_tasks(status: "open")
30
+ tasks.each { |t| puts "#{t.id}: #{t.title}" }
31
+
32
+ # Update a task
33
+ trak.start_task(task.id)
34
+ trak.close_task(task.id, summary: "Implemented in PR #42")
35
+ ```
36
+
37
+ ## Configuration
38
+
39
+ ### Default Configuration
40
+
41
+ ```ruby
42
+ trak = TrakFlow.new
43
+ # Uses .trak_flow/ in current directory
44
+ ```
45
+
46
+ ### Custom Configuration
47
+
48
+ ```ruby
49
+ trak = TrakFlow.new(
50
+ data_dir: "/path/to/data",
51
+ config: {
52
+ default_priority: 2,
53
+ gc_retention: "7d"
54
+ }
55
+ )
56
+ ```
57
+
58
+ ### Configuration from File
59
+
60
+ ```ruby
61
+ trak = TrakFlow.from_config("/path/to/config.json")
62
+ ```
63
+
64
+ ## Core Classes
65
+
66
+ ### TrakFlow
67
+
68
+ Main entry point for all operations.
69
+
70
+ ```ruby
71
+ trak = TrakFlow.new(options = {})
72
+ ```
73
+
74
+ #### Task Methods
75
+
76
+ | Method | Description |
77
+ |--------|-------------|
78
+ | `create_task(attrs)` | Create a new task |
79
+ | `find_task(id)` | Find task by ID |
80
+ | `list_tasks(filters)` | List tasks with filters |
81
+ | `update_task(id, attrs)` | Update task attributes |
82
+ | `start_task(id)` | Mark as in_progress |
83
+ | `close_task(id, summary:)` | Mark as closed |
84
+ | `block_task(id, reason:)` | Mark as blocked |
85
+ | `reopen_task(id)` | Reopen closed task |
86
+ | `delete_task(id)` | Delete task |
87
+
88
+ #### Plan Methods
89
+
90
+ | Method | Description |
91
+ |--------|-------------|
92
+ | `create_plan(title, description:)` | Create a Plan |
93
+ | `add_step(plan_id, title, attrs)` | Add step to Plan |
94
+ | `start_plan(plan_id, title:)` | Create persistent Workflow |
95
+ | `execute_plan(plan_id, title:)` | Create ephemeral Workflow |
96
+ | `list_plans` | List all Plans |
97
+ | `list_workflows(plan_id:)` | List Workflows |
98
+
99
+ #### Dependency Methods
100
+
101
+ | Method | Description |
102
+ |--------|-------------|
103
+ | `add_dependency(source, target, type:)` | Add dependency |
104
+ | `remove_dependency(source, target)` | Remove dependency |
105
+ | `ready_tasks(filters)` | Find tasks with no blockers |
106
+ | `dependency_tree(task_id)` | Get dependency tree |
107
+
108
+ #### Label Methods
109
+
110
+ | Method | Description |
111
+ |--------|-------------|
112
+ | `add_label(task_id, label)` | Add label to task |
113
+ | `remove_label(task_id, label)` | Remove label |
114
+ | `labels_for(task_id)` | Get task's labels |
115
+ | `all_labels` | List all labels |
116
+
117
+ ### TrakFlow::Models::Task
118
+
119
+ Represents a task.
120
+
121
+ ```ruby
122
+ task = trak.find_task("tf-abc123")
123
+
124
+ # Properties
125
+ task.id # => "tf-abc123"
126
+ task.title # => "Implement feature"
127
+ task.description # => "Detailed description"
128
+ task.status # => "in_progress"
129
+ task.priority # => 1
130
+ task.type # => "feature"
131
+ task.assignee # => "claude"
132
+ task.parent_id # => nil
133
+ task.created_at # => Time
134
+ task.updated_at # => Time
135
+ task.closed_at # => nil
136
+ task.notes # => "..."
137
+ task.content_hash # => "a1b2c3d4"
138
+
139
+ # Plan/Workflow properties
140
+ task.plan # => false
141
+ task.source_plan_id # => nil
142
+ task.ephemeral # => false
143
+
144
+ # Predicates
145
+ task.open? # => false
146
+ task.closed? # => false
147
+ task.in_progress? # => true
148
+ task.blocked? # => false
149
+ task.plan? # => false
150
+ task.workflow? # => false
151
+ task.ephemeral? # => false
152
+ task.executable? # => true
153
+ task.discardable? # => false
154
+ ```
155
+
156
+ ### TrakFlow::Storage::Database
157
+
158
+ SQLite storage layer.
159
+
160
+ ```ruby
161
+ db = TrakFlow::Storage::Database.new("/path/to/trak_flow.db")
162
+
163
+ # Query methods
164
+ db.find_task(id)
165
+ db.list_tasks(filters)
166
+ db.find_ready_tasks
167
+ db.find_plans
168
+ db.find_workflows(plan_id:)
169
+
170
+ # Write methods
171
+ db.insert_task(task)
172
+ db.update_task(task)
173
+ db.delete_task(id)
174
+
175
+ # Dependency methods
176
+ db.add_dependency(source, target, type)
177
+ db.remove_dependency(source, target)
178
+ db.dependencies_for(task_id)
179
+ ```
180
+
181
+ ### TrakFlow::Storage::Jsonl
182
+
183
+ JSONL file storage.
184
+
185
+ ```ruby
186
+ jsonl = TrakFlow::Storage::Jsonl.new("/path/to/issues.jsonl")
187
+
188
+ # Load all tasks
189
+ tasks = jsonl.load_all
190
+
191
+ # Append a task
192
+ jsonl.append(task)
193
+
194
+ # Rewrite entire file
195
+ jsonl.save_all(tasks)
196
+ ```
197
+
198
+ ## Examples
199
+
200
+ ### Create and Manage Tasks
201
+
202
+ ```ruby
203
+ require 'trak_flow'
204
+
205
+ trak = TrakFlow.new
206
+
207
+ # Create a feature with subtasks
208
+ feature = trak.create_task(
209
+ title: "User Authentication",
210
+ type: "epic",
211
+ priority: 1
212
+ )
213
+
214
+ login = trak.create_task(
215
+ title: "Login page",
216
+ parent_id: feature.id
217
+ )
218
+
219
+ logout = trak.create_task(
220
+ title: "Logout functionality",
221
+ parent_id: feature.id
222
+ )
223
+
224
+ # Add dependencies
225
+ trak.add_dependency(login.id, logout.id)
226
+
227
+ # Find ready work
228
+ ready = trak.ready_tasks
229
+ puts "Ready to work on: #{ready.map(&:title)}"
230
+
231
+ # Complete the workflow
232
+ trak.start_task(login.id)
233
+ trak.close_task(login.id, summary: "Implemented login")
234
+
235
+ # Now logout is ready
236
+ ready = trak.ready_tasks
237
+ puts "Now ready: #{ready.map(&:title)}"
238
+ ```
239
+
240
+ ### Work with Plans
241
+
242
+ ```ruby
243
+ require 'trak_flow'
244
+
245
+ trak = TrakFlow.new
246
+
247
+ # Create a release plan
248
+ plan = trak.create_plan("Release Process")
249
+ trak.add_step(plan.id, "Update version number")
250
+ trak.add_step(plan.id, "Update CHANGELOG")
251
+ trak.add_step(plan.id, "Run tests")
252
+ trak.add_step(plan.id, "Create release tag")
253
+ trak.add_step(plan.id, "Publish gem")
254
+
255
+ # Start a release workflow
256
+ workflow = trak.start_plan(plan.id, title: "Release v1.0.0")
257
+
258
+ # Work through the steps
259
+ workflow.tasks.each do |task|
260
+ puts "Starting: #{task.title}"
261
+ trak.start_task(task.id)
262
+ # ... do the work ...
263
+ trak.close_task(task.id)
264
+ puts "Completed: #{task.title}"
265
+ end
266
+
267
+ # Summarize the workflow
268
+ trak.summarize_workflow(workflow.id, summary: "Released v1.0.0")
269
+ ```
270
+
271
+ ### Filtering and Querying
272
+
273
+ ```ruby
274
+ require 'trak_flow'
275
+
276
+ trak = TrakFlow.new
277
+
278
+ # Filter by multiple criteria
279
+ bugs = trak.list_tasks(
280
+ status: "open",
281
+ type: "bug",
282
+ priority: [0, 1] # Critical or High
283
+ )
284
+
285
+ # Filter by label
286
+ frontend = trak.list_tasks(label: "frontend")
287
+
288
+ # Complex queries using the database directly
289
+ db = trak.database
290
+ high_priority_ready = db.list_tasks.select do |task|
291
+ task.priority <= 1 && db.is_ready?(task.id)
292
+ end
293
+ ```
294
+
295
+ ### Dependency Analysis
296
+
297
+ ```ruby
298
+ require 'trak_flow'
299
+
300
+ trak = TrakFlow.new
301
+
302
+ # Get dependency tree
303
+ tree = trak.dependency_tree("tf-abc123")
304
+
305
+ puts "Blocked by:"
306
+ tree[:blocked_by].each { |t| puts " - #{t.title}" }
307
+
308
+ puts "Blocks:"
309
+ tree[:blocks].each { |t| puts " - #{t.title}" }
310
+
311
+ # Check for cycles
312
+ if trak.would_create_cycle?("tf-a", "tf-b")
313
+ puts "Warning: would create a cycle!"
314
+ end
315
+ ```
316
+
317
+ ## Error Handling
318
+
319
+ ```ruby
320
+ require 'trak_flow'
321
+
322
+ trak = TrakFlow.new
323
+
324
+ begin
325
+ task = trak.find_task("invalid-id")
326
+ rescue TrakFlow::NotFoundError => e
327
+ puts "Task not found: #{e.message}"
328
+ end
329
+
330
+ begin
331
+ trak.create_task(title: "") # Empty title
332
+ rescue TrakFlow::ValidationError => e
333
+ puts "Validation failed: #{e.message}"
334
+ end
335
+
336
+ begin
337
+ trak.add_dependency("tf-a", "tf-a") # Self-reference
338
+ rescue TrakFlow::DependencyError => e
339
+ puts "Invalid dependency: #{e.message}"
340
+ end
341
+ ```
342
+
343
+ ## Thread Safety
344
+
345
+ The library is designed for single-threaded use. For concurrent access:
346
+
347
+ 1. Use separate `TrakFlow` instances per thread
348
+ 2. Or use the MCP server for concurrent access
349
+ 3. The SQLite database handles concurrent reads safely
@@ -0,0 +1,341 @@
1
+ # Task Model Reference
2
+
3
+ The Task model is the core data structure in TrakFlow.
4
+
5
+ ## Class: TrakFlow::Models::Task
6
+
7
+ ### Initialization
8
+
9
+ ```ruby
10
+ task = TrakFlow::Models::Task.new(
11
+ title: "Task title",
12
+ description: "Optional description",
13
+ type: "task",
14
+ priority: 2,
15
+ assignee: nil,
16
+ parent_id: nil,
17
+ plan: false,
18
+ ephemeral: false
19
+ )
20
+ ```
21
+
22
+ ### Attributes
23
+
24
+ #### Required Attributes
25
+
26
+ | Attribute | Type | Description |
27
+ |-----------|------|-------------|
28
+ | `title` | String | Task title (required) |
29
+
30
+ #### Auto-Generated Attributes
31
+
32
+ | Attribute | Type | Description |
33
+ |-----------|------|-------------|
34
+ | `id` | String | Unique ID (e.g., `tf-abc123`) |
35
+ | `created_at` | Time | Creation timestamp |
36
+ | `updated_at` | Time | Last update timestamp |
37
+ | `content_hash` | String | Hash of task content |
38
+
39
+ #### Optional Attributes
40
+
41
+ | Attribute | Type | Default | Description |
42
+ |-----------|------|---------|-------------|
43
+ | `description` | String | `nil` | Detailed description |
44
+ | `status` | String | `"open"` | Current status |
45
+ | `priority` | Integer | `2` | Priority level (0-4) |
46
+ | `type` | String | `"task"` | Task type |
47
+ | `assignee` | String | `nil` | Assigned user/agent |
48
+ | `parent_id` | String | `nil` | Parent task ID |
49
+ | `closed_at` | Time | `nil` | When task was closed |
50
+ | `notes` | String | `""` | Free-form notes |
51
+
52
+ #### Plan/Workflow Attributes
53
+
54
+ | Attribute | Type | Default | Description |
55
+ |-----------|------|---------|-------------|
56
+ | `plan` | Boolean | `false` | Is this a Plan blueprint |
57
+ | `source_plan_id` | String | `nil` | Source Plan for Workflows |
58
+ | `ephemeral` | Boolean | `false` | Is this ephemeral |
59
+
60
+ ### Status Values
61
+
62
+ | Status | Description |
63
+ |--------|-------------|
64
+ | `open` | Ready to work on |
65
+ | `in_progress` | Currently being worked on |
66
+ | `blocked` | Waiting on something |
67
+ | `deferred` | Postponed for later |
68
+ | `closed` | Completed |
69
+ | `tombstone` | Archived (permanent) |
70
+ | `pinned` | Highlighted for visibility |
71
+
72
+ ### Type Values
73
+
74
+ | Type | Description |
75
+ |------|-------------|
76
+ | `task` | General task (default) |
77
+ | `bug` | Bug fix |
78
+ | `feature` | New feature |
79
+ | `epic` | Large initiative |
80
+ | `chore` | Maintenance work |
81
+
82
+ ### Priority Levels
83
+
84
+ | Level | Name | Description |
85
+ |-------|------|-------------|
86
+ | 0 | Critical | Urgent, drop everything |
87
+ | 1 | High | Important, do soon |
88
+ | 2 | Medium | Normal priority (default) |
89
+ | 3 | Low | Do when time permits |
90
+ | 4 | Backlog | Future consideration |
91
+
92
+ ## Predicate Methods
93
+
94
+ ```ruby
95
+ task = TrakFlow::Models::Task.new(title: "Example")
96
+
97
+ # Status predicates
98
+ task.open? # status == "open"
99
+ task.closed? # status == "closed" or "tombstone"
100
+ task.in_progress? # status == "in_progress"
101
+ task.blocked? # status == "blocked"
102
+ task.deferred? # status == "deferred"
103
+
104
+ # Type predicates
105
+ task.bug? # type == "bug"
106
+ task.feature? # type == "feature"
107
+ task.epic? # type == "epic"
108
+ task.chore? # type == "chore"
109
+
110
+ # Plan/Workflow predicates
111
+ task.plan? # plan == true
112
+ task.workflow? # source_plan_id present and not a plan
113
+ task.ephemeral? # ephemeral == true
114
+
115
+ # Capability predicates
116
+ task.executable? # not a plan (can be executed)
117
+ task.discardable? # ephemeral (can be discarded)
118
+ ```
119
+
120
+ ## Instance Methods
121
+
122
+ ### Status Transitions
123
+
124
+ ```ruby
125
+ task.start! # -> in_progress
126
+ task.block! # -> blocked
127
+ task.defer! # -> deferred
128
+ task.close! # -> closed
129
+ task.reopen! # -> open
130
+ task.archive! # -> tombstone
131
+ ```
132
+
133
+ ### Content Management
134
+
135
+ ```ruby
136
+ # Update timestamp
137
+ task.touch!
138
+
139
+ # Append to notes with trace entry
140
+ task.append_trace("STARTED", "Beginning implementation")
141
+ # Adds: [2024-01-15T10:00:00Z] [STARTED] Beginning implementation
142
+
143
+ # Compute content hash
144
+ task.compute_hash!
145
+ ```
146
+
147
+ ### Serialization
148
+
149
+ ```ruby
150
+ # Convert to Hash
151
+ hash = task.to_h
152
+
153
+ # Convert to JSON
154
+ json = task.to_json
155
+
156
+ # Create from Hash
157
+ task = TrakFlow::Models::Task.from_hash(hash)
158
+
159
+ # Create from JSON
160
+ task = TrakFlow::Models::Task.from_json(json)
161
+ ```
162
+
163
+ ## Validation
164
+
165
+ Tasks are validated on creation and update:
166
+
167
+ ```ruby
168
+ task = TrakFlow::Models::Task.new(title: "")
169
+ task.valid? # => false
170
+ task.errors # => ["Title is required"]
171
+
172
+ task = TrakFlow::Models::Task.new(
173
+ title: "Test",
174
+ status: "invalid"
175
+ )
176
+ task.valid? # => false
177
+ task.errors # => ["Invalid status: invalid"]
178
+ ```
179
+
180
+ ### Validation Rules
181
+
182
+ | Rule | Error Message |
183
+ |------|---------------|
184
+ | Title required | "Title is required" |
185
+ | Valid status | "Invalid status: {status}" |
186
+ | Valid priority | "Invalid priority: {priority}" |
187
+ | Valid type | "Invalid type: {type}" |
188
+ | Plans can't be ephemeral | "Plans cannot be ephemeral" |
189
+ | Plans stay open | "Plans cannot change status" |
190
+ | Plans can't derive from Plans | "Plans cannot be derived from other Plans" |
191
+
192
+ ## ID Generation
193
+
194
+ IDs are generated using content hashing:
195
+
196
+ ```ruby
197
+ task = TrakFlow::Models::Task.new(title: "Example")
198
+ task.generate_id!
199
+ task.id # => "tf-a1b2c3d4"
200
+ ```
201
+
202
+ The ID is derived from:
203
+ - Title
204
+ - Description
205
+ - Type
206
+ - Creation timestamp
207
+ - Random salt (for uniqueness)
208
+
209
+ ### ID Format
210
+
211
+ ```
212
+ tf-xxxxxxxx
213
+ ```
214
+
215
+ - `tf-` prefix identifies TrakFlow tasks
216
+ - 8 character hex hash
217
+
218
+ ## JSON Representation
219
+
220
+ ```json
221
+ {
222
+ "id": "tf-abc123",
223
+ "title": "Implement feature X",
224
+ "description": "Detailed description here",
225
+ "status": "in_progress",
226
+ "priority": 1,
227
+ "type": "feature",
228
+ "assignee": "claude",
229
+ "parent_id": null,
230
+ "created_at": "2024-01-15T10:00:00Z",
231
+ "updated_at": "2024-01-15T14:30:00Z",
232
+ "closed_at": null,
233
+ "content_hash": "a1b2c3d4",
234
+ "plan": false,
235
+ "source_plan_id": null,
236
+ "ephemeral": false,
237
+ "notes": ""
238
+ }
239
+ ```
240
+
241
+ ## Content Hash
242
+
243
+ The content hash enables:
244
+
245
+ 1. **Change detection** - Know when content was modified
246
+ 2. **Deduplication** - Identify identical tasks
247
+ 3. **Sync support** - Merge changes from multiple sources
248
+
249
+ ### Hash Computation
250
+
251
+ ```ruby
252
+ # Automatically computed on save
253
+ task.compute_hash!
254
+
255
+ # Hash is based on:
256
+ # - title
257
+ # - description
258
+ # - type
259
+ # - priority
260
+ # - assignee
261
+ # - status
262
+ # - parent_id
263
+ # - plan
264
+ # - source_plan_id
265
+ # - ephemeral
266
+ # - notes
267
+
268
+ # Excluded from hash:
269
+ # - id
270
+ # - created_at
271
+ # - updated_at
272
+ # - closed_at
273
+ # - content_hash itself
274
+ ```
275
+
276
+ ## Examples
277
+
278
+ ### Creating Different Task Types
279
+
280
+ ```ruby
281
+ # Bug
282
+ bug = TrakFlow::Models::Task.new(
283
+ title: "Fix null pointer exception",
284
+ type: "bug",
285
+ priority: 0
286
+ )
287
+
288
+ # Feature
289
+ feature = TrakFlow::Models::Task.new(
290
+ title: "Add OAuth support",
291
+ type: "feature",
292
+ priority: 1,
293
+ description: "Support Google and GitHub OAuth"
294
+ )
295
+
296
+ # Epic with children
297
+ epic = TrakFlow::Models::Task.new(
298
+ title: "User Management",
299
+ type: "epic"
300
+ )
301
+
302
+ child = TrakFlow::Models::Task.new(
303
+ title: "Login page",
304
+ parent_id: epic.id
305
+ )
306
+ ```
307
+
308
+ ### Creating a Plan
309
+
310
+ ```ruby
311
+ plan = TrakFlow::Models::Task.new(
312
+ title: "Deploy Checklist",
313
+ plan: true
314
+ )
315
+
316
+ plan.plan? # => true
317
+ plan.executable? # => false
318
+ ```
319
+
320
+ ### Status Workflow
321
+
322
+ ```ruby
323
+ task = TrakFlow::Models::Task.new(title: "Example")
324
+
325
+ task.status # => "open"
326
+
327
+ task.start!
328
+ task.status # => "in_progress"
329
+
330
+ task.block!
331
+ task.status # => "blocked"
332
+ task.notes # Contains trace entry
333
+
334
+ task.reopen!
335
+ task.status # => "open"
336
+
337
+ task.start!
338
+ task.close!
339
+ task.status # => "closed"
340
+ task.closed_at # => Time.now
341
+ ```