basecamp

|

INSTALLATION
npx skills add https://github.com/basecamp/skills --skill basecamp
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

$27

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   # Cap results (default varies by resource)

basecamp <cmd> --all        # Fetch all (may be slow for large datasets)

basecamp <cmd> --page 1     # First page only, no auto-pagination

--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:

# Comments are flat - reply to the parent recording_id, not the comment_id

basecamp url parse "https://...messages/123#__recording_456" --json

# Returns recording_id: 123 (parent), comment_id: 456 (fragment) - comment on 123, not 456

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

# Get commit info and comment on todo (use printf %q for safe quoting)

COMMIT=$(git rev-parse --short HEAD)

MSG=$(git log -1 --format=%s)

basecamp comment <todo_id> "Commit $COMMIT: $(printf '%s' "$MSG")" --in <project>

# Complete when done

basecamp done <todo_id>

Track PR in Basecamp

# Create todo for PR work

basecamp todo "Review PR #42" --in <project> --assignee me --due tomorrow

# When merged

basecamp done <todo_id>

basecamp chat post "Merged PR #42" --in <project>

Bulk Process Overdue Todos

# Preview overdue todos

basecamp todos sweep --overdue --dry-run --in <project>

# Complete all with comment

basecamp todos sweep --overdue --complete --comment "Cleaning up" --in <project>

Mentioning people (preferred — deterministic)

# 1. Look up the person

basecamp people pingable --jq '.data[] | select(.name == "Jane Smith")'

# => {"id": 42000, "attachable_sgid": "BAh7CEkiCG...", "name": "Jane Smith"}

# 2. Use SGID in Markdown mention syntax (zero API calls during post)

basecamp comment 123 "Hey [@Jane Smith](mention:BAh7CEkiCG...), check this" --in <project>

# Or use person ID (one lookup during post)

basecamp comment 123 "Hey [@Jane Smith](person:42000), check this" --in <project>

Mentioning people (interactive — may be ambiguous)

# Fuzzy matching: use @First.Last to reduce ambiguity

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>

# Ambiguous names return an error with suggestions

# Use @First.Last for disambiguation

Move Card Through Workflow

# List columns to get IDs

basecamp cards columns --in <project> --json

# Move card to column

basecamp cards move <card_id> --to <column_id> --in <project>

# Move card to specific position in column (1-indexed)

basecamp cards move <card_id> --to <column_id> --position 1 --in <project>

# Move card to on-hold section of its current column

basecamp cards move <card_id> --on-hold --in <project>

# Move card to on-hold section of a specific column (numeric ID)

basecamp cards move <card_id> --to <column_id> --on-hold --in <project>

# Move card to on-hold section of a named column (requires --card-table)

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

# Download attachment from a storage URL (no --in needed)

basecamp files download "https://storage.3.basecamp.com/123/blobs/abc/download/report.pdf"

# Stream to stdout (for piping)

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

# Response includes description_attachments when attachments are present

# Messages/documents use content_attachments; cards may have both

# The notice field hints: "3 attachment(s) — download: basecamp attachments download <id>"

Step 2 (one-shot): Download attachments with the show command

# --download-attachments fetches + downloads in one shot

basecamp todos show <id> --download-attachments --json

# content_attachments/description_attachments entries now include "path" pointing to local files

# Downloads to OS temp dir by default, or specify: --download-attachments /tmp/att

Step 2 (two-step alternative): Download separately

# Download all at once (shows progress on stderr)

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.

# Stream a single image to stdout for piping

basecamp attachments download <id> --file mockup.png --out -

# Select by index when names collide

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               # List all

basecamp projects show <id> --json          # Show details

basecamp projects create "Name" --json      # Create

basecamp projects update <id> --name "New"  # Update

Todos

basecamp todos list --in <project> --json               # List in project

basecamp todos list --assignee me --in <project>        # My todos

basecamp todos list --overdue --in <project>            # Overdue only

basecamp todos list --status completed --in <project>   # Completed

basecamp todos list --list <todolist_id> --in <project> # In specific list

basecamp todo "Task" --in <project> --list <list> --assignee me --due tomorrow

basecamp done <id> [id...]                              # Complete (multiple OK)

basecamp reopen <id>                                    # Uncomplete

basecamp assign <id> [id...] --to <person> --in <project>       # Assign to-do (multiple OK)

basecamp unassign <id> [id...] --from <person> --in <project>   # Remove to-do assignee (multiple OK)

basecamp assign <id> [id...] --card --to <person> --in <project>   # Assign card

basecamp unassign <id> [id...] --card --from <person> --in <project> # Remove card assignee

