| name | basecamp |
| description | Interact with Basecamp via the Basecamp CLI. Full API coverage: projects, todos, cards,
messages, files, schedule, check-ins, timeline, recordings, templates, webhooks,
subscriptions, lineup, chat, gauges, assignments, notifications, and accounts.
Use for ANY Basecamp question or action.
|
| triggers | ["basecamp","/basecamp","basecamp todo","basecamp project","basecamp card","basecamp chat","basecamp campfire","basecamp message","basecamp file","basecamp document","basecamp schedule","basecamp checkin","basecamp check-in","basecamp timeline","basecamp template","basecamp webhook","basecamp gauge","basecamp assignment","basecamp notification","basecamp account","link to basecamp","track in basecamp","post to basecamp","comment on basecamp","complete todo","mark done","create todo","move card","download file","search basecamp","find in basecamp","look up basecamp","check basecamp","list basecamp","show basecamp","get from basecamp","fetch from basecamp","can I basecamp","how do I basecamp","what's in basecamp","what basecamp","does basecamp","my todos","my tasks","my schedule","my basecamp","assigned to me","my assignments","my notifications","overdue todos","upcoming events","project gauge","project progress","3.basecamp.com","basecampapi.com","https://3.basecamp.com/"] |
| invocable | true |
| argument-hint | [action] [args...] |
/basecamp - Basecamp Workflow Command
Full CLI coverage: 155 endpoints across todos, cards, messages, files, schedule, check-ins, timeline, recordings, templates, webhooks, subscriptions, lineup, chat, gauges, assignments, notifications, and accounts.
Agent Invariants
MUST follow these rules:
- Choose the right output mode —
--jq when you need to filter/extract data; --json for full JSON; --md when presenting results to a human (see Output Modes below). Never pipe to external jq — use --jq instead.
- Parse URLs first with
basecamp url parse "<url>" to extract IDs
- Comments are flat - reply to parent recording, not to comments
- Check context via
.basecamp/config.json before assuming project
- Content fields accept Markdown and @mentions — 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. Four mention syntaxes are available (prefer deterministic for agents):
[@Name](mention:SGID) — zero API calls, embeds SGID directly (preferred for agents)
[@Name](person:ID) — one API call, resolves person ID to SGID via pingable set
@sgid:VALUE — inline SGID embed for pipeline composability
@Name / @First.Last — fuzzy name resolution (may be ambiguous)
For todos, documents, and cards, content is sent as-is — use plain text or HTML directly.
- Project scope is mandatory for most commands — via
--in <project> or .basecamp/config.json. Cross-project exceptions: basecamp reports assigned for assigned work, basecamp assignments for structured assignment views, basecamp reports overdue for overdue todos, basecamp reports schedule for upcoming schedule across all projects, basecamp recordings <type> for browsing by type, basecamp notifications for notifications, basecamp gauges list for account-wide gauges.
Output Modes
Choosing a mode:
| Goal | Flag | Format |
|---|
| Filter/extract JSON data | --jq '<expr>' | Built-in jq filter (no external jq needed). Implies --json; filter runs on the envelope. |
| Filter in agent mode | --agent --jq '<expr>' | Filter runs on data-only payload (no envelope), matching --agent contract. |
| Full JSON output | --json | JSON envelope: {ok, data, summary, breadcrumbs, meta} |
| Show results to a user | --md / -m | GFM tables, task lists, structured Markdown |
| Automation / scripting | --agent | Success: raw JSON data (no envelope); errors: {ok:false,...} object; no interactive prompts |
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.
Other modes: --quiet (success: raw JSON, no envelope; errors: {ok:false,...}), --ids-only, --count, --stats (session statistics), --styled (force ANSI), -v / -vv (verbose/trace), --jq '<expr>' (built-in jq filter — see below).
CLI Introspection
Navigate unfamiliar commands with --agent --help — returns structured JSON describing any command:
basecamp todos --agent --help
{"command":"todos","path":"basecamp todos","short":"...","long":"...","usage":"...","notes":["..."],
"subcommands":[{"name":"sweep","short":"...","path":"basecamp todos sweep"}],
"flags":[{"name":"assignee","type":"string","default":"","usage":"..."}],
"inherited_flags":[{"name":"json","shorthand":"j","type":"bool","default":"false","usage":"..."}]}
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").
Pagination
basecamp <cmd> --limit 50
basecamp <cmd> --all
basecamp <cmd> --page 1
--all and --limit are mutually exclusive. --page cannot combine with either.
Smart Defaults
--assignee me resolves to current user
--due tomorrow / --due +3 / --due "next week" - natural date parsing
- Project from
.basecamp/config.json if --in not specified
Quick Reference
Note: Most queries require project scope (via --in <project> or .basecamp/config.json). Cross-project exceptions: basecamp reports assigned, basecamp assignments, basecamp reports overdue, basecamp reports schedule, basecamp recordings <type>, basecamp notifications, basecamp gauges list.
| Task | Command |
|---|
| List projects | basecamp projects list --json |
| My todos (in project) | basecamp todos list --assignee me --in <project> --json |
| My todos (cross-project) | basecamp reports assigned --json (defaults to "me") |
| My schedule (cross-project) | basecamp reports schedule --json (upcoming events across all projects) |
| All todos (cross-project) | basecamp recordings todos --json (no assignee data — cannot filter by person) |
| Overdue todos (in project) | basecamp todos list --overdue --in <project> --json |
| Overdue todos (cross-project) | basecamp reports overdue --json |
| Assign todo | basecamp assign <id> [id...] --to <person> --in <project> --json |
| Assign card | basecamp assign <id> [id...] --card --to <person> --in <project> --json |
| Assign card step | basecamp assign <id> [id...] --step --to <person> --in <project> --json |
| Create todo | basecamp todo "Task" --in <project> --list <list> --json |
| Create todolist | basecamp todolists create "Name" --in <project> --json |
| Complete todo | basecamp done <id> --json |
| List cards | basecamp cards list --in <project> --json |
| Create card | basecamp card "Title" --in <project> --json |
| Move card | basecamp cards move <id> --to <column> [--position N] --in <project> --json |
| Move card to on-hold | basecamp cards move <id> --on-hold --in <project> --json |
| Post message | basecamp message "Title" "Body" --in <project> --json |
| Post with @mention | basecamp message "Title" "Hey @First.Last, ..." --in <project> --json |
| Post silently | basecamp message "Title" "Body" --no-subscribe --in <project> --json |
| Post to chat | basecamp chat post "Message" --in <project> --json |
| Add comment | basecamp comment <recording_id> "Text" --in <project> --json |
| List attachments | basecamp attachments list <id|url> --json |
| Download attachments | basecamp attachments download <id> --out /tmp/ |
| Show + download | basecamp todos show <id> --download-attachments --json |
| Stream attachment to stdout | basecamp attachments download <id> --file <name> --out - |
| Search | basecamp search "query" --json |
| Parse URL | basecamp url parse "<url>" --json |
| Upload file | basecamp files uploads create <file> [--vault <folder_id>] --in <project> --json |
| Download file | basecamp files download <id> --in <project> |
| Stream file to stdout | basecamp files download <id> --out - --in <project> |
| Download storage URL | basecamp files download "https://storage.3.basecamp.com/.../download/report.pdf" |
| My assignments | basecamp assignments --json (priorities + non-priorities) |
| Overdue assignments | basecamp assignments due overdue --json |
| Completed assignments | basecamp assignments completed --json |
| Notifications | basecamp notifications --json |
| Mark notification read | basecamp notifications read <id> --json |
| Gauges (account-wide) | basecamp gauges list --json |
| Gauge needles | basecamp gauges needles --in <project> --json |
| Create needle | basecamp gauges create --position 75 --color green --in <project> --json |
| Account details | basecamp accounts show --json |
| Watch timeline | basecamp timeline --watch |
URL Parsing
Always parse URLs before acting on them:
basecamp url parse "https://3.basecamp.com/2914079/buckets/41746046/messages/9478142982#__recording_9488783598" --json
Returns: account_id, project_id, type, recording_id, comment_id (from fragment).
URL patterns:
/buckets/27/messages/123 - Message 123 in project 27
/buckets/27/messages/123#__recording_456 - Comment 456 on message 123
/buckets/27/card_tables/cards/789 - Card 789
/buckets/27/card_tables/columns/456 - Column 456 (for creating cards)
/buckets/27/todos/101 - Todo 101
/buckets/27/uploads/202 - Upload/file 202
/buckets/27/documents/303 - Document 303
/buckets/27/schedule_entries/404 - Schedule entry 404
Replying to comments:
basecamp url parse "https://...messages/123#__recording_456" --json
basecamp comment 123 "Reply" --in <project>
Decision Trees
Finding Content
Need to find something?
├── Know the type + project? → basecamp <type> list --in <project> --json
│ (some groups have default list behavior; use --agent --help if unsure)
├── My assigned work? → basecamp assignments --json (priorities + non-priorities)
│ Or: basecamp reports assigned --json (traditional view, defaults to "me")
├── My overdue assignments? → basecamp assignments due overdue --json
├── My notifications? → basecamp notifications --json
├── Upcoming schedule? → basecamp reports schedule --json (cross-project)
├── Overdue across projects? → basecamp reports overdue --json
├── Browse by type cross-project? → basecamp recordings <type> --json
│ (types: todos, messages, documents, comments, cards, uploads)
│ Note: Defaults to active status; use --status archived for archived items
│ ⚠ No assignee data — cannot filter by person; use reports assigned instead
├── Full-text search? → basecamp search "query" --json
└── Have a URL? → basecamp url parse "<url>" --json
Modifying Content
Want to change something?
├── Have URL? → basecamp url parse "<url>" → use extracted IDs
├── Have ID? → basecamp <resource> update <id> --field value
├── Change status? → basecamp recordings trash|archive|restore <id>
└── Complete todo? → basecamp done <id>
Common Workflows
Link Code to Basecamp Todo
COMMIT=$(git rev-parse --short HEAD)
MSG=$(git log -1 --format=%s)
basecamp comment <todo_id> "Commit $COMMIT: $(printf '%s' "$MSG")" --in <project>
basecamp done <todo_id>
Track PR in Basecamp
basecamp todo "Review PR #42" --in <project> --assignee me --due tomorrow
basecamp done <todo_id>
basecamp chat post "Merged PR #42" --in <project>
Bulk Process Overdue Todos
basecamp todos sweep --overdue --dry-run --in <project>
basecamp todos sweep --overdue --complete --comment "Cleaning up" --in <project>
Mentioning people (preferred — deterministic)
basecamp people pingable --jq '.data[] | select(.name == "Jane Smith")'
basecamp comment 123 "Hey [@Jane Smith](mention:BAh7CEkiCG...), check this" --in <project>
basecamp comment 123 "Hey [@Jane Smith](person:42000), check this" --in <project>
Mentioning people (interactive — may be ambiguous)
basecamp comment <id> "@Jane.Smith, please review this" --in <project>
basecamp message "Update" "cc @Jane, @Alex" --in <project>
basecamp chat post "@Jane, done!" --in <project>
Move Card Through Workflow
basecamp cards columns --in <project> --json
basecamp cards move <card_id> --to <column_id> --in <project>
basecamp cards move <card_id> --to <column_id> --position 1 --in <project>
basecamp cards move <card_id> --on-hold --in <project>
basecamp cards move <card_id> --to <column_id> --on-hold --in <project>
basecamp cards move <card_id> --to "Column Name" --on-hold --card-table <table_id> --in <project>
Download File from Basecamp
basecamp files download <upload_id> --in <project> --out ./downloads
basecamp files download "https://storage.3.basecamp.com/123/blobs/abc/download/report.pdf"
basecamp files download <upload_id> --out - --in <project>
Working with Attachments (Multimodal Agent Workflow)
Messages, todos, cards, and documents may contain images and file attachments
(mockups, screenshots, annotated designs). Show commands surface these as
field-scoped collections — content_attachments and/or description_attachments
— keyed by which rich-text attribute contained them. The notice field hints at
the download command.
Step 1: Fetch the recording and check for attachments
basecamp todos show <id> --json
Step 2 (one-shot): Download attachments with the show command
basecamp todos show <id> --download-attachments --json
Step 2 (two-step alternative): Download separately
basecamp attachments download <id> --out /tmp/attachments
Step 3: View images with your native file-read tool
For multimodal LLMs (Claude, Gemini), use your file-read tool on the path
from the response to view downloaded images directly — no browser needed.
This surfaces visual context (mockups, screenshots, annotated designs) that
is often the most important part of a Basecamp todo or message.
basecamp attachments download <id> --file mockup.png --out -
basecamp attachments download <id> --index 2 --out -
Key pattern: When a show command response contains content_attachments
or description_attachments, always download and view them — visual context is
often more important than the text content. Use --download-attachments for
one-shot fetch+download, or follow the breadcrumb hint for two-step control.
Resource Reference
Projects
basecamp projects list --json
basecamp projects show <id> --json
basecamp projects create "Name" --json
basecamp projects update <id> --name "New"
Todos
basecamp todos list --in <project> --json
basecamp todos list --assignee me --in <project>
basecamp todos list --overdue --in <project>
basecamp todos list --status completed --in <project>
basecamp todos list --list <todolist_id> --in <project>
basecamp todo "Task" --in <project> --list <list> --assignee me --due tomorrow
basecamp done <id> [id...]
basecamp reopen <id>
basecamp assign <id> [id...] --to <person> --in <project>
basecamp unassign <id> [id...] --from <person> --in <project>
basecamp assign <id> [id...] --card --to <person> --in <project>
basecamp unassign <id> [id...] --card --from <person> --in <project>
basecamp assign <id> [id...] --step --to <person> --in <project>
basecamp unassign <id> [id...] --step --from <person> --in <project>
basecamp todos position <id> --to 1
basecamp todos position <id> --to 1 --list <id|name|url>
basecamp todos sweep --overdue --complete --comment "Done" --in <project>
Flags: --assignee (todos only - not available on cards/messages), --status (completed/incomplete), --overdue, --list, --due, --limit, --all
Todolists
Todolists are containers for todos. Create a todolist before adding todos.
basecamp todolists list --in <project> --json
basecamp todolists show <id> --in <project>
basecamp todolists create "Name" --in <project> --json
basecamp todolists create "Name" --description "Desc" --in <project>
basecamp todolists update <id> --name "New" --in <project>
Cards (Kanban)
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.
basecamp cards list --in <project> --json
basecamp cards list --card-table <id> --in <project>
basecamp cards list --column <id> --in <project>
basecamp cards columns --in <project> --json
basecamp cards show <id> --in <project>
basecamp card "Title" "<p>Body</p>" --in <project> --column <id>
basecamp cards update <id> --title "New" --due tomorrow --assignee me
basecamp cards move <id> --to <column_id>
basecamp cards move <id> --to "Done" --card-table <table_id>
basecamp cards move <id> --to "Done" --position 1 --card-table <table_id>
basecamp cards move <id> --on-hold
basecamp cards move <id> --to <column_id> --on-hold
Archived/trashed cards: cards list only returns active cards. For archived or trashed cards, use basecamp recordings cards --status archived --in <project> or --status trashed.
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.
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.
Card Steps (checklists):
basecamp cards steps <card_id> --in <project>
basecamp cards step create "Step" --card <id> --in <project>
basecamp cards step complete <step_id> --in <project>
basecamp cards step uncomplete <step_id>
Column management:
basecamp cards column show <id> --in <project>
basecamp cards column create "Name" --in <project>
basecamp cards column update <id> --title "New"
basecamp cards column move <id> --position 2
basecamp cards column color <id> --color blue
basecamp cards column on-hold <id>
basecamp cards column watch <id>
Messages
basecamp messages list --in <project> --json
basecamp messages show <id> --in <project>
basecamp message "Title" "Body" --in <project>
basecamp message "Draft" "WIP" --draft --in <project>
basecamp messages publish <id>
basecamp messages update <id> --title "New" --body "Updated"
basecamp messages pin <id> --in <project>
basecamp messages unpin <id>
Archived/trashed messages: messages list only returns active messages. For archived or trashed messages, use basecamp recordings messages --status archived --in <project> or --status trashed.
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)
basecamp message "Bot update" "Done" --no-subscribe --in <project>
basecamp message "FYI" "Note" --subscribe "Alice,bob@x.com" --in <project>
Comments
basecamp comments list <recording_id> --in <project> --json
basecamp comment <recording_id> "Text" --in <project>
basecamp comment <recording_id> "@Jane.Smith, looks good!" --in <project>
basecamp comments update <id> "Updated" --in <project>
Files & Documents
basecamp files list --in <project> --json
basecamp files list --vault <folder_id> --in <project>
basecamp files show <id> --in <project>
basecamp files download <id> --in <project>
basecamp files download <id> --out ./dir
basecamp files download "https://storage.../download/f"
basecamp files uploads create <file> --in <project>
basecamp files uploads create <file> --vault <folder_id> --in <project>
basecamp files folder create "Folder" --in <project>
basecamp files doc create "Doc" "Body" --in <project>
basecamp files doc create "Draft" --draft --in <project>
basecamp files doc create "Notes" "..." --no-subscribe --in <project>
basecamp files update <id> --title "New" --content "Updated"
Subcommands: folders, uploads, documents (each with pagination flags)
Schedule
For upcoming events across all projects, use basecamp reports schedule --json.
basecamp schedule info --in <project> --json
basecamp schedule entries --in <project> --json
basecamp schedule show <id> --in <project>
basecamp schedule show <id> --date 20240315
basecamp schedule create "Event" --starts-at "2024-03-15T09:00:00Z" --ends-at "2024-03-15T10:00:00Z" --in <project>
basecamp schedule create "Meeting" --all-day --notify --participants 1,2,3 --in <project>
basecamp schedule create "Sync" --starts-at "..." --ends-at "..." --no-subscribe --in <project>
basecamp schedule update <id> --summary "New title" --starts-at "..."
basecamp schedule settings --include-due --in <project>
Flags: --all-day, --notify, --participants <ids>, --no-subscribe, --subscribe "people" (mutually exclusive), --status (active/archived/trashed)
Check-ins
basecamp checkins --in <project> --json
basecamp checkins questions --in <project>
basecamp checkins question <id> --in <project>
basecamp checkins answers <question_id> --in <project>
basecamp checkins answer <id> --in <project>
basecamp checkins question create "What did you work on?" --in <project>
basecamp checkins question update <id> "New question" --frequency every_week
basecamp checkins answer create <question-id> "My answer" --in <project>
basecamp checkins answer update <id> "Updated" --in <project>
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"
Timeline
basecamp timeline --json
basecamp timeline --in <project> --json
basecamp timeline me --json
basecamp timeline --person <id> --json
basecamp timeline --watch
basecamp timeline --watch --interval 60
Use --limit N to cap results or --all to fetch everything (default: 100 events). --all and --page cannot be combined with --watch.
Recordings (Cross-project)
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.
basecamp recordings todos --json
basecamp recordings todos --all --json
basecamp recordings messages --in <project>
basecamp recordings documents --status archived
basecamp recordings cards --sort created_at --direction asc
basecamp recordings cards --status archived --all --json
Types: todos, messages, documents, comments, cards, uploads
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).
Status management:
basecamp recordings trash <id> --in <project>
basecamp recordings archive <id> --in <project>
basecamp recordings restore <id> --in <project>
basecamp recordings visibility <id> --visible --in <project>
basecamp recordings visibility <id> --hidden
Templates
basecamp templates --json
basecamp templates show <id> --json
basecamp templates create "Template Name"
basecamp templates update <id> --name "New Name"
basecamp templates delete <id>
basecamp templates construct <id> --name "New Project"
basecamp templates construction <template_id> <construction_id>
Construct returns construction_id - poll until status="completed" to get project.
Webhooks
basecamp webhooks list --in <project> --json
basecamp webhooks show <id> --in <project>
basecamp webhooks create "https://..." --in <project>
basecamp webhooks create "https://..." --types "Todo,Comment" --in <project>
basecamp webhooks update <id> --active --in <project>
basecamp webhooks update <id> --inactive
basecamp webhooks delete <id> --in <project>
Event types: Todo, Todolist, Message, Comment, Document, Upload, Vault, Schedule::Entry, Kanban::Card, Question, Question::Answer
Subscriptions
basecamp subscriptions <recording_id>
basecamp subscriptions subscribe <id>
basecamp subscriptions unsubscribe <id>
basecamp subscriptions add <id> --people 1,2,3
basecamp subscriptions remove <id> --people 1,2,3
Lineup (Account-wide Markers)
basecamp lineup list
basecamp lineup create "Milestone" "2024-03-15"
basecamp lineup create "Launch" tomorrow
basecamp lineup update <id> "New Name" "+7"
basecamp lineup delete <id>
Note: Lineup markers are account-wide, not project-scoped.
Gauges
Gauges track project progress with colored needles on a 0-100 scale.
basecamp gauges list --json
basecamp gauges needles --in <project> --json
basecamp gauges needle <id> --json
basecamp gauges create --position 75 --color green --in <project>
basecamp gauges create --position 50 --color yellow --description "Halfway" --in <project>
basecamp gauges create --position 25 --notify custom --subscriptions 1,2 --in <project>
basecamp gauges update <id> --description "Updated"
basecamp gauges delete <id>
basecamp gauges enable --in <project>
basecamp gauges disable --in <project>
Colors: green, yellow, red. Notify: everyone, working_on, custom (with --subscriptions).
Assignments
View your assignments across all projects. Separate from reports assigned — provides structured priority grouping and due-date scoping.
basecamp assignments --json
basecamp assignments list --json
basecamp assignments completed --json
basecamp assignments due overdue --json
basecamp assignments due due_today --json
basecamp assignments due due_tomorrow --json
basecamp assignments due due_later_this_week --json
Scopes: overdue, due_today, due_tomorrow, due_later_this_week, due_next_week, due_later.
Notifications
basecamp notifications --json
basecamp notifications list --page 2 --json
basecamp notifications read <id> --json
basecamp notifications read <id> <id> --page 2 --json
Note: read resolves notification IDs from the specified page. Use --page to match the page you listed.
Accounts
basecamp accounts list --json
basecamp accounts use <id>
basecamp accounts show --json
basecamp accounts update --name "New Name" --json
basecamp accounts logo upload <file> --json
basecamp accounts logo remove --json
Chat
basecamp chat --in <project> --json
basecamp chat messages --in <project> --json
basecamp chat post "Hello!" --in <project>
basecamp chat post "@Jane.Smith, check this" --in <project>
basecamp chat line <line_id> --in <project>
basecamp chat delete <line_id> --in <project> --force
People
basecamp people list --json
basecamp people list --project <project> --json
basecamp me --json
basecamp people show <id> --json
basecamp people add <id> --project <project>
basecamp people remove <id> --project <project>
Search
basecamp search "query" --json
basecamp search "query" --sort updated_at --limit 20
basecamp search metadata --json
Generic Show
basecamp show <type> <id> --in <project> --json
Configuration
The CLI uses two directory namespaces: basecamp for your Basecamp identity and project relationships, basecamp for tool-specific operational data.
~/.config/basecamp/ # Basecamp identity (DO NOT read credentials)
├── credentials.json # OAuth tokens — NEVER read or log
├── client.json # DCR client registration
└── config.json # Global preferences (account_id, base_url, format)
~/.cache/basecamp/ # Tool cache (ephemeral, auto-managed)
├── completion.json # Tab completion cache
└── resilience/ # Circuit breaker state
.basecamp/ # Per-repo config (committed to git)
└── config.json # Project defaults (project_id, account_id, todolist_id)
Per-repo config: .basecamp/config.json
{
"project_id": "12345",
"todolist_id": "67890"
}
Initialize:
basecamp config init
basecamp config set project_id <id>
basecamp config set todolist_id <id>
Config Trust:
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.
basecamp config trust
basecamp config trust /path/to/.basecamp/config.json
basecamp config trust --list
basecamp config untrust
basecamp config untrust /path/to/.basecamp/config.json
Check context:
cat .basecamp/config.json 2>/dev/null || echo "No project configured"
Global config: ~/.config/basecamp/config.json (account_id, base_url, format preferences)
Error Handling
General diagnostics:
basecamp doctor --json
Rate limiting (429): The CLI handles backoff automatically. If you see 429 errors, reduce request frequency.
Authentication errors:
basecamp auth status
basecamp auth login
basecamp auth login --scope full
basecamp auth login --device-code
Network errors / localhost URLs:
cat ~/.config/basecamp/config.json
Not found errors:
basecamp auth status
cat ~/.config/basecamp/accounts.json
Required arguments are positional (not flags):
basecamp todo "Buy milk" (not --content)
basecamp card "New feature" (not --title)
basecamp message "Subject" "Body" (not --subject)
basecamp chat post "Hello" (not --content)
basecamp comment <id> "Text" (not a flag)
basecamp webhooks create "https://..." --in <project> (not --url)
basecamp checkins answer create <question-id> "content" (not --question)
--date YYYY-MM-DD is optional for checkins answer create; if omitted, it defaults to today
Missing argument errors (code: "usage"):
When a required positional argument is missing, the CLI returns a structured error naming
the specific argument. Use this for elicitation:
$ basecamp todo --json
{"ok": false, "error": "<content> required", "code": "usage",
"hint": "Usage: basecamp todo <content>"}
$ basecamp comments create 123 --json
{"ok": false, "error": "<content> required", "code": "usage", ...}
The error field names the missing <arg> — use it to prompt the user for the specific value.
URL malformed (curl exit 3): Special characters in content. Use plain text or properly escaped HTML.
Built-in jq Filtering
The CLI has a built-in --jq flag powered by gojq — no external jq binary required. Always prefer --jq over piping to external jq.
basecamp todos list --in <project> --jq '.data[] | select(.completed == false) | .title'
basecamp todos list --in <project> --jq '.data | length'
basecamp todos list --in <project> --jq '[.data[] | {id, title, status}]'
basecamp todos list --in <project> --jq '.breadcrumbs[0].cmd'
basecamp todos list --in <project> --jq '.meta.stats.requests'
basecamp cards list --in <project> --jq '[.data[] | select(.completed == true) | .title]'
basecamp people list --jq '[.data[] | {name: .name, email: .email_address}]'
--jq implies --json — no need to pass both. String results print as plain text; objects and arrays print as formatted JSON.
Exit Codes
| Exit | Meaning | Fix |
|---|
| 0 | OK | — |
| 1 | Usage error | Check basecamp <cmd> --help |
| 2 | Not found | Verify ID/URL exists |
| 3 | Auth error | basecamp auth login |
| 4 | Forbidden | Check account/project permissions |
| 5 | Rate limit | Wait and retry (resilience layer handles Retry-After automatically) |
| 6 | Network error | Check connectivity, basecamp doctor |
| 7 | API error | Retry; if persistent, check basecamp doctor |
| 8 | Ambiguous | Be more specific (use ID instead of name) |
Learn More