Skip to content

Add shared CLI toolkit: rubric, packages, seed, and actions#1

Merged
jeremy merged 11 commits intomainfrom
common
Mar 4, 2026
Merged

Add shared CLI toolkit: rubric, packages, seed, and actions#1
jeremy merged 11 commits intomainfrom
common

Conversation

@jeremy
Copy link
Copy Markdown
Member

@jeremy jeremy commented Mar 4, 2026

Summary

Shared Go module and specification for all 37signals CLIs. Extracted from basecamp-cli and generalized for fizzy-cli, hey-cli, etc.

Packages

  • output/ — Envelope types, exit codes, typed errors, format dispatch, TTY auto-detection. A CLI that imports this and uses Writer.OK() / Writer.Err() automatically complies with Tier 1A and 1B of the rubric.
  • credstore/ — Keyring + file fallback credential storage, parameterized per CLI.
  • pkce/ — PKCE verifier, challenge, and state generation (RFC 7636).
  • oauthcallback/ — Local HTTP server for OAuth redirect flows.
  • surface/ — CLI surface snapshots and compatibility diffs for Cobra command trees.
  • profile/ — Named environment profiles with resolution precedence (flag > env > config > auto-select > interactive picker).

Specification

  • RUBRIC.md — 80 criteria across 4 tiers (Agent Contract, Reliability, Agent Integration, Distribution & Ecosystem). Two profiles: API CLI (full) and TUI tool (subset). Scoring template included.
  • MAKEFILE-CONVENTION.md — Standard target contract for all 37signals CLI repos.

Infrastructure

  • actions/ — Reusable GitHub Actions: rubric-check, surface-compat, sync-skills.
  • seed/ — Complete starter kit for bootstrapping a new CLI: output/auth wrappers, .claude-plugin with hooks and agents, skill embedding, doctor/setup/skill command skeletons, .goreleaser.yaml (cosign, SBOM, notarization), API-COVERAGE.md template.
  • skills/ — rubric-audit agent skill.
  • prompts/ — Agent prompts for closing rubric gaps and seeding new CLIs.

Test plan

  • make passes (vet + test across all packages)
  • Verify basecamp-cli can import packages (Phase 3 migration) — all 5 packages (output, credstore, pkce, surface, profile) verified via test module with replace directive
  • Score fizzy-cli and hey-cli against RUBRIC.md — fizzy: 43/81, hey: 10/81

Module github.com/basecamp/cli with Go 1.24. Makefile with check
(default), fmt-check, vet, and test targets. MAKEFILE-CONVENTION.md
documents the standard target contract for all 37signals CLI repos.
Copilot AI review requested due to automatic review settings March 4, 2026 21:55
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b2da56831a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread actions/sync-skills/action.yml Outdated
Comment thread oauthcallback/server.go Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces a new shared Go module (github.com/basecamp/cli) intended to standardize behavior across 37signals CLIs (output contracts, auth helpers, PKCE/OAuth flow support, surface snapshots, profiles), plus a rubric/specification, reusable GitHub Actions, and a “seed” starter kit for bootstrapping new CLIs.

Changes:

  • Added shared Go packages: output, credstore, pkce, oauthcallback, surface, profile (with unit tests).
  • Added portfolio-level specs/docs: RUBRIC.md and MAKEFILE-CONVENTION.md.
  • Added reusable GitHub Actions and a seed kit (templates, scripts, Claude plugin scaffolding, prompts, skill templates).

Reviewed changes