basecamp assign <id> [id...] --step --to <person> --in <project>   # Assign card step

basecamp unassign <id> [id...] --step --from <person> --in <project> # Remove step assignee

basecamp todos position <id> --to 1                     # Move to top

basecamp todos position <id> --to 1 --list <id|name|url> # Move to different list

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              # List todolists

basecamp todolists show <id> --in <project>                # Show details

basecamp todolists create "Name" --in <project> --json     # Create

basecamp todolists create "Name" --description "Desc" --in <project>

basecamp todolists update <id> --name "New" --in <project> # Update

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             # All cards

basecamp cards list --card-table <id> --in <project>  # Specific table (required if multiple)

basecamp cards list --column <id> --in <project>      # Cards in column

basecamp cards columns --in <project> --json          # List columns (needs --card-table if multiple)

basecamp cards show <id> --in <project>               # Card details

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>             # Move to column (numeric ID)

basecamp cards move <id> --to "Done" --card-table <table_id>  # Move by name (needs table)

basecamp cards move <id> --to "Done" --position 1 --card-table <table_id>  # Move to position

basecamp cards move <id> --on-hold                    # Move to on-hold of current column

basecamp cards move <id> --to <column_id> --on-hold   # Move to on-hold of target column

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>     # List steps

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>                # Enable on-hold section

basecamp cards column watch <id>                  # Subscribe to column

Messages

basecamp messages list --in <project> --json  # List messages

basecamp messages show <id> --in <project>    # Show message

basecamp message "Title" "Body" --in <project>

basecamp message "Draft" "WIP" --draft --in <project>  # Create draft

basecamp messages publish <id>               # Publish a draft

basecamp messages update <id> --title "New" --body "Updated"

basecamp messages pin <id> --in <project>     # Pin to top

basecamp messages unpin <id>                  # Unpin

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>  # With @mention

basecamp comments update <id> "Updated" --in <project>

Files &#x26; Documents

basecamp files list --in <project> --json               # List all (folders, files, docs)

basecamp files list --vault <folder_id> --in <project>  # List folder contents

basecamp files show <id> --in <project>                 # Show item (auto-detects type)

basecamp files download <id> --in <project>             # Download file

basecamp files download <id> --out ./dir                # Download to specific dir

basecamp files download "https://storage.../download/f" # Download from storage URL

basecamp files uploads create <file> --in <project>      # Upload file to root

basecamp files uploads create <file> --vault <folder_id> --in <project>  # Upload to folder

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       # Schedule info

basecamp schedule entries --in <project> --json   # List entries

basecamp schedule show <id> --in <project>        # Entry details

basecamp schedule show <id> --date 20240315       # Specific occurrence (recurring)

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>  # Include todos/cards due dates

Flags: --all-day, --notify, --participants <ids>, --no-subscribe, --subscribe "people" (mutually exclusive), --status (active/archived/trashed)

Check-ins

basecamp checkins --in <project> --json           # Questionnaire info

basecamp checkins questions --in <project>        # List questions

basecamp checkins question <id> --in <project>    # Question details

basecamp checkins answers <question_id> --in <project>  # List answers

basecamp checkins answer <id> --in <project>      # Answer details

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>  # Defaults to today

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                          # Account-wide activity

basecamp timeline --in <project> --json           # Project activity

basecamp timeline me --json                       # Your activity

basecamp timeline --person <id> --json            # Person's activity

basecamp timeline --watch                         # Live monitoring (TUI)

basecamp timeline --watch --interval 60           # Poll every 60 seconds

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                  # All todos across projects

basecamp recordings todos --all --json            # All todos (paginate through all)

basecamp recordings messages --in <project>       # Messages in project

basecamp recordings documents --status archived   # Archived docs

basecamp recordings cards --sort created_at --direction asc

basecamp recordings cards --status archived --all --json  # Include archived cards

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>     # Move to trash

basecamp recordings archive <id> --in <project>   # Archive

basecamp recordings restore <id> --in <project>   # Restore to active

basecamp recordings visibility <id> --visible --in <project>  # Show to clients

basecamp recordings visibility <id> --hidden      # Hide from clients

Templates

basecamp templates --json                         # List templates

basecamp templates show <id> --json               # Template details

basecamp templates create "Template Name"         # Create empty template

basecamp templates update <id> --name "New Name"

basecamp templates delete <id>                    # Trash template

basecamp templates construct <id> --name "New Project"  # Create project (async)

basecamp templates construction <template_id> <construction_id>  # Check status

Construct returns construction_id - poll until status="completed" to get project.

