1use clap::{Parser, Subcommand};
2
3#[derive(Parser)]
4#[command(name = "td", version, about = "Todo tracker for AI agents")]
5pub struct Cli {
6 /// Output JSON
7 #[arg(short = 'j', long = "json", global = true)]
8 pub json: bool,
9
10 #[command(subcommand)]
11 pub command: Command,
12}
13
14#[derive(Subcommand)]
15pub enum Command {
16 /// Initialize .td directory
17 Init {
18 /// Add .td/ to .gitignore
19 #[arg(long)]
20 stealth: bool,
21 },
22
23 /// Create a new task
24 #[command(visible_alias = "add")]
25 Create {
26 /// Task title
27 title: Option<String>,
28
29 /// Priority (low, medium, high)
30 #[arg(short, long, default_value = "medium")]
31 priority: String,
32
33 /// Effort (low, medium, high)
34 #[arg(short, long, default_value = "medium")]
35 effort: String,
36
37 /// Task type
38 #[arg(short = 't', long = "type", default_value = "task")]
39 task_type: String,
40
41 /// Description
42 #[arg(short = 'd', long = "desc")]
43 desc: Option<String>,
44
45 /// Parent task ID (creates a subtask)
46 #[arg(long)]
47 parent: Option<String>,
48
49 /// Labels (comma-separated)
50 #[arg(short, long)]
51 labels: Option<String>,
52 },
53
54 /// List tasks
55 #[command(visible_alias = "ls")]
56 List {
57 /// Filter by status
58 #[arg(short, long)]
59 status: Option<String>,
60
61 /// Filter by priority (low, medium, high)
62 #[arg(short, long)]
63 priority: Option<String>,
64
65 /// Filter by effort (low, medium, high)
66 #[arg(short, long)]
67 effort: Option<String>,
68
69 /// Filter by label
70 #[arg(short, long)]
71 label: Option<String>,
72 },
73
74 /// Show task details
75 Show {
76 /// Task ID
77 id: String,
78 },
79
80 /// Update a task
81 Update {
82 /// Task ID
83 id: String,
84
85 /// Set status
86 #[arg(short, long)]
87 status: Option<String>,
88
89 /// Set priority (low, medium, high)
90 #[arg(short, long)]
91 priority: Option<String>,
92
93 /// Set effort (low, medium, high)
94 #[arg(short, long)]
95 effort: Option<String>,
96
97 /// Set title
98 #[arg(short = 't', long)]
99 title: Option<String>,
100
101 /// Set description
102 #[arg(short = 'd', long = "desc")]
103 desc: Option<String>,
104 },
105
106 /// Mark task(s) as closed
107 #[command(visible_alias = "close")]
108 Done {
109 /// Task IDs
110 #[arg(required = true)]
111 ids: Vec<String>,
112 },
113
114 /// Reopen task(s)
115 Reopen {
116 /// Task IDs
117 #[arg(required = true)]
118 ids: Vec<String>,
119 },
120
121 /// Manage dependencies / blockers
122 Dep {
123 #[command(subcommand)]
124 action: DepAction,
125 },
126
127 /// Manage labels
128 Label {
129 #[command(subcommand)]
130 action: LabelAction,
131 },
132
133 /// Search tasks by title or description
134 Search {
135 /// Search query
136 query: String,
137 },
138
139 /// Show tasks with no open blockers
140 Ready,
141
142 /// Recommend next task(s) to work on
143 Next {
144 /// Scoring strategy: impact (default) or effort
145 #[arg(short, long, default_value = "impact")]
146 mode: String,
147
148 /// Show signal breakdown and equation
149 #[arg(short, long)]
150 verbose: bool,
151
152 /// Maximum number of results
153 #[arg(short = 'n', long = "limit", default_value = "5")]
154 limit: usize,
155 },
156
157 /// Show task statistics (always JSON)
158 Stats,
159
160 /// Vacuum the database
161 Compact,
162
163 /// Export tasks to JSONL (one JSON object per line)
164 Export,
165
166 /// Import tasks from a JSONL file
167 Import {
168 /// Path to JSONL file (- for stdin)
169 file: String,
170 },
171
172 /// Install the agent skill file (SKILL.md)
173 Skill {
174 /// Skills directory (writes managing-tasks-with-td/SKILL.md inside)
175 #[arg(long)]
176 dir: Option<String>,
177 },
178}
179
180#[derive(Subcommand)]
181pub enum DepAction {
182 /// Add a dependency (child is blocked by parent)
183 Add {
184 /// Task that is blocked
185 child: String,
186 /// Task that blocks it
187 parent: String,
188 },
189 /// Remove a dependency
190 Rm {
191 /// Task that was blocked
192 child: String,
193 /// Task that was blocking
194 parent: String,
195 },
196 /// Show child tasks
197 Tree {
198 /// Parent task ID
199 id: String,
200 },
201}
202
203#[derive(Subcommand)]
204pub enum LabelAction {
205 /// Add a label to a task
206 Add {
207 /// Task ID
208 id: String,
209 /// Label to add
210 label: String,
211 },
212 /// Remove a label from a task
213 Rm {
214 /// Task ID
215 id: String,
216 /// Label to remove
217 label: String,
218 },
219 /// List labels on a task
220 List {
221 /// Task ID
222 id: String,
223 },
224 /// List all distinct labels
225 ListAll,
226}