@krodak/clickup-cli 0.14.0 → 0.15.0

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.
package/README.md CHANGED
@@ -8,547 +8,218 @@
8
8
  [![CI](https://github.com/krodak/clickup-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/krodak/clickup-cli/actions/workflows/ci.yml)
9
9
 
10
10
  ```bash
11
- npm install -g @krodak/clickup-cli # or: brew tap krodak/tap && brew install clickup-cli
12
- cu init # walks you through API token + workspace setup
11
+ npm install -g @krodak/clickup-cli && cu init
13
12
  ```
14
13
 
15
- You need a ClickUp personal API token (`pk_...` from https://app.clickup.com/settings/apps).
14
+ ## Talk to your agent
16
15
 
17
- ## Using with AI agents
16
+ Install `cu`, install the skill file, and your agent works with ClickUp. No API knowledge needed.
18
17
 
19
- This is the primary use case. Install the tool, install the skill file, and your agent knows how to work with ClickUp.
18
+ > **"Read task abc123, do the work, then mark it in review and leave a comment with the commit hash."**
20
19
 
21
- ### 1. Install the skill
20
+ > **"What's my standup? What did I finish, what's in progress, what's overdue?"**
22
21
 
23
- The repo includes a skill file at `skills/clickup-cli/SKILL.md` that teaches agents all available commands and when to use them. It's also packaged as a Claude Code plugin.
22
+ > **"Create a subtask under the initiative for the edge case we found."**
24
23
 
25
- **Claude Code (plugin - recommended):**
24
+ > **"Check my sprint and tell me what's behind schedule."**
26
25
 
27
- The repo ships as a Claude Code plugin. Point Claude Code at the repo or installed npm package:
26
+ > **"Update the description with your findings and flag blockers in a comment."**
28
27
 
29
- ```bash
30
- claude --plugin-dir ./node_modules/@krodak/clickup-cli
31
- ```
32
-
33
- Or copy the skill manually:
34
-
35
- ```bash
36
- mkdir -p ~/.claude/skills/clickup
37
- cp skills/clickup-cli/SKILL.md ~/.claude/skills/clickup/SKILL.md
38
- ```
39
-
40
- Then reference it in your `CLAUDE.md` or project instructions.
41
-
42
- **OpenCode:**
43
-
44
- ```bash
45
- mkdir -p ~/.config/opencode/skills/clickup
46
- cp skills/clickup-cli/SKILL.md ~/.config/opencode/skills/clickup/SKILL.md
47
- ```
48
-
49
- **Codex / other agents:**
50
-
51
- Copy the contents of `skills/clickup-cli/SKILL.md` into your system prompt or project instructions. It's a standalone markdown document.
52
-
53
- ### 2. Talk to your agent
54
-
55
- Once the skill is installed, you just tell the agent what you need in plain language. It figures out which `cu` commands to run.
56
-
57
- ```
58
- "Read the description of task <id>, do the work, then mark it in review and leave a comment with the commit hash."
59
-
60
- "Check all subtasks under initiative <id> and improve their descriptions based on what's in the codebase."
61
-
62
- "What's my standup summary? What did I finish yesterday, what's in progress, what's overdue?"
28
+ The agent reads the skill file, picks the right `cu` commands, and handles everything. You don't need to learn the CLI - the agent does.
63
29
 
64
- "Do exploratory work for task <id>, update the description with your findings, and flag blockers in a comment."
30
+ ## Setup
65
31
 
66
- "Create a subtask under <id> for the edge case we just found."
32
+ You need Node 22+ and a ClickUp personal API token (`pk_...` from [ClickUp Settings > Apps](https://app.clickup.com/settings/apps)).
67
33
 
68
- "Check my sprint and tell me what's overdue."
69
- ```
70
-
71
- You don't need to learn the CLI commands yourself. The agent handles it.
72
-
73
- ### Why a CLI and not MCP?
74
-
75
- A CLI + skill file has fewer moving parts. No extra server process, no protocol layer. The agent already knows how to run shell commands - the skill file just teaches it which ones exist. This matches what Peter Steinberger and the OpenClaw project have found: for tool-use with coding agents, CLI + instructions tends to work better than MCP in practice.
76
-
77
- ### Scoped output
78
-
79
- Most commands return only your tasks by default. `cu tasks`, `cu sprint`, `cu overdue`, `cu summary` all scope to what's assigned to you. `cu spaces --my` filters to spaces where you have tasks. This keeps output small and relevant - important when it's going into an agent's context window.
80
-
81
- ## Using from the terminal
82
-
83
- When you run `cu` in a terminal directly, you get an interactive mode with tables and a task picker.
84
-
85
- ```bash
86
- cu tasks # interactive table with checkbox picker
87
- cu sprint # your sprint tasks, auto-detected
88
- cu summary # standup helper: completed / in progress / overdue
89
- cu overdue # tasks past their due date
90
- cu open "login bug" # fuzzy search, opens in browser
91
- cu update abc123 -s "done" # update status
92
- cu assign abc123 --to me # assign yourself
93
- ```
34
+ <details open>
35
+ <summary>&nbsp;<img src="https://cdn.simpleicons.org/openai/999999" height="16" align="center">&nbsp;<strong>OpenCode</strong></summary>
94
36
 
95
- Pass `--json` to any read command to force JSON output instead of the default format.
96
-
97
- When output is piped (no TTY), all commands output **Markdown** by default - optimized for AI agent context windows. Pass `--json` to any command for JSON output. Set `CU_OUTPUT=json` environment variable to always get JSON when piped.
98
-
99
- ## Commands
100
-
101
- 31 commands total. All support `--help` for full flag details.
102
-
103
- ### `cu init`
104
-
105
- First-time setup. Prompts for your API token, verifies it, auto-detects your workspace, and writes `~/.config/cu/config.json`.
37
+ **1. Install the CLI**
106
38
 
107
39
  ```bash
40
+ npm install -g @krodak/clickup-cli
108
41
  cu init
109
42
  ```
110
43
 
111
- ### `cu tasks`
112
-
113
- List tasks assigned to me. By default shows all task types. Use `--type` to filter by task type.
114
-
115
- ```bash
116
- cu tasks
117
- cu tasks --status "in progress"
118
- cu tasks --name "login"
119
- cu tasks --type task # regular tasks only
120
- cu tasks --type initiative # initiatives only
121
- cu tasks --type "Bug" # custom task type by name
122
- cu tasks --list <listId>
123
- cu tasks --space <spaceId>
124
- cu tasks --include-closed
125
- cu tasks --json
126
- ```
127
-
128
- ### `cu sprint`
129
-
130
- List my tasks in the currently active sprint (auto-detected from sprint folder date ranges).
131
-
132
- ```bash
133
- cu sprint
134
- cu sprint --status "in progress"
135
- cu sprint --include-closed
136
- cu sprint --json
137
- ```
138
-
139
- ### `cu sprints`
140
-
141
- List all sprints across sprint folders. Marks the currently active sprint.
142
-
143
- ```bash
144
- cu sprints
145
- cu sprints --space "Engineering"
146
- cu sprints --json
147
- ```
148
-
149
- ### `cu assigned`
150
-
151
- All tasks assigned to me, grouped by pipeline stage (code review, in progress, to do, etc.).
152
-
153
- ```bash
154
- cu assigned
155
- cu assigned --status "in progress"
156
- cu assigned --include-closed
157
- cu assigned --json
158
- ```
159
-
160
- ### `cu inbox`
161
-
162
- Tasks assigned to me that were recently updated, grouped by time period (today, yesterday, last 7 days, etc.). Default lookback is 30 days.
163
-
164
- ```bash
165
- cu inbox
166
- cu inbox --days 7
167
- cu inbox --include-closed
168
- cu inbox --json
169
- ```
170
-
171
- ### `cu task <id>`
172
-
173
- Get task details including custom fields and checklists. Pretty summary in terminal, JSON when piped.
174
-
175
- ```bash
176
- cu task abc123
177
- cu task abc123 --json
178
- ```
179
-
180
- **Note:** When piped, `cu task` outputs a structured Markdown summary of the task. For the full raw API response with all fields (custom fields, checklists, etc.), use `--json`.
181
-
182
- ### `cu subtasks <id>`
183
-
184
- List subtasks of a task.
185
-
186
- ```bash
187
- cu subtasks abc123
188
- cu subtasks abc123 --status "in progress"
189
- cu subtasks abc123 --name "auth"
190
- cu subtasks abc123 --include-closed
191
- cu subtasks abc123 --json
192
- ```
193
-
194
- ### `cu update <id>`
195
-
196
- Update a task. Provide at least one option.
197
-
198
- ```bash
199
- cu update abc123 -s "in progress"
200
- cu update abc123 -n "New task name"
201
- cu update abc123 -d "Updated description with **markdown**"
202
- cu update abc123 --priority high
203
- cu update abc123 --due-date 2025-03-15
204
- cu update abc123 --assignee me
205
- cu update abc123 --assignee 12345
206
- cu update abc123 -n "New name" -s "done" --priority urgent
207
- cu update abc123 --time-estimate 2h
208
- cu update abc123 --parent parentTaskId # make it a subtask
209
- cu update abc123 -s "in progress" --json
210
- ```
211
-
212
- | Flag | Description |
213
- | ---------------------------- | --------------------------------------------------------------------------- |
214
- | `-n, --name <text>` | New task name |
215
- | `-d, --description <text>` | New description (markdown supported) |
216
- | `-s, --status <status>` | New status, supports fuzzy matching (e.g. `"prog"` matches `"in progress"`) |
217
- | `--priority <level>` | Priority: `urgent`, `high`, `normal`, `low` (or 1-4) |
218
- | `--due-date <date>` | Due date (`YYYY-MM-DD`) |
219
- | `--time-estimate <duration>` | Time estimate (e.g. `"2h"`, `"30m"`, `"1h30m"`) |
220
- | `--assignee <userId>` | Add assignee by user ID or `"me"` |
221
- | `--parent <taskId>` | Set parent task (makes this a subtask) |
222
- | `--json` | Force JSON output even in terminal |
223
-
224
- ### `cu create`
225
-
226
- Create a new task. If `--parent` is given, list is auto-detected from the parent task.
227
-
228
- ```bash
229
- cu create -n "Fix login bug" -l <listId>
230
- cu create -n "Subtask name" -p <parentTaskId> # --list auto-detected
231
- cu create -n "Task" -l <listId> -d "desc" -s "open"
232
- cu create -n "Task" -l <listId> --priority high --due-date 2025-06-01
233
- cu create -n "Task" -l <listId> --assignee me --tags "bug,frontend"
234
- cu create -n "Initiative" -l <listId> --custom-item-id 1
235
- cu create -n "Task" -l <listId> --time-estimate 2h
236
- cu create -n "Fix bug" -l <listId> --json
237
- ```
238
-
239
- | Flag | Required | Description |
240
- | ---------------------------- | ---------------- | ---------------------------------------------------- |
241
- | `-n, --name <name>` | yes | Task name |
242
- | `-l, --list <listId>` | if no `--parent` | Target list ID |
243
- | `-p, --parent <taskId>` | no | Parent task (list auto-detected) |
244
- | `-d, --description <text>` | no | Description (markdown) |
245
- | `-s, --status <status>` | no | Initial status |
246
- | `--priority <level>` | no | Priority: `urgent`, `high`, `normal`, `low` (or 1-4) |
247
- | `--due-date <date>` | no | Due date (`YYYY-MM-DD`) |
248
- | `--time-estimate <duration>` | no | Time estimate (e.g. `"2h"`, `"30m"`, `"1h30m"`) |
249
- | `--assignee <userId>` | no | Assignee by user ID or `"me"` |
250
- | `--tags <tags>` | no | Comma-separated tag names |
251
- | `--custom-item-id <id>` | no | Custom task type ID (e.g. for creating initiatives) |
252
- | `--json` | no | Force JSON output even in terminal |
253
-
254
- ### `cu delete <id>`
255
-
256
- Delete a task. **DESTRUCTIVE - cannot be undone.**
257
-
258
- ```bash
259
- cu delete abc123
260
- cu delete abc123 --confirm
261
- cu delete abc123 --confirm --json
262
- ```
263
-
264
- In TTY mode without `--confirm`: shows the task name and prompts for confirmation (default: No). In non-interactive/piped mode, `--confirm` is required.
265
-
266
- | Flag | Description |
267
- | ----------- | ----------------------------------------------------------- |
268
- | `--confirm` | Skip confirmation prompt (required in non-interactive mode) |
269
- | `--json` | Force JSON output |
270
-
271
- ### `cu field <id>`
272
-
273
- Set or remove a custom field value. Field names are resolved case-insensitively; errors list available fields/options.
274
-
275
- ```bash
276
- cu field abc123 --set "Priority Level" high
277
- cu field abc123 --set "Story Points" 5
278
- cu field abc123 --set "Approved" true
279
- cu field abc123 --set "Category" "Bug Fix"
280
- cu field abc123 --set "Due" 2025-06-01
281
- cu field abc123 --set "Website" "https://example.com"
282
- cu field abc123 --set "Contact" "user@example.com"
283
- cu field abc123 --remove "Priority Level"
284
- cu field abc123 --set "Points" 3 --remove "Old Field"
285
- cu field abc123 --set "Points" 3 --json
286
- ```
287
-
288
- | Flag | Description |
289
- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
290
- | `--set "Field Name" <val>` | Set a custom field by name. Supports: text, number, checkbox (true/false), dropdown (option name), date (YYYY-MM-DD), url, email |
291
- | `--remove "Field Name"` | Remove a custom field value |
292
- | `--json` | Force JSON output |
293
-
294
- Both `--set` and `--remove` can be used together in one invocation.
295
-
296
- ### `cu comment <id>`
297
-
298
- Post a comment on a task.
299
-
300
- ```bash
301
- cu comment abc123 -m "Addressed in PR #42"
302
- cu comment abc123 -m "Done" --json
303
- ```
304
-
305
- ### `cu comments <id>`
306
-
307
- List comments on a task. Formatted view in terminal, JSON when piped.
308
-
309
- ```bash
310
- cu comments abc123
311
- cu comments abc123 --json
312
- ```
313
-
314
- ### `cu comment-edit <commentId>`
315
-
316
- Edit an existing comment on a task.
317
-
318
- ```bash
319
- cu comment-edit <commentId> -m "Updated text"
320
- cu comment-edit <commentId> -m "Fixed" --resolved
321
- cu comment-edit <commentId> -m "Reopening" --unresolved
322
- cu comment-edit <commentId> -m "Updated" --json
323
- ```
324
-
325
- | Flag | Required | Description |
326
- | --------------- | -------- | -------------------------- |
327
- | `-m, --message` | yes | New comment text |
328
- | `--resolved` | no | Mark comment as resolved |
329
- | `--unresolved` | no | Mark comment as unresolved |
330
- | `--json` | no | Force JSON output |
331
-
332
- ### `cu activity <id>`
333
-
334
- View task details and comment history together. Combines `cu task` and `cu comments` into a single view.
335
-
336
- ```bash
337
- cu activity abc123
338
- cu activity abc123 --json
339
- ```
340
-
341
- ### `cu lists <spaceId>`
342
-
343
- List all lists in a space, including lists inside folders. Useful for discovering list IDs needed by `--list` filter and `cu create -l`.
44
+ **2. Install the skill**
344
45
 
345
46
  ```bash
346
- cu lists <spaceId>
347
- cu lists <spaceId> --name "sprint"
348
- cu lists <spaceId> --json
349
- ```
350
-
351
- | Flag | Description |
352
- | ------------------ | ---------------------------------- |
353
- | `--name <partial>` | Filter lists by partial name match |
354
- | `--json` | Force JSON output |
355
-
356
- ### `cu spaces`
357
-
358
- List spaces in your workspace. Useful for getting space IDs for the `--space` filter.
359
-
360
- ```bash
361
- cu spaces
362
- cu spaces --name "eng"
363
- cu spaces --my
364
- cu spaces --json
365
- ```
366
-
367
- | Flag | Description |
368
- | ------------------ | -------------------------------------------- |
369
- | `--name <partial>` | Filter spaces by partial name match |
370
- | `--my` | Show only spaces where I have assigned tasks |
371
- | `--json` | Force JSON output |
372
-
373
- ### `cu open <query>`
374
-
375
- Open a task in the browser. Accepts a task ID or partial name.
376
-
377
- ```bash
378
- cu open abc123
379
- cu open "login bug"
380
- cu open abc123 --json
381
- ```
382
-
383
- If the query matches multiple tasks by name, all matches are listed and the first is opened.
384
-
385
- ### `cu search <query>`
386
-
387
- Search my tasks by name. Supports multi-word queries with case-insensitive matching. Status filter supports fuzzy matching.
388
-
389
- ```bash
390
- cu search "login bug"
391
- cu search auth
392
- cu search "payment flow" --json
393
- cu search auth --status "prog" # fuzzy matches "in progress"
394
- cu search "old task" --include-closed
395
- ```
396
-
397
- ### `cu summary`
398
-
399
- Daily standup helper. Shows tasks grouped into: recently completed, in progress, and overdue.
400
-
401
- ```bash
402
- cu summary
403
- cu summary --hours 48
404
- cu summary --json
47
+ mkdir -p ~/.config/opencode/skills/clickup
48
+ cp $(npm root -g)/@krodak/clickup-cli/skills/clickup-cli/SKILL.md ~/.config/opencode/skills/clickup/SKILL.md
405
49
  ```
406
50
 
407
- | Flag | Description |
408
- | ------------- | -------------------------------------------------- |
409
- | `--hours <n>` | Lookback for recently completed tasks (default 24) |
410
- | `--json` | Force JSON output |
51
+ </details>
411
52
 
412
- ### `cu overdue`
53
+ <details>
54
+ <summary>&nbsp;<img src="https://cdn.simpleicons.org/anthropic/D97757" height="16" align="center">&nbsp;<strong>Claude Code</strong></summary>
413
55
 
414
- List tasks that are past their due date (excludes done/closed tasks by default). Sorted most overdue first.
56
+ **1. Install the CLI**
415
57
 
416
58
  ```bash
417
- cu overdue
418
- cu overdue --include-closed
419
- cu overdue --json
420
- ```
421
-
422
- ### `cu assign <id>`
423
-
424
- Assign or unassign users from a task. Supports `me` as shorthand for your user ID.
425
-
426
- ```bash
427
- cu assign abc123 --to 12345
428
- cu assign abc123 --to me
429
- cu assign abc123 --remove 12345
430
- cu assign abc123 --to me --remove 67890
431
- cu assign abc123 --to me --json
59
+ npm install -g @krodak/clickup-cli
60
+ cu init
432
61
  ```
433
62
 
434
- | Flag | Description |
435
- | ------------------- | --------------------------------- |
436
- | `--to <userId>` | Add assignee (user ID or `me`) |
437
- | `--remove <userId>` | Remove assignee (user ID or `me`) |
438
- | `--json` | Force JSON output |
439
-
440
- ### `cu depend <id>`
441
-
442
- Add or remove task dependencies. Set a task as waiting on or blocking another task.
63
+ **2. Install the skill**
443
64
 
444
65
  ```bash
445
- cu depend abc123 --on def456 # abc123 depends on (waits for) def456
446
- cu depend abc123 --blocks def456 # abc123 blocks def456
447
- cu depend abc123 --on def456 --remove # remove the dependency
448
- cu depend abc123 --blocks def456 --remove
449
- cu depend abc123 --on def456 --json
66
+ mkdir -p ~/.claude/skills/clickup
67
+ cp $(npm root -g)/@krodak/clickup-cli/skills/clickup-cli/SKILL.md ~/.claude/skills/clickup/SKILL.md
450
68
  ```
451
69
 
452
- | Flag | Description |
453
- | ------------------- | ------------------------------------------- |
454
- | `--on <taskId>` | Task that this task depends on (waiting on) |
455
- | `--blocks <taskId>` | Task that this task blocks |
456
- | `--remove` | Remove the dependency instead of adding it |
457
- | `--json` | Force JSON output |
458
-
459
- ### `cu move <id>`
460
-
461
- Add or remove a task from a list. Tasks can belong to multiple lists in ClickUp.
70
+ Then reference it in your `CLAUDE.md` or project instructions.
462
71
 
463
- ```bash
464
- cu move abc123 --to <listId> # add task to a list
465
- cu move abc123 --remove <listId> # remove task from a list
466
- cu move abc123 --to <newListId> --remove <oldListId> # move between lists
467
- cu move abc123 --to <listId> --json
468
- ```
72
+ </details>
469
73
 
470
- | Flag | Description |
471
- | ------------------- | -------------------------- |
472
- | `--to <listId>` | Add task to this list |
473
- | `--remove <listId>` | Remove task from this list |
474
- | `--json` | Force JSON output |
74
+ <details>
75
+ <summary>&nbsp;<img src="https://cdn.simpleicons.org/anthropic/D97757" height="16" align="center">&nbsp;<strong>Claude Desktop</strong></summary>
475
76
 
476
- ### `cu tag <id>`
77
+ Claude Desktop doesn't run CLI tools directly. Use it alongside a coding agent (Claude Code, OpenCode) that has `cu` installed, or run `cu` commands manually in your terminal.
477
78
 
478
- Add or remove tags on a task. Both `--add` and `--remove` can be used together.
79
+ **Install the CLI:**
479
80
 
480
81
  ```bash
481
- cu tag abc123 --add "bug"
482
- cu tag abc123 --add "bug,frontend,urgent"
483
- cu tag abc123 --remove "wontfix"
484
- cu tag abc123 --add "bug" --remove "triage"
485
- cu tag abc123 --add "bug" --json
82
+ npm install -g @krodak/clickup-cli
83
+ cu init
486
84
  ```
487
85
 
488
- | Flag | Description |
489
- | ----------------- | ----------------------------------- |
490
- | `--add <tags>` | Comma-separated tag names to add |
491
- | `--remove <tags>` | Comma-separated tag names to remove |
492
- | `--json` | Force JSON output |
493
-
494
- ### `cu checklist`
86
+ </details>
495
87
 
496
- Manage checklists on tasks. Six subcommands for full CRUD operations.
88
+ <details>
89
+ <summary>&nbsp;<img src="https://cdn.simpleicons.org/homebrew/FBB040" height="16" align="center">&nbsp;<strong>Homebrew</strong></summary>
497
90
 
498
91
  ```bash
499
- cu checklist view abc123 # view all checklists on a task
500
- cu checklist create abc123 "QA Checklist" # add a checklist
501
- cu checklist delete <checklistId> # remove a checklist
502
- cu checklist add-item <checklistId> "Run tests" # add an item
503
- cu checklist edit-item <clId> <itemId> --resolved # mark item done
504
- cu checklist delete-item <clId> <itemId> # remove an item
92
+ brew tap krodak/tap
93
+ brew install clickup-cli
94
+ cu init
505
95
  ```
506
96
 
507
- | Subcommand | Arguments | Description |
508
- | ------------- | -------------------------------- | --------------------- |
509
- | `view` | `<taskId>` | Show all checklists |
510
- | `create` | `<taskId> <name>` | Create a checklist |
511
- | `delete` | `<checklistId>` | Delete a checklist |
512
- | `add-item` | `<checklistId> <name>` | Add checklist item |
513
- | `edit-item` | `<checklistId> <itemId> [flags]` | Edit checklist item |
514
- | `delete-item` | `<checklistId> <itemId>` | Delete checklist item |
97
+ Then install the skill for your agent (see OpenCode or Claude Code sections above).
515
98
 
516
- `edit-item` flags: `--name <text>`, `--resolved`, `--unresolved`, `--assignee <userId>`. All subcommands support `--json`.
99
+ </details>
517
100
 
518
- Checklists are also shown inline in `cu task <id>` detail view.
101
+ <details>
102
+ <summary>&nbsp;<img src="https://cdn.simpleicons.org/openai/999999" height="16" align="center">&nbsp;<strong>Codex / Other agents</strong></summary>
519
103
 
520
- ### `cu auth`
521
-
522
- Check authentication status. Validates your API token and shows your user info.
104
+ **1. Install the CLI**
523
105
 
524
106
  ```bash
525
- cu auth
526
- cu auth --json
527
- ```
528
-
529
- ### `cu config`
530
-
531
- Manage CLI configuration.
532
-
533
- ```bash
534
- cu config get apiToken
535
- cu config set teamId 12345
536
- cu config path
107
+ npm install -g @krodak/clickup-cli
108
+ cu init
537
109
  ```
538
110
 
539
- Valid keys: `apiToken`, `teamId`. Setting `apiToken` validates the `pk_` prefix.
111
+ **2. Add the skill to your agent**
540
112
 
541
- ### `cu completion <shell>`
113
+ Copy `skills/clickup-cli/SKILL.md` into your agent's system prompt or project instructions. It's a standalone markdown document that teaches the agent all available commands.
542
114
 
543
- Output shell completion script. Supports `bash`, `zsh`, and `fish`.
115
+ </details>
544
116
 
545
- ```bash
546
- eval "$(cu completion bash)" # Bash
547
- eval "$(cu completion zsh)" # Zsh
548
- cu completion fish > ~/.config/fish/completions/cu.fish # Fish
549
- ```
117
+ ## Commands
550
118
 
551
- ## Config
119
+ 36 commands total. [Full reference with examples and flags](docs/commands.md).
120
+
121
+ ### Tasks
122
+
123
+ | Command | Description |
124
+ | --------------------- | ----------------------------------------------------------- |
125
+ | `cu tasks` | List my tasks (filter by status, name, type, list, space) |
126
+ | `cu task <id>` | Task details with custom fields and checklists |
127
+ | `cu subtasks <id>` | List subtasks of a task |
128
+ | `cu create` | Create a task or subtask |
129
+ | `cu update <id>` | Update task fields (status, name, priority, assignee, etc.) |
130
+ | `cu delete <id>` | Delete a task (requires confirmation) |
131
+ | `cu assign <id>` | Assign/unassign users |
132
+ | `cu depend <id>` | Add/remove task dependencies |
133
+ | `cu move <id>` | Add/remove task from lists |
134
+ | `cu open <query>` | Open task in browser by ID or name |
135
+ | `cu search <query>` | Search my tasks by name |
136
+ | _`cu duplicate <id>`_ | _Copy a task - coming soon_ |
137
+ | _`cu bulk`_ | _Bulk task operations - coming soon_ |
138
+
139
+ ### Sprints & Planning
140
+
141
+ | Command | Description |
142
+ | ------------- | ----------------------------------------------- |
143
+ | `cu sprint` | My tasks in the active sprint (auto-detected) |
144
+ | `cu sprints` | List all sprints |
145
+ | `cu assigned` | All my tasks grouped by status |
146
+ | `cu summary` | Standup helper: completed, in progress, overdue |
147
+ | `cu overdue` | Tasks past their due date |
148
+ | `cu inbox` | Recently updated tasks |
149
+
150
+ ### Comments
151
+
152
+ | Command | Description |
153
+ | -------------------------- | -------------------------------- |
154
+ | `cu comment <id>` | Post a comment on a task |
155
+ | `cu comments <id>` | List comments on a task |
156
+ | `cu comment-edit <id>` | Edit an existing comment |
157
+ | `cu activity <id>` | Task details + comments combined |
158
+ | _`cu comment-delete <id>`_ | _Delete a comment - coming soon_ |
159
+
160
+ ### Custom Fields
161
+
162
+ | Command | Description |
163
+ | ---------------------- | ----------------------------------------------------------------------------------- |
164
+ | `cu field <id>` | Set/remove custom field values (text, number, dropdown, date, checkbox, url, email) |
165
+ | _`cu fields <listId>`_ | _List available custom fields for a list - coming soon_ |
166
+
167
+ ### Checklists
168
+
169
+ | Command | Description |
170
+ | ---------------------------------------- | ------------------------------------------------ |
171
+ | `cu checklist view <id>` | View all checklists on a task |
172
+ | `cu checklist create <id> <name>` | Create a checklist |
173
+ | `cu checklist delete <id>` | Delete a checklist |
174
+ | `cu checklist add-item <id> <name>` | Add item to a checklist |
175
+ | `cu checklist edit-item <id> <itemId>` | Edit a checklist item (name, resolved, assignee) |
176
+ | `cu checklist delete-item <id> <itemId>` | Delete a checklist item |
177
+
178
+ ### Tags
179
+
180
+ | Command | Description |
181
+ | --------------------- | --------------------------------------------------- |
182
+ | `cu tag <id>` | Add/remove tags on a task |
183
+ | _`cu tags <spaceId>`_ | _List/create/delete space-level tags - coming soon_ |
184
+
185
+ ### Workspace
186
+
187
+ | Command | Description |
188
+ | ------------------------ | ----------------------------------------- |
189
+ | `cu spaces` | List workspace spaces |
190
+ | `cu lists <spaceId>` | Lists in a space (including folder lists) |
191
+ | `cu auth` | Check authentication status |
192
+ | _`cu folders <spaceId>`_ | _List folders in a space - coming soon_ |
193
+ | _`cu members`_ | _List workspace members - coming soon_ |
194
+
195
+ ### Time Tracking
196
+
197
+ | Command | Description |
198
+ | ----------------------------- | ----------------------------------------------- |
199
+ | `cu time start <id>` | Start tracking time on a task |
200
+ | `cu time stop` | Stop the running timer |
201
+ | `cu time status` | Show the currently running timer |
202
+ | `cu time log <id> <duration>` | Log a manual time entry (e.g. "2h", "30m") |
203
+ | `cu time list` | List recent time entries (default: last 7 days) |
204
+
205
+ ### Setup
206
+
207
+ | Command | Description |
208
+ | ----------------------- | --------------------------------- |
209
+ | `cu init` | First-time setup wizard |
210
+ | `cu config` | Get/set config values |
211
+ | `cu completion <shell>` | Shell completions (bash/zsh/fish) |
212
+
213
+ ## Output Modes
214
+
215
+ | Context | Default | Override |
216
+ | -------------- | --------------------------- | ---------------------------- |
217
+ | Terminal (TTY) | Interactive tables + picker | `--json` |
218
+ | Piped (no TTY) | Markdown (optimized for AI) | `--json` or `CU_OUTPUT=json` |
219
+
220
+ Most commands scope to your assigned tasks by default - keeping output small and relevant for agent context windows.
221
+
222
+ ## Configuration
552
223
 
553
224
  ### Config file
554
225
 
@@ -573,6 +244,10 @@ Environment variables override config file values:
573
244
 
574
245
  When both are set, the config file is not required. Useful for CI/CD and containerized agents.
575
246
 
247
+ ## Why a CLI and not MCP?
248
+
249
+ A CLI + skill file has fewer moving parts. No server process, no protocol layer. The agent already knows how to run shell commands - the skill file teaches it which ones exist. For tool-use with coding agents, CLI + instructions tends to work better than MCP in practice.
250
+
576
251
  ## Development
577
252
 
578
253
  ```bash
package/dist/index.js CHANGED
@@ -120,6 +120,9 @@ var ClickUpClient = class {
120
120
  async getSpaceWithStatuses(spaceId) {
121
121
  return this.request(`/space/${spaceId}`);
122
122
  }
123
+ async getListWithStatuses(listId) {
124
+ return this.request(`/list/${listId}`);
125
+ }
123
126
  async getSpaces(teamId) {
124
127
  const data = await this.request(`/team/${teamId}/space?archived=false`);
125
128
  return data.spaces ?? [];
@@ -235,6 +238,63 @@ var ClickUpClient = class {
235
238
  { method: "DELETE" }
236
239
  );
237
240
  }
241
+ async startTimeEntry(teamId, taskId, description) {
242
+ const body = {
243
+ tid: taskId,
244
+ start: Date.now(),
245
+ duration: -1
246
+ };
247
+ if (description) body.description = description;
248
+ const data = await this.request(`/team/${teamId}/time_entries/start`, {
249
+ method: "POST",
250
+ body: JSON.stringify(body)
251
+ });
252
+ return data.data;
253
+ }
254
+ async stopTimeEntry(teamId) {
255
+ const data = await this.request(`/team/${teamId}/time_entries/stop`, {
256
+ method: "POST"
257
+ });
258
+ return data.data;
259
+ }
260
+ async getRunningTimeEntry(teamId) {
261
+ const data = await this.request(
262
+ `/team/${teamId}/time_entries/current`
263
+ );
264
+ return data.data ?? null;
265
+ }
266
+ async createTimeEntry(teamId, taskId, duration, opts) {
267
+ const start = opts?.start ?? Date.now() - duration;
268
+ const body = {
269
+ tid: taskId,
270
+ start,
271
+ duration
272
+ };
273
+ if (opts?.description) body.description = opts.description;
274
+ const data = await this.request(`/team/${teamId}/time_entries`, {
275
+ method: "POST",
276
+ body: JSON.stringify(body)
277
+ });
278
+ return data.data;
279
+ }
280
+ async getTimeEntries(teamId, opts) {
281
+ const params = new URLSearchParams();
282
+ if (opts?.startDate != null) params.set("start_date", String(opts.startDate));
283
+ if (opts?.endDate != null) params.set("end_date", String(opts.endDate));
284
+ const query = params.toString();
285
+ const url = `/team/${teamId}/time_entries${query ? `?${query}` : ""}`;
286
+ const data = await this.request(url);
287
+ const entries = data.data ?? [];
288
+ if (opts?.taskId) {
289
+ return entries.filter((e) => e.task?.id === opts.taskId);
290
+ }
291
+ return entries;
292
+ }
293
+ async deleteTimeEntry(teamId, timeEntryId) {
294
+ await this.request(`/team/${teamId}/time_entries/${timeEntryId}`, {
295
+ method: "DELETE"
296
+ });
297
+ }
238
298
  };
239
299
 
240
300
  // src/config.ts
@@ -865,9 +925,8 @@ function hasUpdateFields(options) {
865
925
  }
866
926
  async function resolveStatus(client, taskId, statusInput) {
867
927
  const task = await client.getTask(taskId);
868
- if (!task.space) return statusInput;
869
- const space = await client.getSpaceWithStatuses(task.space.id);
870
- const available = space.statuses.map((s) => s.status);
928
+ const list = await client.getListWithStatuses(task.list.id);
929
+ const available = list.statuses.map((s) => s.status);
871
930
  const matched = matchStatus(statusInput, available);
872
931
  if (!matched) {
873
932
  throw new Error(`No matching status for "${statusInput}". Available: ${available.join(", ")}`);
@@ -1749,7 +1808,7 @@ function bashCompletion() {
1749
1808
  cword=$COMP_CWORD
1750
1809
  fi
1751
1810
 
1752
- local commands="init auth tasks task update create sprint sprints subtasks comment comment-edit comments activity lists spaces inbox assigned open search summary overdue assign depend move field delete tag checklist config completion"
1811
+ local commands="init auth tasks task update create sprint sprints subtasks comment comment-edit comments activity lists spaces inbox assigned open search summary overdue assign depend move field delete tag checklist time config completion"
1753
1812
 
1754
1813
  if [[ $cword -eq 1 ]]; then
1755
1814
  COMPREPLY=($(compgen -W "$commands --help --version" -- "$cur"))
@@ -1850,6 +1909,11 @@ function bashCompletion() {
1850
1909
  COMPREPLY=($(compgen -W "view create delete add-item edit-item delete-item" -- "$cur"))
1851
1910
  fi
1852
1911
  ;;
1912
+ time)
1913
+ if [[ $cword -eq 2 ]]; then
1914
+ COMPREPLY=($(compgen -W "start stop status log list" -- "$cur"))
1915
+ fi
1916
+ ;;
1853
1917
  comment-edit)
1854
1918
  COMPREPLY=($(compgen -W "-m --message --resolved --unresolved --json" -- "$cur"))
1855
1919
  ;;
@@ -1906,6 +1970,7 @@ _cu() {
1906
1970
  'delete:Delete a task'
1907
1971
  'tag:Add or remove tags from a task'
1908
1972
  'checklist:Manage checklists on a task'
1973
+ 'time:Track time on tasks'
1909
1974
  'comment-edit:Edit an existing comment'
1910
1975
  'config:Manage CLI configuration'
1911
1976
  'completion:Output shell completion script'
@@ -2142,6 +2207,53 @@ _cu() {
2142
2207
  ;;
2143
2208
  esac
2144
2209
  ;;
2210
+ time)
2211
+ local -a time_cmds
2212
+ time_cmds=(
2213
+ 'start:Start tracking time on a task'
2214
+ 'stop:Stop the running timer'
2215
+ 'status:Show the currently running timer'
2216
+ 'log:Log a manual time entry'
2217
+ 'list:List recent time entries'
2218
+ )
2219
+ _arguments -C \\
2220
+ '1:time command:->time_cmd' \\
2221
+ '*::time_arg:->time_args'
2222
+ case $state in
2223
+ time_cmd)
2224
+ _describe 'time command' time_cmds
2225
+ ;;
2226
+ time_args)
2227
+ case $words[1] in
2228
+ start)
2229
+ _arguments \\
2230
+ '1:task_id:' \\
2231
+ '(-d --description)'{-d,--description}'[Description]:text:' \\
2232
+ '--json[Force JSON output]'
2233
+ ;;
2234
+ stop)
2235
+ _arguments '--json[Force JSON output]'
2236
+ ;;
2237
+ status)
2238
+ _arguments '--json[Force JSON output]'
2239
+ ;;
2240
+ log)
2241
+ _arguments \\
2242
+ '1:task_id:' \\
2243
+ '2:duration:' \\
2244
+ '(-d --description)'{-d,--description}'[Description]:text:' \\
2245
+ '--json[Force JSON output]'
2246
+ ;;
2247
+ list)
2248
+ _arguments \\
2249
+ '--days[Number of days to look back]:days:' \\
2250
+ '--task[Filter by task ID]:task_id:' \\
2251
+ '--json[Force JSON output]'
2252
+ ;;
2253
+ esac
2254
+ ;;
2255
+ esac
2256
+ ;;
2145
2257
  comment-edit)
2146
2258
  _arguments \\
2147
2259
  '1:comment_id:' \\
@@ -2217,6 +2329,7 @@ complete -c cu -n __fish_use_subcommand -a field -d 'Set or remove a custom fiel
2217
2329
  complete -c cu -n __fish_use_subcommand -a delete -d 'Delete a task'
2218
2330
  complete -c cu -n __fish_use_subcommand -a tag -d 'Add or remove tags from a task'
2219
2331
  complete -c cu -n __fish_use_subcommand -a checklist -d 'Manage checklists on a task'
2332
+ complete -c cu -n __fish_use_subcommand -a time -d 'Track time on tasks'
2220
2333
  complete -c cu -n __fish_use_subcommand -a comment-edit -d 'Edit an existing comment'
2221
2334
  complete -c cu -n __fish_use_subcommand -a config -d 'Manage CLI configuration'
2222
2335
  complete -c cu -n __fish_use_subcommand -a completion -d 'Output shell completion script'
@@ -2339,6 +2452,17 @@ complete -c cu -n '__fish_seen_subcommand_from edit-item' -l resolved -d 'Mark i
2339
2452
  complete -c cu -n '__fish_seen_subcommand_from edit-item' -l unresolved -d 'Mark item as unresolved'
2340
2453
  complete -c cu -n '__fish_seen_subcommand_from edit-item' -l assignee -d 'Assign user by ID'
2341
2454
 
2455
+ complete -c cu -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list' -a start -d 'Start tracking time on a task'
2456
+ complete -c cu -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list' -a stop -d 'Stop the running timer'
2457
+ complete -c cu -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list' -a status -d 'Show the currently running timer'
2458
+ complete -c cu -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list' -a log -d 'Log a manual time entry'
2459
+ complete -c cu -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list' -a list -d 'List recent time entries'
2460
+ complete -c cu -n '__fish_seen_subcommand_from start stop status log list; and __fish_seen_subcommand_from time' -l json -d 'Force JSON output'
2461
+ complete -c cu -n '__fish_seen_subcommand_from start; and __fish_seen_subcommand_from time' -s d -l description -d 'Description'
2462
+ complete -c cu -n '__fish_seen_subcommand_from log; and __fish_seen_subcommand_from time' -s d -l description -d 'Description'
2463
+ complete -c cu -n '__fish_seen_subcommand_from list; and __fish_seen_subcommand_from time' -l days -d 'Number of days to look back'
2464
+ complete -c cu -n '__fish_seen_subcommand_from list; and __fish_seen_subcommand_from time' -l task -d 'Filter by task ID'
2465
+
2342
2466
  complete -c cu -n '__fish_seen_subcommand_from comment-edit' -s m -l message -d 'New comment text'
2343
2467
  complete -c cu -n '__fish_seen_subcommand_from comment-edit' -l resolved -d 'Mark comment as resolved'
2344
2468
  complete -c cu -n '__fish_seen_subcommand_from comment-edit' -l unresolved -d 'Mark comment as unresolved'
@@ -2651,6 +2775,71 @@ async function editComment(config, commentId, text, resolved) {
2651
2775
  await client.updateComment(commentId, text, resolved);
2652
2776
  }
2653
2777
 
2778
+ // src/commands/time.ts
2779
+ import chalk6 from "chalk";
2780
+ function formatDuration2(ms) {
2781
+ const totalMinutes = Math.round(Math.abs(ms) / 6e4);
2782
+ const hours = Math.floor(totalMinutes / 60);
2783
+ const minutes = totalMinutes % 60;
2784
+ if (hours > 0 && minutes > 0) return `${hours}h ${minutes}m`;
2785
+ if (hours > 0) return `${hours}h`;
2786
+ return `${minutes}m`;
2787
+ }
2788
+ function formatTimestamp2(ms) {
2789
+ return new Date(Number(ms)).toLocaleString("en-US", {
2790
+ month: "short",
2791
+ day: "numeric",
2792
+ hour: "numeric",
2793
+ minute: "2-digit"
2794
+ });
2795
+ }
2796
+ async function startTimer(config, taskId, description) {
2797
+ const client = new ClickUpClient(config);
2798
+ return client.startTimeEntry(config.teamId, taskId, description);
2799
+ }
2800
+ async function stopTimer(config) {
2801
+ const client = new ClickUpClient(config);
2802
+ return client.stopTimeEntry(config.teamId);
2803
+ }
2804
+ async function timerStatus(config) {
2805
+ const client = new ClickUpClient(config);
2806
+ return client.getRunningTimeEntry(config.teamId);
2807
+ }
2808
+ async function logTime(config, taskId, durationStr, description) {
2809
+ const client = new ClickUpClient(config);
2810
+ const duration = parseTimeEstimate(durationStr);
2811
+ return client.createTimeEntry(config.teamId, taskId, duration, { description });
2812
+ }
2813
+ async function listTimeEntries(config, opts) {
2814
+ const client = new ClickUpClient(config);
2815
+ const days = opts?.days ?? 7;
2816
+ const endDate = Date.now();
2817
+ const startDate = endDate - days * 24 * 60 * 60 * 1e3;
2818
+ return client.getTimeEntries(config.teamId, {
2819
+ startDate,
2820
+ endDate,
2821
+ taskId: opts?.taskId
2822
+ });
2823
+ }
2824
+ function formatTimeEntry(entry) {
2825
+ const lines = [];
2826
+ const taskName = entry.task?.name ?? "No task";
2827
+ const taskId = entry.task?.id ?? "";
2828
+ const isRunning = entry.duration < 0;
2829
+ const elapsed = isRunning ? Date.now() - Number(entry.start) : entry.duration;
2830
+ const durationStr = formatDuration2(elapsed);
2831
+ const status = isRunning ? chalk6.green("RUNNING") : "";
2832
+ lines.push(`${chalk6.bold(taskName)} ${chalk6.dim(taskId)} ${status}`);
2833
+ lines.push(
2834
+ ` ${durationStr} - ${formatTimestamp2(entry.start)}${entry.description ? ` - ${entry.description}` : ""}`
2835
+ );
2836
+ return lines.join("\n");
2837
+ }
2838
+ function formatTimeEntries(entries) {
2839
+ if (entries.length === 0) return "No time entries";
2840
+ return entries.map(formatTimeEntry).join("\n");
2841
+ }
2842
+
2654
2843
  // src/index.ts
2655
2844
  var require2 = createRequire(import.meta.url);
2656
2845
  var { version } = require2("../package.json");
@@ -3049,6 +3238,71 @@ checklistCmd.command("delete-item <checklistId> <checklistItemId>").description(
3049
3238
  }
3050
3239
  })
3051
3240
  );
3241
+ var timeCmd = program.command("time").description("Track time on tasks");
3242
+ timeCmd.command("start <taskId>").description("Start tracking time on a task").option("-d, --description <text>", "Description for the time entry").option("--json", "Force JSON output even in terminal").action(
3243
+ wrapAction(async (taskId, opts) => {
3244
+ const config = loadConfig();
3245
+ const result = await startTimer(config, taskId, opts.description);
3246
+ if (shouldOutputJson(opts.json ?? false)) {
3247
+ console.log(JSON.stringify(result, null, 2));
3248
+ } else {
3249
+ const taskName = result.task?.name ?? taskId;
3250
+ console.log(`Started timer on "${taskName}"`);
3251
+ }
3252
+ })
3253
+ );
3254
+ timeCmd.command("stop").description("Stop the running timer").option("--json", "Force JSON output even in terminal").action(
3255
+ wrapAction(async (opts) => {
3256
+ const config = loadConfig();
3257
+ const result = await stopTimer(config);
3258
+ if (shouldOutputJson(opts.json ?? false)) {
3259
+ console.log(JSON.stringify(result, null, 2));
3260
+ } else {
3261
+ console.log(formatTimeEntry(result));
3262
+ }
3263
+ })
3264
+ );
3265
+ timeCmd.command("status").description("Show the currently running timer").option("--json", "Force JSON output even in terminal").action(
3266
+ wrapAction(async (opts) => {
3267
+ const config = loadConfig();
3268
+ const result = await timerStatus(config);
3269
+ if (shouldOutputJson(opts.json ?? false)) {
3270
+ console.log(JSON.stringify(result, null, 2));
3271
+ } else if (result) {
3272
+ console.log(formatTimeEntry(result));
3273
+ } else {
3274
+ console.log("No timer running");
3275
+ }
3276
+ })
3277
+ );
3278
+ timeCmd.command("log <taskId> <duration>").description('Log a manual time entry (e.g. "2h", "30m", "1h30m")').option("-d, --description <text>", "Description for the time entry").option("--json", "Force JSON output even in terminal").action(
3279
+ wrapAction(
3280
+ async (taskId, duration, opts) => {
3281
+ const config = loadConfig();
3282
+ const result = await logTime(config, taskId, duration, opts.description);
3283
+ if (shouldOutputJson(opts.json ?? false)) {
3284
+ console.log(JSON.stringify(result, null, 2));
3285
+ } else {
3286
+ console.log(`Logged ${duration} on task ${taskId}`);
3287
+ }
3288
+ }
3289
+ )
3290
+ );
3291
+ timeCmd.command("list").description("List recent time entries (default: last 7 days)").option("--days <n>", "Number of days to look back", "7").option("--task <taskId>", "Filter by task ID").option("--json", "Force JSON output even in terminal").action(
3292
+ wrapAction(async (opts) => {
3293
+ const config = loadConfig();
3294
+ const days = opts.days ? Number(opts.days) : 7;
3295
+ if (!Number.isFinite(days) || days <= 0) {
3296
+ throw new Error("--days must be a positive number");
3297
+ }
3298
+ const entries = await listTimeEntries(config, { days, taskId: opts.task });
3299
+ if (shouldOutputJson(opts.json ?? false)) {
3300
+ console.log(JSON.stringify(entries, null, 2));
3301
+ } else {
3302
+ console.log(formatTimeEntries(entries));
3303
+ }
3304
+ })
3305
+ );
3052
3306
  var configCmd = program.command("config").description("Manage CLI configuration");
3053
3307
  configCmd.command("get <key>").description("Print a config value").action(
3054
3308
  wrapAction(async (key) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krodak/clickup-cli",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "ClickUp CLI for AI agents and humans",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: clickup
3
- description: 'Use when managing ClickUp tasks, sprints, or comments via the `cu` CLI tool. Triggers: task queries, status updates, sprint tracking, creating subtasks, posting comments, standup summaries, searching tasks, checking overdue items, assigning tasks, listing spaces and lists, opening tasks in browser, checking auth or config, setting custom fields, deleting tasks, managing tags, managing checklists, editing comments.'
3
+ description: 'Use when managing ClickUp tasks, sprints, or comments via the `cu` CLI tool. Triggers: task queries, status updates, sprint tracking, creating subtasks, posting comments, standup summaries, searching tasks, checking overdue items, assigning tasks, listing spaces and lists, opening tasks in browser, checking auth or config, setting custom fields, deleting tasks, managing tags, managing checklists, editing comments, time tracking.'
4
4
  ---
5
5
 
6
6
  # ClickUp CLI (`cu`)
@@ -73,6 +73,11 @@ All commands support `--help` for full flag details.
73
73
  | `cu checklist add-item <checklistId> <name> [--json]` | Add item to a checklist |
74
74
  | `cu checklist edit-item <checklistId> <itemId> [--name n] [--resolved] [--unresolved] [--assignee id] [--json]` | Edit a checklist item |
75
75
  | `cu checklist delete-item <checklistId> <itemId> [--json]` | Delete a checklist item |
76
+ | `cu time start <taskId> [-d desc] [--json]` | Start tracking time on a task |
77
+ | `cu time stop [--json]` | Stop the running timer |
78
+ | `cu time status [--json]` | Show currently running timer |
79
+ | `cu time log <taskId> <duration> [-d desc] [--json]` | Log manual time entry (e.g. "2h", "30m") |
80
+ | `cu time list [--days n] [--task id] [--json]` | List recent time entries |
76
81
  | `cu config get <key>` / `cu config set <key> <value>` / `cu config path` | Manage CLI config |
77
82
  | `cu completion <shell>` | Shell completions (bash/zsh/fish) |
78
83
 
@@ -106,6 +111,7 @@ All commands support `--help` for full flag details.
106
111
  | `cu overdue` | Excludes closed tasks, sorted most overdue first |
107
112
  | `cu open` | Tries task ID first, falls back to name search |
108
113
  | `cu checklist` | Full CRUD for task checklists: view, create, delete, add-item, edit-item, delete-item |
114
+ | `cu time` | Track time: start/stop timer, log entries, list history. Duration format: "2h", "30m", "1h30m" |
109
115
  | `cu comment-edit` | Edit comment text and resolution status |
110
116
  | `cu task` | Shows custom fields and checklists in detail view |
111
117
  | `cu lists` | Discovers list IDs needed for `--list` and `cu create -l` |
@@ -164,6 +170,11 @@ cu checklist create abc123def "QA Steps" # add checklist
164
170
  cu checklist add-item <clId> "Run unit tests" # add item
165
171
  cu checklist edit-item <clId> <itemId> --resolved # check off item
166
172
  cu comment-edit <commentId> -m "Updated findings" # edit a comment
173
+ cu time start abc123def -d "Working on feature" # start timer
174
+ cu time status # check running timer
175
+ cu time stop # stop timer
176
+ cu time log abc123def 2h -d "Code review" # log manual entry
177
+ cu time list --days 7 # recent entries
167
178
  cu delete abc123def --confirm # irreversible!
168
179
  ```
169
180