Webhooks

basecamp webhooks list --in <project> --json  # List webhooks

basecamp webhooks show <id> --in <project>    # Webhook details

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      # Disable

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>              # Who's subscribed

basecamp subscriptions subscribe <id>              # Subscribe yourself

basecamp subscriptions unsubscribe <id>            # Unsubscribe

basecamp subscriptions add <id> --people 1,2,3     # Add people

basecamp subscriptions remove <id> --people 1,2,3  # Remove people

Lineup (Account-wide Markers)

basecamp lineup list                              # List all markers

basecamp lineup create "Milestone" "2024-03-15"   # Create marker

basecamp lineup create "Launch" tomorrow          # Natural date parsing

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                           # All gauges (account-wide)

basecamp gauges needles --in <project> --json         # Needles for a project

basecamp gauges needle <id> --json                    # Needle details

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>                 # Enable gauge on project

basecamp gauges disable --in <project>                # Disable gauge

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                           # All (priorities + non-priorities)

basecamp assignments list --json                      # Same as bare

basecamp assignments completed --json                 # Completed assignments

basecamp assignments due overdue --json               # Overdue

basecamp assignments due due_today --json             # Due today

basecamp assignments due due_tomorrow --json          # Due tomorrow

basecamp assignments due due_later_this_week --json   # Due later this week

Scopes: overdue, due_today, due_tomorrow, due_later_this_week, due_next_week, due_later.

Notifications

basecamp notifications --json                         # List (page 1)

basecamp notifications list --page 2 --json           # Page 2

basecamp notifications read <id> --json               # Mark as read

basecamp notifications read <id> <id> --page 2 --json # Mark from page 2

Note: read resolves notification IDs from the specified page. Use --page to match the page you listed.

Accounts

basecamp accounts list --json                         # List authorized accounts

basecamp accounts use <id>                            # Set default account

basecamp accounts show --json                         # Account details, limits, subscription

basecamp accounts update --name "New Name" --json     # Rename account

basecamp accounts logo upload <file> --json           # Upload logo (PNG/JPEG/GIF/WebP/AVIF/HEIC, 5MB max)

basecamp accounts logo remove --json                  # Remove logo

Chat

basecamp chat --in <project> --json           # List chats

basecamp chat messages --in <project> --json  # List messages

basecamp chat post "Hello!" --in <project>

basecamp chat post "@Jane.Smith, check this" --in <project>  # With @mention (auto text/html)

basecamp chat line <line_id> --in <project>   # Show line

basecamp chat delete <line_id> --in <project> --force # Delete line (permanent, not trashable)

People

basecamp people list --json                          # All people in account

basecamp people list --project <project> --json    # People on project

basecamp me --json                                 # Current user

basecamp people show <id> --json                   # Person details

basecamp people add <id> --project <project>       # Add to project

basecamp people remove <id> --project <project>    # Remove from project

Search

basecamp search "query" --json                    # Full-text search

basecamp search "query" --sort updated_at --limit 20

basecamp search metadata --json                   # Available search scopes

Generic Show

basecamp show <type> <id> --in <project> --json   # Show any recording type

# Types: todo, todolist, message, comment, card, card-table, document (or omit <type> for generic lookup)

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                    # Trust nearest .basecamp/config.json

basecamp config trust /path/to/.basecamp/config.json  # Trust specific config file

basecamp config trust --list             # Show all trusted configs

basecamp config untrust                  # Revoke trust for nearest config

basecamp config untrust /path/to/.basecamp/config.json  # Revoke trust for specific path

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                            # Check CLI health, auth, connectivity

Rate limiting (429): The CLI handles backoff automatically. If you see 429 errors, reduce request frequency.

Authentication errors:

basecamp auth status                              # Check auth

basecamp auth login                               # Re-authenticate

basecamp auth login --scope full                  # Full access (BC3 OAuth only)

basecamp auth login --device-code                 # Headless: display URL, paste callback

Network errors / localhost URLs:

# Check for dev config

cat ~/.config/basecamp/config.json

# Should only contain: {"account_id": "<id>"}

# Remove base_url/api_url if pointing to localhost

Not found errors:

basecamp auth status                              # Verify auth working

cat ~/.config/basecamp/accounts.json              # Check available accounts

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.**

# Extract fields from data array

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}]'

# Access envelope metadata

basecamp todos list --in <project> --jq '.breadcrumbs[0].cmd'

basecamp todos list --in <project> --jq '.meta.stats.requests'

# Filter and transform

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

  • API coverage: See API-COVERAGE.md in the CLI repo
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card