td-ai-tools 1.0.2 → 1.0.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "td-ai-tools",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Install agent skills and packs into your project",
5
5
  "scripts": {
6
6
  "smoke:install": "./scripts/smoke-install.sh"
@@ -0,0 +1,651 @@
1
+ ---
2
+ name: basecamp
3
+ description: |
4
+ Interact with Basecamp via the Basecamp CLI. Full API coverage: projects, todos, cards,
5
+ messages, files, schedule, check-ins, timeline, recordings, templates, webhooks,
6
+ subscriptions, lineup, and campfire. Use for ANY Basecamp question or action.
7
+ invocable: true
8
+ argument-hint: '[action] [args...]'
9
+ ---
10
+
11
+ # /basecamp - Basecamp Workflow Command
12
+
13
+ Full CLI coverage: 130 endpoints across todos, cards, messages, files, schedule, check-ins, timeline, recordings, templates, webhooks, subscriptions, lineup, and campfire.
14
+
15
+ ## Agent Invariants
16
+
17
+ **MUST follow these rules:**
18
+
19
+ 1. **Choose the right output mode** — `--json` when you need to parse data; `--md` when presenting results to a human (see Output Modes below)
20
+ 2. **Parse URLs first** with `basecamp url parse "<url>"` to extract IDs
21
+ 3. **Comments are flat** - reply to parent recording, not to comments
22
+ 4. **Check context** via `.basecamp/config.json` before assuming project
23
+ 5. **Content fields accept Markdown** — message body and comment content accept Markdown syntax; the CLI converts to HTML automatically. Use Markdown formatting (lists, bold, links, code blocks) for rich content. For todos, documents, and cards, content is sent as-is — use plain text or HTML directly.
24
+ 6. **Project scope is mandatory for most commands** — via `--in <project>` or `.basecamp/config.json`. Cross-project exceptions: `basecamp reports assigned` for assigned work, `basecamp reports overdue` for overdue todos, `basecamp recordings <type>` for browsing by type.
25
+
26
+ ### Output Modes
27
+
28
+ **Choosing a mode:**
29
+
30
+ | Goal | Flag | Format |
31
+ | ---------------------- | ------------- | --------------------------------------------------------------------------------------------- |
32
+ | Parse data, pipe to jq | `--json` | JSON envelope: `{ok, data, summary, breadcrumbs, meta}` |
33
+ | Show results to a user | `--md` / `-m` | GFM tables, task lists, structured Markdown |
34
+ | Automation / scripting | `--agent` | Success: raw JSON data (no envelope); errors: `{ok:false,...}` object; no interactive prompts |
35
+
36
+ Always pass `--json` or `--md` explicitly — auto-detection depends on config and may not produce the format you expect. Use `--md` when composing reports, summarizing data, or displaying results inline. `--agent` is for headless integration scripts.
37
+
38
+ **Other modes:** `--quiet` (success: raw JSON, no envelope; errors: `{ok:false,...}`), `--ids-only`, `--count`, `--stats` (session statistics), `--styled` (force ANSI), `-v` / `-vv` (verbose/trace).
39
+
40
+ ### CLI Introspection
41
+
42
+ Navigate unfamiliar commands with `--agent --help` — returns structured JSON describing any command:
43
+
44
+ ```bash
45
+ basecamp todos --agent --help
46
+ ```
47
+
48
+ ```json
49
+ {
50
+ "command": "todos",
51
+ "path": "basecamp todos",
52
+ "short": "...",
53
+ "long": "...",
54
+ "usage": "...",
55
+ "notes": ["..."],
56
+ "subcommands": [{ "name": "sweep", "short": "...", "path": "basecamp todos sweep" }],
57
+ "flags": [{ "name": "assignee", "type": "string", "default": "", "usage": "..." }],
58
+ "inherited_flags": [
59
+ { "name": "json", "shorthand": "j", "type": "bool", "default": "false", "usage": "..." }
60
+ ]
61
+ }
62
+ ```
63
+
64
+ Walk the tree: start at `basecamp --agent --help` for top-level commands, then drill into any subcommand. Commands include `notes` with domain-specific agent hints (e.g., "Cards do NOT support --assignee filtering").
65
+
66
+ ### Pagination
67
+
68
+ ```bash
69
+ basecamp <cmd> --limit 50 # Cap results (default varies by resource)
70
+ basecamp <cmd> --all # Fetch all (may be slow for large datasets)
71
+ basecamp <cmd> --page 1 # First page only, no auto-pagination
72
+ ```
73
+
74
+ `--all` and `--limit` are mutually exclusive. `--page` cannot combine with either.
75
+
76
+ ### Smart Defaults
77
+
78
+ - `--assignee me` resolves to current user
79
+ - `--due tomorrow` / `--due +3` / `--due "next week"` - natural date parsing
80
+ - Project from `.basecamp/config.json` if `--in` not specified
81
+
82
+ ## Quick Reference
83
+
84
+ > **Note:** Most queries require project scope (via `--in <project>` or `.basecamp/config.json`). Cross-project exceptions: `basecamp reports assigned`, `basecamp reports overdue`, `basecamp recordings <type>`.
85
+
86
+ | Task | Command |
87
+ | ----------------------------- | ------------------------------------------------------------------------------- |
88
+ | List projects | `basecamp projects list --json` |
89
+ | My todos (in project) | `basecamp todos list --assignee me --in <project> --json` |
90
+ | My todos (cross-project) | `basecamp reports assigned --json` (defaults to "me") |
91
+ | All todos (cross-project) | `basecamp recordings todos --json` (no assignee data — cannot filter by person) |
92
+ | Overdue todos (in project) | `basecamp todos list --overdue --in <project> --json` |
93
+ | Overdue todos (cross-project) | `basecamp reports overdue --json` |
94
+ | Assign todo | `basecamp assign <id> --to <person> --in <project> --json` |
95
+ | Create todo | `basecamp todo "Task" --in <project> --list <list> --json` |
96
+ | Create todolist | `basecamp todolists create "Name" --in <project> --json` |
97
+ | Complete todo | `basecamp done <id> --json` |
98
+ | List cards | `basecamp cards list --in <project> --json` |
99
+ | Create card | `basecamp card "Title" --in <project> --json` |
100
+ | Move card | `basecamp cards move <id> --to <column> --in <project> --json` |
101
+ | Post message | `basecamp message "Title" "Body" --in <project> --json` |
102
+ | Post silently | `basecamp message "Title" "Body" --no-subscribe --in <project> --json` |
103
+ | Post to campfire | `basecamp campfire post "Message" --in <project> --json` |
104
+ | Add comment | `basecamp comment <recording_id> "Text" --in <project> --json` |
105
+ | Search | `basecamp search "query" --json` |
106
+ | Parse URL | `basecamp url parse "<url>" --json` |
107
+ | Download file | `basecamp files download <id> --in <project>` |
108
+ | Watch timeline | `basecamp timeline --watch` |
109
+
110
+ ## URL Parsing
111
+
112
+ **Always parse URLs before acting on them:**
113
+
114
+ ```bash
115
+ basecamp url parse "https://3.basecamp.com/2914079/buckets/41746046/messages/9478142982#__recording_9488783598" --json
116
+ ```
117
+
118
+ Returns: `account_id`, `project_id`, `type`, `recording_id`, `comment_id` (from fragment).
119
+
120
+ **URL patterns:**
121
+
122
+ - `/buckets/27/messages/123` - Message 123 in project 27
123
+ - `/buckets/27/messages/123#__recording_456` - Comment 456 on message 123
124
+ - `/buckets/27/card_tables/cards/789` - Card 789
125
+ - `/buckets/27/card_tables/columns/456` - Column 456 (for creating cards)
126
+ - `/buckets/27/todos/101` - Todo 101
127
+ - `/buckets/27/uploads/202` - Upload/file 202
128
+ - `/buckets/27/documents/303` - Document 303
129
+ - `/buckets/27/schedule_entries/404` - Schedule entry 404
130
+
131
+ **Replying to comments:**
132
+
133
+ ```bash
134
+ # Comments are flat - reply to the parent recording_id, not the comment_id
135
+ basecamp url parse "https://...messages/123#__recording_456" --json
136
+ # Returns recording_id: 123 (parent), comment_id: 456 (fragment) - comment on 123, not 456
137
+ basecamp comment 123 "Reply" --in <project>
138
+ ```
139
+
140
+ ## Decision Trees
141
+
142
+ ### Finding Content
143
+
144
+ ```
145
+ Need to find something?
146
+ ├── Know the type + project? → basecamp <type> list --in <project> --json
147
+ │ (some groups have default list behavior; use --agent --help if unsure)
148
+ ├── My assigned work? → basecamp reports assigned --json (defaults to "me")
149
+ ├── Overdue across projects? → basecamp reports overdue --json
150
+ ├── Browse by type cross-project? → basecamp recordings <type> --json
151
+ │ (types: todos, messages, documents, comments, cards, uploads)
152
+ │ Note: Defaults to active status; use --status archived for archived items
153
+ │ ⚠ No assignee data — cannot filter by person; use reports assigned instead
154
+ ├── Full-text search? → basecamp search "query" --json
155
+ └── Have a URL? → basecamp url parse "<url>" --json
156
+ ```
157
+
158
+ ### Modifying Content
159
+
160
+ ```
161
+ Want to change something?
162
+ ├── Have URL? → basecamp url parse "<url>" → use extracted IDs
163
+ ├── Have ID? → basecamp <resource> update <id> --field value
164
+ ├── Change status? → basecamp recordings trash|archive|restore <id>
165
+ └── Complete todo? → basecamp done <id>
166
+ ```
167
+
168
+ ## Common Workflows
169
+
170
+ ### Link Code to Basecamp Todo
171
+
172
+ ```bash
173
+ # Get commit info and comment on todo (use printf %q for safe quoting)
174
+ COMMIT=$(git rev-parse --short HEAD)
175
+ MSG=$(git log -1 --format=%s)
176
+ basecamp comment <todo_id> "Commit $COMMIT: $(printf '%s' "$MSG")" --in <project>
177
+
178
+ # Complete when done
179
+ basecamp done <todo_id>
180
+ ```
181
+
182
+ ### Track PR in Basecamp
183
+
184
+ ```bash
185
+ # Create todo for PR work
186
+ basecamp todo "Review PR #42" --in <project> --assignee me --due tomorrow
187
+
188
+ # When merged
189
+ basecamp done <todo_id>
190
+ basecamp campfire post "Merged PR #42" --in <project>
191
+ ```
192
+
193
+ ### Bulk Process Overdue Todos
194
+
195
+ ```bash
196
+ # Preview overdue todos
197
+ basecamp todos sweep --overdue --dry-run --in <project>
198
+
199
+ # Complete all with comment
200
+ basecamp todos sweep --overdue --complete --comment "Cleaning up" --in <project>
201
+ ```
202
+
203
+ ### Move Card Through Workflow
204
+
205
+ ```bash
206
+ # List columns to get IDs
207
+ basecamp cards columns --in <project> --json
208
+
209
+ # Move card to column
210
+ basecamp cards move <card_id> --to <column_id> --in <project>
211
+ ```
212
+
213
+ ### Download File from Basecamp
214
+
215
+ ```bash
216
+ basecamp files download <upload_id> --in <project> --out ./downloads
217
+ ```
218
+
219
+ ## Resource Reference
220
+
221
+ ### Projects
222
+
223
+ ```bash
224
+ basecamp projects list --json # List all
225
+ basecamp projects show <id> --json # Show details
226
+ basecamp projects create "Name" --json # Create
227
+ basecamp projects update <id> --name "New" # Update
228
+ ```
229
+
230
+ ### Todos
231
+
232
+ ```bash
233
+ basecamp todos list --in <project> --json # List in project
234
+ basecamp todos list --assignee me --in <project> # My todos
235
+ basecamp todos list --overdue --in <project> # Overdue only
236
+ basecamp todos list --status completed --in <project> # Completed
237
+ basecamp todos list --list <todolist_id> --in <project> # In specific list
238
+ basecamp todo "Task" --in <project> --list <list> --assignee me --due tomorrow
239
+ basecamp done <id> [id...] # Complete (multiple OK)
240
+ basecamp reopen <id> # Uncomplete
241
+ basecamp assign <id> --to <person> --in <project> # Assign (person: ID, email, or "me")
242
+ basecamp unassign <id> --from <person> --in <project> # Remove assignee
243
+ basecamp todos position <id> --to 1 # Move to top
244
+ basecamp todos sweep --overdue --complete --comment "Done" --in <project>
245
+ ```
246
+
247
+ **Flags:** `--assignee` (todos only - not available on cards/messages), `--status` (completed/pending), `--overdue`, `--list`, `--due`, `--limit`, `--all`
248
+
249
+ ### Todolists
250
+
251
+ Todolists are containers for todos. Create a todolist before adding todos.
252
+
253
+ ```bash
254
+ basecamp todolists list --in <project> --json # List todolists
255
+ basecamp todolists show <id> --in <project> # Show details
256
+ basecamp todolists create "Name" --in <project> --json # Create
257
+ basecamp todolists create "Name" --description "Desc" --in <project>
258
+ basecamp todolists update <id> --name "New" --in <project> # Update
259
+ ```
260
+
261
+ ### Cards (Kanban)
262
+
263
+ **Note:** Cards do NOT support `--assignee` filtering like todos. Fetch all cards and filter client-side if needed. If a project has multiple card tables, you must specify `--card-table <id>`. When you get an "Ambiguous card table" error, the hint shows available table IDs and names.
264
+
265
+ ```bash
266
+ basecamp cards list --in <project> --json # All cards
267
+ basecamp cards list --card-table <id> --in <project> # Specific table (required if multiple)
268
+ basecamp cards list --column <id> --in <project> # Cards in column
269
+ basecamp cards columns --in <project> --json # List columns (needs --card-table if multiple)
270
+ basecamp cards show <id> --in <project> # Card details
271
+ basecamp card "Title" "<p>Body</p>" --in <project> --column <id>
272
+ basecamp cards update <id> --title "New" --due tomorrow --assignee me
273
+ basecamp cards move <id> --to <column_id> # Move to column (numeric ID)
274
+ basecamp cards move <id> --to "Done" --card-table <table_id> # Move by name (needs table)
275
+ ```
276
+
277
+ **Identifying completed cards:** Cards in Done columns have `parent.type: "Kanban::DoneColumn"` and `completed: true`. Use this to identify completed cards that haven't been archived.
278
+
279
+ **Limitation:** Basecamp does not track when cards are moved between columns. The `updated_at` field updates on any modification and cannot reliably indicate when a card was completed.
280
+
281
+ **Card Steps (checklists):**
282
+
283
+ ```bash
284
+ basecamp cards steps <card_id> --in <project> # List steps
285
+ basecamp cards step create "Step" --card <id> --in <project>
286
+ basecamp cards step complete <step_id> --in <project>
287
+ basecamp cards step uncomplete <step_id>
288
+ ```
289
+
290
+ **Column management:**
291
+
292
+ ```bash
293
+ basecamp cards column show <id> --in <project>
294
+ basecamp cards column create "Name" --in <project>
295
+ basecamp cards column update <id> --title "New"
296
+ basecamp cards column move <id> --position 2
297
+ basecamp cards column color <id> --color blue
298
+ basecamp cards column on-hold <id> # Enable on-hold section
299
+ basecamp cards column watch <id> # Subscribe to column
300
+ ```
301
+
302
+ ### Messages
303
+
304
+ ```bash
305
+ basecamp messages list --in <project> --json # List messages
306
+ basecamp messages show <id> --in <project> # Show message
307
+ basecamp message "Title" "Body" --in <project>
308
+ basecamp messages update <id> --title "New" --body "Updated"
309
+ basecamp messages pin <id> --in <project> # Pin to top
310
+ basecamp messages unpin <id> # Unpin
311
+ ```
312
+
313
+ **Flags:** `--draft` (create as draft), `--no-subscribe` (silent, no notifications), `--subscribe "people"` (comma-separated names, emails, IDs, or "me"; mutually exclusive with `--no-subscribe`), `--message-board <id>` (if multiple boards)
314
+
315
+ ```bash
316
+ basecamp message "Bot update" "Done" --no-subscribe --in <project>
317
+ basecamp message "FYI" "Note" --subscribe "Alice,bob@x.com" --in <project>
318
+ ```
319
+
320
+ ### Comments
321
+
322
+ ```bash
323
+ basecamp comments list <recording_id> --in <project> --json
324
+ basecamp comment <recording_id> "Text" --in <project>
325
+ basecamp comments update <id> "Updated" --in <project>
326
+ ```
327
+
328
+ ### Files & Documents
329
+
330
+ ```bash
331
+ basecamp files list --in <project> --json # List all (folders, files, docs)
332
+ basecamp files list --vault <folder_id> --in <project> # List folder contents
333
+ basecamp files show <id> --in <project> # Show item (auto-detects type)
334
+ basecamp files download <id> --in <project> # Download file
335
+ basecamp files download <id> --out ./dir # Download to specific dir
336
+ basecamp files folder create "Folder" --in <project>
337
+ basecamp files doc create "Doc" "Body" --in <project>
338
+ basecamp files doc create "Draft" --draft --in <project>
339
+ basecamp files doc create "Notes" "..." --no-subscribe --in <project>
340
+ basecamp files update <id> --title "New" --content "Updated"
341
+ ```
342
+
343
+ **Subcommands:** `folders`, `uploads`, `documents` (each with pagination flags)
344
+
345
+ ### Schedule
346
+
347
+ ```bash
348
+ basecamp schedule --in <project> --json # Schedule info
349
+ basecamp schedule entries --in <project> --json # List entries
350
+ basecamp schedule show <id> --in <project> # Entry details
351
+ basecamp schedule show <id> --date 20240315 # Specific occurrence (recurring)
352
+ basecamp schedule create "Event" --starts-at "2024-03-15T09:00:00Z" --ends-at "2024-03-15T10:00:00Z" --in <project>
353
+ basecamp schedule create "Meeting" --all-day --notify --participants 1,2,3 --in <project>
354
+ basecamp schedule create "Sync" --starts-at "..." --ends-at "..." --no-subscribe --in <project>
355
+ basecamp schedule update <id> --summary "New title" --starts-at "..."
356
+ basecamp schedule settings --include-due --in <project> # Include todos/cards due dates
357
+ ```
358
+
359
+ **Flags:** `--all-day`, `--notify`, `--participants <ids>`, `--no-subscribe`, `--subscribe "people"` (mutually exclusive), `--status` (active/archived/trashed)
360
+
361
+ ### Check-ins
362
+
363
+ ```bash
364
+ basecamp checkins --in <project> --json # Questionnaire info
365
+ basecamp checkins questions --in <project> # List questions
366
+ basecamp checkins question <id> --in <project> # Question details
367
+ basecamp checkins answers <question_id> --in <project> # List answers
368
+ basecamp checkins answer <id> --in <project> # Answer details
369
+ basecamp checkins question create "What did you work on?" --in <project>
370
+ basecamp checkins question update <id> "New question" --frequency every_week
371
+ basecamp checkins answer create <question-id> "My answer" --in <project>
372
+ basecamp checkins answer update <id> "Updated" --in <project>
373
+ ```
374
+
375
+ **Schedule options:** `--frequency` (every_day, every_week, every_other_week, every_month, on_certain_days), `--days 1,2,3,4,5` (0=Sun), `--time "5:00pm"`
376
+
377
+ ### Timeline
378
+
379
+ ```bash
380
+ basecamp timeline --json # Account-wide activity
381
+ basecamp timeline --in <project> --json # Project activity
382
+ basecamp timeline me --json # Your activity
383
+ basecamp timeline --person <id> --json # Person's activity
384
+ basecamp timeline --watch # Live monitoring (TUI)
385
+ basecamp timeline --watch --interval 60 # Poll every 60 seconds
386
+ ```
387
+
388
+ **Note:** `basecamp timeline` (account-wide) works reliably. The `--limit` flag is not supported on timeline commands.
389
+
390
+ ### Recordings (Cross-project)
391
+
392
+ Use `basecamp recordings <type>` for cross-project type browsing. **For assigned todos, prefer `basecamp reports assigned`** — recordings do not include assignee data and cannot be filtered by person.
393
+
394
+ ```bash
395
+ basecamp recordings todos --json # All todos across projects
396
+ basecamp recordings todos --all --json # All todos (paginate through all)
397
+ basecamp recordings messages --in <project> # Messages in project
398
+ basecamp recordings documents --status archived # Archived docs
399
+ basecamp recordings cards --sort created_at --direction asc
400
+ basecamp recordings cards --status archived --all --json # Include archived cards
401
+ ```
402
+
403
+ **Types:** `todos`, `messages`, `documents`, `comments`, `cards`, `uploads`
404
+
405
+ **Status filtering:** By default, only `active` recordings are returned. Use `--status archived` or `--status trashed` to query other statuses. You may need separate queries to get complete data (e.g., active + archived).
406
+
407
+ **Status management:**
408
+
409
+ ```bash
410
+ basecamp recordings trash <id> --in <project> # Move to trash
411
+ basecamp recordings archive <id> --in <project> # Archive
412
+ basecamp recordings restore <id> --in <project> # Restore to active
413
+ basecamp recordings visibility <id> --visible --in <project> # Show to clients
414
+ basecamp recordings visibility <id> --hidden # Hide from clients
415
+ ```
416
+
417
+ ### Templates
418
+
419
+ ```bash
420
+ basecamp templates --json # List templates
421
+ basecamp templates show <id> --json # Template details
422
+ basecamp templates create "Template Name" # Create empty template
423
+ basecamp templates update <id> --name "New Name"
424
+ basecamp templates delete <id> # Trash template
425
+ basecamp templates construct <id> --name "New Project" # Create project (async)
426
+ basecamp templates construction <template_id> <construction_id> # Check status
427
+ ```
428
+
429
+ **Construct returns construction_id - poll until status="completed" to get project.**
430
+
431
+ ### Webhooks
432
+
433
+ ```bash
434
+ basecamp webhooks list --in <project> --json # List webhooks
435
+ basecamp webhooks show <id> --in <project> # Webhook details
436
+ basecamp webhooks create "https://..." --in <project>
437
+ basecamp webhooks create "https://..." --types "Todo,Comment" --in <project>
438
+ basecamp webhooks update <id> --active --in <project>
439
+ basecamp webhooks update <id> --inactive # Disable
440
+ basecamp webhooks delete <id> --in <project>
441
+ ```
442
+
443
+ **Event types:** Todo, Todolist, Message, Comment, Document, Upload, Vault, Schedule::Entry, Kanban::Card, Question, Question::Answer
444
+
445
+ ### Subscriptions
446
+
447
+ ```bash
448
+ basecamp subscriptions <recording_id> # Who's subscribed
449
+ basecamp subscriptions subscribe <id> # Subscribe yourself
450
+ basecamp subscriptions unsubscribe <id> # Unsubscribe
451
+ basecamp subscriptions add <id> --people 1,2,3 # Add people
452
+ basecamp subscriptions remove <id> --people 1,2,3 # Remove people
453
+ ```
454
+
455
+ ### Lineup (Account-wide Markers)
456
+
457
+ ```bash
458
+ basecamp lineup create "Milestone" "2024-03-15" # Create marker
459
+ basecamp lineup create "Launch" tomorrow # Natural date parsing
460
+ basecamp lineup update <id> "New Name" "+7"
461
+ basecamp lineup delete <id>
462
+ ```
463
+
464
+ **Note:** Lineup markers are account-wide, not project-scoped.
465
+
466
+ ### Campfire
467
+
468
+ ```bash
469
+ basecamp campfire --in <project> --json # List campfires
470
+ basecamp campfire messages --in <project> --json # List messages
471
+ basecamp campfire post "Hello!" --in <project>
472
+ basecamp campfire line <line_id> --in <project> # Show line
473
+ basecamp campfire delete <line_id> --in <project> # Delete line
474
+ ```
475
+
476
+ ### People
477
+
478
+ ```bash
479
+ basecamp people list --json # All people in account
480
+ basecamp people list --project <project> --json # People on project
481
+ basecamp me --json # Current user
482
+ basecamp people show <id> --json # Person details
483
+ basecamp people add <id> --project <project> # Add to project
484
+ basecamp people remove <id> --project <project> # Remove from project
485
+ ```
486
+
487
+ ### Search
488
+
489
+ ```bash
490
+ basecamp search "query" --json # Full-text search
491
+ basecamp search "query" --sort updated_at --limit 20
492
+ basecamp search metadata --json # Available search scopes
493
+ ```
494
+
495
+ ### Generic Show
496
+
497
+ ```bash
498
+ basecamp show <type> <id> --in <project> --json # Show any recording type
499
+ # Types: todo, todolist, message, comment, card, card-table, document (or omit <type> for generic lookup)
500
+ ```
501
+
502
+ ## Configuration
503
+
504
+ The CLI uses two directory namespaces: `basecamp` for your Basecamp identity and project relationships, `basecamp` for tool-specific operational data.
505
+
506
+ ```
507
+ ~/.config/basecamp/ # Basecamp identity (DO NOT read credentials)
508
+ ├── credentials.json # OAuth tokens — NEVER read or log
509
+ ├── client.json # DCR client registration
510
+ └── config.json # Global preferences (account_id, base_url, format)
511
+
512
+ ~/.cache/basecamp/ # Tool cache (ephemeral, auto-managed)
513
+ ├── completion.json # Tab completion cache
514
+ └── resilience/ # Circuit breaker state
515
+
516
+ .basecamp/ # Per-repo config (committed to git)
517
+ └── config.json # Project defaults (project_id, account_id, todolist_id)
518
+ ```
519
+
520
+ **Per-repo config:** `.basecamp/config.json`
521
+
522
+ ```json
523
+ {
524
+ "project_id": "12345",
525
+ "todolist_id": "67890"
526
+ }
527
+ ```
528
+
529
+ **Initialize:**
530
+
531
+ ```bash
532
+ basecamp config init
533
+ basecamp config set project_id <id>
534
+ basecamp config set todolist_id <id>
535
+ ```
536
+
537
+ **Config Trust:**
538
+
539
+ Authority keys (`base_url`, `default_profile`, `profiles`) in local/repo configs are blocked until explicitly trusted. This prevents a cloned repo's config from redirecting OAuth tokens.
540
+
541
+ ```bash
542
+ basecamp config trust # Trust nearest .basecamp/config.json
543
+ basecamp config trust /path/to/.basecamp/config.json # Trust specific config file
544
+ basecamp config trust --list # Show all trusted configs
545
+ basecamp config untrust # Revoke trust for nearest config
546
+ basecamp config untrust /path/to/.basecamp/config.json # Revoke trust for specific path
547
+ ```
548
+
549
+ **Check context:**
550
+
551
+ ```bash
552
+ cat .basecamp/config.json 2>/dev/null || echo "No project configured"
553
+ ```
554
+
555
+ **Global config:** `~/.config/basecamp/config.json` (account_id, base_url, format preferences)
556
+
557
+ ## Error Handling
558
+
559
+ **General diagnostics:**
560
+
561
+ ```bash
562
+ basecamp doctor --json # Check CLI health, auth, connectivity
563
+ ```
564
+
565
+ **Rate limiting (429):** The CLI handles backoff automatically. If you see 429 errors, reduce request frequency.
566
+
567
+ **Authentication errors:**
568
+
569
+ ```bash
570
+ basecamp auth status # Check auth
571
+ basecamp auth login # Re-authenticate
572
+ basecamp auth login --scope full # Full access (BC3 OAuth only)
573
+ ```
574
+
575
+ **Network errors / localhost URLs:**
576
+
577
+ ```bash
578
+ # Check for dev config
579
+ cat ~/.config/basecamp/config.json
580
+ # Should only contain: {"account_id": "<id>"}
581
+ # Remove base_url/api_url if pointing to localhost
582
+ ```
583
+
584
+ **Not found errors:**
585
+
586
+ ```bash
587
+ basecamp auth status # Verify auth working
588
+ cat ~/.config/basecamp/accounts.json # Check available accounts
589
+ ```
590
+
591
+ **Required arguments are positional (not flags):**
592
+
593
+ - `basecamp todo "Buy milk"` (not `--content`)
594
+ - `basecamp card "New feature"` (not `--title`)
595
+ - `basecamp message "Subject" "Body"` (not `--subject`)
596
+ - `basecamp campfire post "Hello"` (not `--content`)
597
+ - `basecamp comment <id> "Text"` (not a flag)
598
+ - `basecamp webhooks create "https://..." --in <project>` (not `--url`)
599
+ - `basecamp checkins answer create <question-id> "content"` (not `--question`)
600
+
601
+ **Missing argument errors (code: "usage"):**
602
+ When a required positional argument is missing, the CLI returns a structured error naming
603
+ the specific argument. Use this for elicitation:
604
+
605
+ ```bash
606
+ $ basecamp todo --json
607
+ {"ok": false, "error": "<content> required", "code": "usage",
608
+ "hint": "Usage: basecamp todo <content>"}
609
+
610
+ $ basecamp comments create 123 --json
611
+ {"ok": false, "error": "<content> required", "code": "usage", ...}
612
+ ```
613
+
614
+ The `error` field names the missing `<arg>` — use it to prompt the user for the specific value.
615
+
616
+ **URL malformed (curl exit 3):** Special characters in content. Use plain text or properly escaped HTML.
617
+
618
+ ## jq Patterns
619
+
620
+ Common data extraction patterns for the output envelope:
621
+
622
+ ```bash
623
+ # Extract fields from data array
624
+ basecamp todos list --in <project> --json | jq '.data[] | select(.completed == false) | .title'
625
+ basecamp todos list --in <project> --json | jq '.data | length'
626
+ basecamp todos list --in <project> --json | jq '.data[] | {id, title, status}'
627
+
628
+ # Access envelope metadata
629
+ basecamp todos list --in <project> --json | jq '.breadcrumbs[0].cmd'
630
+ basecamp todos list --in <project> --json | jq '.meta.stats.requests'
631
+ ```
632
+
633
+ ## Exit Codes
634
+
635
+ | Exit | Meaning | Fix |
636
+ | ---- | ------------- | ------------------------------------------------------------------- |
637
+ | 0 | OK | — |
638
+ | 1 | Usage error | Check `basecamp <cmd> --help` |
639
+ | 2 | Not found | Verify ID/URL exists |
640
+ | 3 | Auth error | `basecamp auth login` |
641
+ | 4 | Forbidden | Check account/project permissions |
642
+ | 5 | Rate limit | Wait and retry (resilience layer handles Retry-After automatically) |
643
+ | 6 | Network error | Check connectivity, `basecamp doctor` |
644
+ | 7 | API error | Retry; if persistent, check `basecamp doctor` |
645
+ | 8 | Ambiguous | Be more specific (use ID instead of name) |
646
+
647
+ ## Learn More
648
+
649
+ - API concepts: https://github.com/basecamp/bc3-api#key-concepts
650
+ - CLI repo: https://github.com/basecamp/basecamp-cli
651
+ - API coverage: See API-COVERAGE.md in the CLI repo
@@ -56,6 +56,7 @@ python3 .agents/skills/everhour-basecamp-estimates/scripts/update_estimates.py \
56
56
  - A scalar estimate is applied to each active todo.
57
57
  - A JSON estimate array is applied in active-todo order and must match the active todo count exactly.
58
58
  - It matches Basecamp titles against Everhour task names inside the configured project.
59
+ - If multiple Everhour tasks have the same normalized title, it selects the task whose Everhour task id or URL maps to the Basecamp todo id.
59
60
  - Matching is exact after normalization:
60
61
  - trim whitespace
61
62
  - collapse repeated spaces
@@ -67,7 +68,7 @@ python3 .agents/skills/everhour-basecamp-estimates/scripts/update_estimates.py \
67
68
  ## Guardrails
68
69
 
69
70
  - If any Basecamp title has no Everhour match, stop and report it.
70
- - If any Basecamp title matches more than one Everhour task, stop and report the ambiguity.
71
+ - If any Basecamp title matches more than one Everhour task and the Basecamp todo id cannot resolve one task, stop and report the ambiguity.
71
72
  - If an estimate array length does not match the active todo count, stop before any updates.
72
73
  - If the provided todo URL is already completed, stop without updating anything.
73
74
  - Do not update Basecamp titles before Everhour updates complete.