Copilot reviewed 47 out of 48 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
surface/surface_test.go Tests for Cobra surface snapshotting and diffing.
surface/snapshot.go Implements command/flag/subcommand snapshot traversal.
surface/diff.go Implements snapshot diffing (added/removed entries).
skills/rubric-audit/SKILL.md Agent skill doc for auditing a CLI against the rubric.
seed/skills/embed.go.tmpl Template for embedding skill files via go:embed.
seed/skills/app/SKILL.md.tmpl Template SKILL.md for a seeded CLI.
seed/scripts/sync-skills.sh CI script to sync skills into a distribution repo.
seed/internal/output/output.go Seed wrapper re-exporting shared output types/helpers.
seed/internal/commands/skill.go.tmpl Seed skill command to print embedded SKILL.md.
seed/internal/commands/setup.go.tmpl Seed skeleton doc for interactive setup wizard.
seed/internal/commands/doctor.go.tmpl Seed skeleton doc for a doctor health-check command.
seed/internal/auth/auth.go Seed auth helpers wiring credstore + pkce.
seed/Makefile Seed CLI Makefile implementing the documented target contract.
seed/CONTRIBUTING.md.tmpl Seed contributing guide template.
seed/API-COVERAGE.md.tmpl Seed template for tracking endpoint-to-command coverage.
seed/AGENTS.md.tmpl Seed development context and conventions template.
seed/.goreleaser.yaml Seed GoReleaser config (signing/SBOM/notarization).
seed/.golangci.yml Seed golangci-lint configuration.
seed/.claude-plugin/plugin.json Seed Claude plugin manifest template.
seed/.claude-plugin/hooks/session-start.sh Seed SessionStart hook to emit CLI context.
seed/.claude-plugin/agents/navigator.md Seed “navigator” agent template.
seed/.claude-plugin/agents/context-linker.md Seed “context linker” agent template.
prompts/seed-cli.md Prompt/spec for generating a new CLI from the seed.
prompts/close-gap.md Prompt/spec for closing a specific rubric gap.
profile/resolve.go Profile resolution logic (flag/env/config/auto/picker).
profile/profile_test.go Tests for profile store + resolution.
profile/profile.go Profile store implementation and validation helpers.
pkce/pkce_test.go Tests for PKCE verifier/challenge/state generation.
pkce/pkce.go PKCE helpers for verifier/challenge/state.
output/output_test.go Extensive tests for output envelopes, codes, formats, helpers.
output/normalize.go Normalizes data types (incl. UseNumber) for JSON output.
output/errors.go Typed error model and constructors, plus AsError.
output/envelope.go Writer implementation, formats, envelopes, and helpers.
output/codes.go Exit-code and code-string constants + mapping.
oauthcallback/server_test.go Tests for local OAuth callback server behavior.
oauthcallback/server.go Local HTTP callback server implementation.
credstore/store_test.go Tests for file-based credential storage fallback.
credstore/store.go Credential store abstraction (keyring + file fallback).
credstore/migrate.go Migration helper from file store to keyring.
credstore/file.go File-backed credential storage implementation.
actions/sync-skills/action.yml Composite action to sync skills to distribution repo.
actions/surface-compat/action.yml Composite action to detect breaking CLI surface removals.
actions/rubric-check/action.yml Composite action to score a CLI against key rubric checks.
RUBRIC.md Full rubric spec (tiers/criteria/scoring template).
Makefile Root module Makefile (library-style: fmt/vet/test/lint/etc).
MAKEFILE-CONVENTION.md Standard target contract for CLI/library Makefiles.
go.mod Defines module path and dependencies.
go.sum Dependency checksums.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread oauthcallback/server.go Outdated
Comment thread actions/surface-compat/action.yml
Comment thread actions/rubric-check/action.yml Outdated
Comment thread output/errors.go
Comment thread output/envelope.go
Comment thread oauthcallback/server.go Outdated
Comment thread credstore/store.go Outdated
Comment thread oauthcallback/server.go
Comment thread oauthcallback/server_test.go
Comment thread credstore/store.go Outdated
Copilot AI review requested due to automatic review settings March 4, 2026 22:26
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 48 out of 49 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread actions/sync-skills/action.yml
Comment thread seed/scripts/publish-aur.sh
Comment thread output/envelope.go Outdated
Comment thread credstore/store.go Outdated
Comment thread actions/surface-compat/action.yml Outdated
Comment thread actions/surface-compat/action.yml
jeremy added 10 commits March 4, 2026 14:46
The agent contract in type form. A CLI that imports output and uses
Writer.OK() / Writer.Err() automatically complies with Tier 1A and 1B
of the rubric.

- Response / ErrorResponse envelope types
- Format enum with TTY auto-detection (FormatAuto)
- 8 typed exit codes (0=OK through 8=Ambiguous)
- CLIError with Code, Message, Hint, Retryable, HTTPStatus
- Typed constructors: ErrUsage, ErrNotFound, ErrAuth, etc.
- NormalizeData with json.Number preservation for large IDs
- TruncationNotice helpers for paginated responses
- Breadcrumb type for agent chaining
Parameterized by ServiceName, DisableEnvVar, and FallbackDir so each
CLI configures its own namespace. Probes system keyring at init, falls
back to atomic file writes with 0600 permissions. Includes
MigrateToKeyring() for upgrading file-based credentials.
Three stdlib-only functions implementing RFC 7636 for OAuth flows.
GenerateVerifier (32 bytes), GenerateChallenge (S256), GenerateState
(16 bytes).
WaitForCallback starts a local HTTP server, validates the OAuth state
parameter, and returns the authorization code. 5-minute timeout,
sync.Once shutdown, HTML response to the browser.
Walks a Cobra command tree to produce deterministic CMD/FLAG/SUB
entries. Diff() compares two snapshots and reports additions and
removals. HasBreakingChanges() flags flag/subcommand removals for
CI enforcement.
Profile bundles a base URL with optional app-specific Extra fields.
Store manages profiles in a JSON config file with atomic writes.
Resolve implements strict precedence: --profile flag > APP_PROFILE
env > default_profile config > auto-select single > interactive
picker. CredentialKey returns "profile:<name>" for named profiles.
80 criteria across 4 tiers evaluating agent operability, reliability,
integration, and distribution. Two profiles: API CLI (full rubric)
and TUI tool (subset). 7 design principles. Scoring template for
evaluating any CLI against the standard.

Tier 1: Agent Contract (26) — structured output, exit codes,
  programmatic discovery, authentication
Tier 2: Reliability (16) — surface stability, resilience, configuration
Tier 3: Agent Integration (11) — skill/plugin, pagination, observability
Tier 4: Distribution & Ecosystem (27) — distribution, testing,
  completion, developer experience
actions/rubric-check — score a CLI against the rubric
actions/surface-compat — fail on flag/subcommand removal
actions/sync-skills — publish embedded skills to basecamp/skills
Complete starter kit for a new 37signals CLI:

- internal/output/ and internal/auth/ wrapping shared packages
- internal/commands/ with doctor, setup, and skill command skeletons
- .claude-plugin/ with SessionStart hook, navigator and context-linker
  agent templates
- skills/ with embed.go and SKILL.md templates
- scripts/sync-skills.sh for publishing skills on release
- .goreleaser.yaml with cosign signing, SBOM, and notarization
- .golangci.yml, Makefile, AGENTS.md, CONTRIBUTING.md templates
- API-COVERAGE.md tracking matrix template
skills/rubric-audit/SKILL.md — agent skill for scoring any CLI
prompts/close-gap.md — agent prompt for closing a specific rubric gap
prompts/seed-cli.md — agent prompt for bootstrapping a new CLI
@jeremy
Copy link
Copy Markdown
Member Author

jeremy commented Mar 4, 2026

/cc @robzolkos @monorkin @kevinmcconnell

Extracting and harmonizing common app CLI bits!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants