Before making code or documentation changes in this repo:
- Switch back to
master. - Pull the latest changes with
git pull --ff-only. - Create a new branch with a short, descriptive name related to the feature being added or the bug being fixed.
- Make the requested changes on that branch.
Do not start work from an old feature branch unless the user explicitly asks to continue that branch.
When the user asks to add a "ticket", "issue", or "bug" to this repo, all of the steps below are required — creating the GitHub issue alone is not enough.
1. Create the issue with the repo label and an area label:
gh issue create --repo andreagrandi/mb-cli \
--title "<concise title>" \
--body "<description>" \
--label "mb-cli" \
--label "<area>"- Always apply the
mb-clilabel — every work item in this repo carries it. - Add the matching area label when one exists:
feature,ux,agent,docs,security,testing,release. TheReliabilityandPackagingareas have no label; for those, set only the project Area field (step 3). - Add a type label when it fits:
bug(bug report),enhancement(feature request), ordocumentation(docs-only work).
2. Add the issue to the "CLI Tools" project and capture the item ID (https://github.com/users/andreagrandi/projects/1):
ITEM_ID=$(gh project item-add 1 --owner andreagrandi \
--url <issue-url> --format json --jq .id)3. Set Priority, Area, and Status on the project item. The project and field IDs are identical for every repo on this board:
- Project ID:
PVT_kwHOAAm1584BYDlZ - Priority — field
PVTSSF_lAHOAAm1584BYDlZzhTMDck: Highed3787e3, Medium3e3ea407, Low994234f4 - Area — field
PVTSSF_lAHOAAm1584BYDlZzhTMDco: Reliability6595432d, Packaging6895c50a, UX2bc024bb, Testing0d5bc016, Feature6390f97d, Agent3a2d6f7e, Docsf5c50514, Security062d12a3, Releaseb344aeab - Status — field
PVTSSF_lAHOAAm1584BYDlZzhTMDNQ: Todof75ad846, In Progress47fc9ee4, Done98236657
# Priority — always set it
gh project item-edit --id "$ITEM_ID" --project-id PVT_kwHOAAm1584BYDlZ \
--field-id PVTSSF_lAHOAAm1584BYDlZzhTMDck \
--single-select-option-id <priority-option-id>
# Area — match the area label from step 1
gh project item-edit --id "$ITEM_ID" --project-id PVT_kwHOAAm1584BYDlZ \
--field-id PVTSSF_lAHOAAm1584BYDlZzhTMDco \
--single-select-option-id <area-option-id>
# Status — new tickets start as Todo
gh project item-edit --id "$ITEM_ID" --project-id PVT_kwHOAAm1584BYDlZ \
--field-id PVTSSF_lAHOAAm1584BYDlZzhTMDNQ \
--single-select-option-id f75ad846If the user does not state a priority or area, ask before creating the issue. Follow the conventions of existing project issues — do not invent new labels or fields.
mb-cli follows the standard Go project layout:
mb-cli/
├── cmd/mb-cli/main.go # Application entry point
├── internal/
│ ├── cli/ # CLI command implementations (Cobra)
│ ├── client/ # Metabase API client
│ ├── config/ # Configuration management
│ ├── formatter/ # Output formatting (JSON, table)
│ └── version/ # Version information
├── tests/ # Test files
└── Makefile # Build targets
make build- Build binary to bin/mb-climake test- Run all testsmake test-verbose- Run tests with verbose outputmake fmt- Format code with gofmtmake vet- Static analysis with go vetmake lint- Run golangci-lintmake clean- Remove build artifactsmake deps- Download and tidy dependenciesmake build-all- Cross-platform builds
Environment variables (both required):
MB_HOST- Metabase instance URL (e.g.https://your-metabase-instance.com)MB_API_KEY- Metabase API key
- Use Go standard formatting (gofmt)
- Package names: lowercase, single word
- Types: PascalCase
- Functions/methods: PascalCase (exported), camelCase (unexported)
- Variables: camelCase
- Constants: PascalCase or ALL_CAPS
- Import ordering: standard library, third-party, local packages
- Use
fmt.Errorffor error wrapping - Always defer
resp.Body.Close()after error check for HTTP responses - Use table-driven tests with
tests := []struct{}pattern - Test files go in the
tests/directory - Use
httptest.NewServerfor HTTP client testing
- After implementing API methods or CLI commands, always smoke test every method against the real Metabase API (
make build && ./bin/mb-cli <command>) - Do not consider a step complete until all endpoints have been verified end-to-end, not just unit tested
- When you generate or update the CHANGELOG.md, be concise
- New additions go in [Unreleased] section
- Don't bump version unless requested
Every PR that introduces a user-visible change must add an entry under the
## [Unreleased] section of CHANGELOG.md before it is opened for review.
This is the same workflow LogBasset follows and the entry is what becomes the
public release note.
Add an entry whenever a change affects what users observe or depend on:
- New, removed, or renamed commands, subcommands, flags, or environment variables
- Changes to command output (format, schema, default format, sort order, truncation)
- Changes to default behavior (e.g. PII redaction defaults, exit codes, validation, error messages users may script against)
- Bug fixes that change observable behavior
- Packaging and install changes (Homebrew formula,
go installpath, release artifacts, supported Go versions for distributed binaries) - Security or privacy behavior (redaction, logging of sensitive values, authentication handling)
- Documentation changes that describe a new capability shipped in the same PR (the entry covers the capability, not the docs)
Skip the changelog only for changes invisible to users:
- Internal refactors with no behavior change
- Test-only changes
- Pure CI / tooling tweaks that do not affect built artifacts
- Repo housekeeping (README typos, comments, formatting)
- Dependency bumps that do not change behavior (Dependabot PRs are exempt by default; if a bump changes behavior, add an entry manually)
If you are unsure, add an entry — over-documenting is cheaper than a missing release note.
- Add a single bullet under
## [Unreleased]at the top ofCHANGELOG.md - One line, present tense, user-facing wording ("Add
query filtercommand", "Redact PII in native SQL results", "Fix Homebrew install on macOS") - Reference the issue or PR number in parentheses when it adds context
(e.g.
(#20)); do not include personal information - Do not bump the version or move entries out of
[Unreleased]— that happens during the release process
The PR template has a "Changelog updated" checkbox. If a PR genuinely needs no entry, tick the "No changelog entry needed" box and briefly say why.
When asked to create a new release, follow this exact sequence:
- Ensure tests pass without errors:
make test- Set the release version in
internal/version/version.go:
- Use the provided version if one is given.
- Otherwise bump the patch version (example:
0.1.0->0.1.1). - Update
var Version = "..."ininternal/version/version.go.
- Update
CHANGELOG.md:
- Add a short bullet-point summary of changes since the last release.
- Follow the existing changelog format.
- Commit the release-prep changes.
- Push the release-prep commit.
- Create the tag using the version from
internal/version/version.go:
git tag v<version>- Push the tag:
git push origin v<version>Notes:
- The tag push triggers
.github/workflows/release.yml. - Do not manually create a GitHub release before the workflow runs.