Contributions are welcome! Here's how to get going.
brew install mise
git clone https://github.com/RevenueCat/cli && cd cli
mise install # installs Go 1.25 per mise.toml
go mod tidy
make install-hooks # installs git hooks via lefthook (fmt + vet + test on commit)
make check # verify everything passes cleango run ./cmd/rc --help
go run ./cmd/rc commands --json | jq # full surface
go run ./cmd/rc schema customers grant # per-command schemaBuild a local binary:
go build -o /tmp/rc ./cmd/rc
/tmp/rc --versionUse env vars and an isolated config dir so dev runs don't touch your real profile:
export RC_API_KEY="sk_..."
export RC_PROJECT_ID="proj_..."
export RC_CONFIG_DIR="$(mktemp -d)"
go run ./cmd/rc projects list
go run ./cmd/rc customers show <id>When done: unset RC_API_KEY and revoke the key in the dashboard.
make test # go test -race ./...
make cover # coverage report
make check # fmt + vet + test (run before pushing)Tests use scrubbed fixtures from internal/api/testdata/v2/ — no API key needed.
When the API surface changes, capture and scrub new responses:
# 1. Capture with curl
mkdir /tmp/rc-fixtures
curl -s -H "Authorization: Bearer $RC_API_KEY" \
https://api.revenuecat.com/v2/projects/$PROJ/<path> \
> /tmp/rc-fixtures/<name>.json
# 2. Scrub (replaces real IDs, emails, IPs with deterministic fakes)
go run ./internal/api/testdata/scrub \
-in /tmp/rc-fixtures \
-out internal/api/testdata/v2
# 3. Verify no leaks
git diff internal/api/testdata/v2/
grep -r "$REAL_ID" internal/api/testdata/v2/ && echo "LEAK"| Target | What it does |
|---|---|
make build |
go build ./... |
make test |
go test -race ./... |
make cover |
Coverage report |
make fmt |
gofmt -w |
make fmt-check |
Fails if anything's unformatted (CI parity) |
make vet |
go vet |
make lint |
staticcheck |
make check |
fmt-check + vet + test |
make tidy |
go mod tidy |
Releases are automated — maintainers only need to push a tag:
# Make sure main is green, then:
git tag v0.1.0 && git push --tagsGitHub Actions picks up the tag, runs GoReleaser, publishes binaries to the GitHub release, and updates the Homebrew formula in RevenueCat/homebrew-tap automatically.
One-time setup: add a HOMEBREW_TAP_GITHUB_TOKEN repo secret with write access to RevenueCat/homebrew-tap.
Use semver: v0.x.y while pre-1.0, v1.x.y after stable release.
This repo uses Conventional Commits. The pre-commit hook enforces it automatically after make install-hooks.
<type>(<scope>): <description>
Types: feat fix docs refactor perf test chore ci build revert
Examples:
feat(auth): add OAuth browser login
fix(charts): filter future cohort periods
docs: update README quick start
Release notes are auto-generated from commit history — feat and fix commits show up in the GitHub release, others are filtered out.
- Check AGENTS.md — it documents the architecture and conventions.
- Check docs/command-surface.md before adding or renaming a command.
- Open an issue first if you're unsure whether something's in scope.
- Make sure
make checkpasses before pushing. - Use conventional commit messages — the hook will tell you if the format is wrong.
- Open a PR with a clear description of what changed and why.
cmd/rc/ entry point
internal/
api/ typed REST client — one file per resource, no CLI concepts
cli/ user-intent commands — composes api/ calls into UX
config/ profile + env layering (~/.config/revenuecat/*.json)
output/ TTY pretty-print vs --json renderer
tui/ interactive prompts (huh) and chart viewer (BubbleTea)
The key rule: internal/api/ knows nothing about the CLI. internal/cli/ owns all UX. See AGENTS.md for the full conventions.