Skip to content

Latest commit

Β 

History

History
158 lines (125 loc) Β· 6.76 KB

File metadata and controls

158 lines (125 loc) Β· 6.76 KB

Basecamp CLI Development Context

Getting Started

See CONTRIBUTING.md for build setup, testing, and PR workflow.

The standard development loop in this repo: make changes, run bin/ci, fix what it catches, repeat until green, then push. Treat bin/ci as your inner-loop companion, not a final hurdle.

Repository Structure

basecamp-cli/
β”œβ”€β”€ cmd/basecamp/     # Main entrypoint
β”œβ”€β”€ internal/
β”‚   β”œβ”€β”€ appctx/       # Application context
β”‚   β”œβ”€β”€ auth/         # OAuth authentication
β”‚   β”œβ”€β”€ cli/          # CLI framework
β”‚   β”œβ”€β”€ commands/     # Command implementations
β”‚   β”œβ”€β”€ completion/   # Shell completion
β”‚   β”œβ”€β”€ config/       # Configuration management
β”‚   β”œβ”€β”€ dateparse/    # Date parsing
β”‚   β”œβ”€β”€ hostutil/     # Host utilities
β”‚   β”œβ”€β”€ models/       # Data models
β”‚   β”œβ”€β”€ names/        # Name resolution
β”‚   β”œβ”€β”€ observability/ # Tracing and metrics
β”‚   β”œβ”€β”€ output/       # Output formatting
β”‚   β”œβ”€β”€ presenter/    # Output presentation
β”‚   β”œβ”€β”€ resilience/   # Retry and backoff
β”‚   β”œβ”€β”€ sdk/          # Basecamp SDK wrapper
β”‚   β”œβ”€β”€ tui/          # Terminal UI
β”‚   └── version/      # Version info
β”œβ”€β”€ e2e/              # BATS integration tests
β”œβ”€β”€ skills/           # Agent skills
β”œβ”€β”€ hooks/            # Agent lifecycle hooks (both agents)
β”œβ”€β”€ .claude-plugin/   # Claude Code integration
└── .codex-plugin/    # Codex plugin manifest

Basecamp API Reference

API documentation: https://github.com/basecamp/bc3-api

Key endpoints used by the CLI:

  • /projects.json - List projects
  • /buckets/{id}/todolists/{id}/todos.json - Todos in a list
  • /buckets/{id}/todos/{id}/completion.json - Complete todo
  • /people.json - List people
  • /my/profile.json - Current user

Search: Use basecamp search "query" for full-text search across projects. The Recordings API (basecamp recordings) is for browsing by type/status without a search term.

Testing

bin/ci is the local CI gate. It runs every check that remote CI runs: formatting, vetting, linting, unit tests, e2e tests, naming conventions, CLI surface snapshots, skill drift detection, SDK provenance, and go mod tidy. Run it early and often β€” after finishing a feature, after fixing a bug, before pushing. If you're about to git push and haven't run bin/ci in this session, stop and run it first.

Skill drift: make check-skill-drift runs over both skills/basecamp/SKILL.md and skills/basecamp-doctor/SKILL.md, checking that the commands and flags each one references still exist in the .surface snapshot. It catches stale references, not missing coverage, so adding a command breaks neither skill.

Removal is only partly caught. resolve_cmd walks up to the nearest existing ancestor, so dropping a nested subcommand leaves the reference resolving against its parent and the check still passes β€” basecamp setup <removed> resolves as basecamp setup. Removing a top-level command is caught; removing a subcommand is not. Don't lean on CI for this. Update the skill the change actually affects; basecamp-doctor deliberately covers only doctor, setup and auth remediation.

bin/ci                # The single command β€” run this

When iterating on a specific area, use targeted make targets for faster feedback, then finish with bin/ci before pushing:

make build            # Build binary to ./bin/basecamp
make test             # Go unit tests
make test-e2e         # BATS end-to-end tests
make lint             # Linter
make check            # All checks (what bin/ci runs)

Dead code: make deadcode reports unreachable functions whole-program, rooted at the shipped binary and again with -tags dev. It is a report, not a gate, and is deliberately outside make check. The linter's unused cannot do this job β€” it runs per-package and counts every exported identifier in a non-main package as used, which is how 600 lines of exported, zero-caller internal/tui API survived it. Root it at the binary, not ./...: only main packages are roots, so ./... reports everything no main reaches β€” mostly the dev-tagged workspace tree β€” as unreachable.

It also analyzes one GOOS/GOARCH at a time, while we release five. A host run says nothing about the others: code behind another platform's build tag is never loaded, and a function whose only caller sits behind one looks unreachable. Before deleting anything platform-adjacent, check the other targets β€” install the tool for the host and set GOOS for the analysis (GOOS=windows deadcode ./cmd/basecamp), since GOOS=windows go run cross-compiles the tool itself and fails.

Read the output before acting on it: a zero-caller exported symbol is a candidate, not a verdict, and the dev-tagged tree is legitimately partial.

Requirements: Go 1.26+, bats-core for e2e tests.

OAuth Development

For local development against BC3:

BASECAMP_BASE_URL=http://3.basecamp.localhost:3001 basecamp auth login

OAuth endpoints are discovered via .well-known/oauth-authorization-server.

Benchmarks

make bench            # Run all benchmarks
make bench-cpu        # Run with CPU profiling
make bench-mem        # Run with memory profiling
make bench-save       # Save baseline for comparison
make bench-compare    # Compare against baseline

SDK Sync

The CLI depends on the Basecamp SDK (github.com/basecamp/basecamp-sdk/go). When the SDK adds new API operations, the CLI must add corresponding commands.

Tracking: internal/version/sdk-provenance.json records the SDK version + API revision the CLI is built against. API-COVERAGE.md tracks endpoint coverage.

Workflow (see also .claude/skills/sdk-bump.md):

  1. make bump-sdk β€” updates go.mod + provenance (never edit go.mod directly)
  2. go build ./... β€” detect breaking changes
  3. Fix any compilation errors in internal/commands/ and internal/sdk/
  4. Check for new SDK services/methods β†’ create corresponding CLI commands
  5. make test β€” verify all pass including catalog parity
  6. Update API-COVERAGE.md with new endpoint coverage

Completeness bar: every new SDK service method needs:

  • Command file in internal/commands/
  • Catalog entry in commands.go
  • Registration in internal/cli/root.go + commands_test.go
  • API-COVERAGE.md row

Andon cord: if the SDK lacks a Go service wrapper for a generated endpoint, stop and open an issue on basecamp-sdk β€” never call the raw generated client from CLI code.

Code style

See STYLE.md for the Go conventions used here. Read it when writing or reviewing Go; it is not imported, so it stays out of context for sessions that never touch Go.