Summary
Ship bash, zsh, and fish completions for things so that things <TAB> and things list <TAB> work out of the box for Homebrew users — and stay in sync with the CLI surface automatically.
Motivation
things has 20+ subcommands and many of them take typed flags (--when, --deadline, --tag, --project, list views like today/upcoming/etc.). Without completions, users (and the bundled agent skill workflows) discover the surface only by reading --help. Completions make the CLI dramatically easier to drive interactively.
The Homebrew cask is the natural delivery channel: GoReleaser already ships the binary, and homebrew_casks has a generate_completions_from_executable: block that calls the binary at install time to emit completion scripts and drop them in the right Homebrew prefix. Zero post-install steps for the user.
Approach
Split into two PRs so the CLI work can land first and the cask wiring is a small follow-up.
PR 1 — feat(cli): generate shell completions (CLI)
Kong (alecthomas/kong) doesn't have built-in shell completion generation like Cobra does. The standard add-on is willabides/kongplete, which uses posener/complete under the hood and works with all three target shells.
Steps:
- Add
github.com/willabides/kongplete to go.mod.
- Add a new
completions <shell> subcommand in cmd/things/ that invokes kongplete.Complete for the requested shell (bash/zsh/fish) and writes the script to stdout.
- Wire the global
kong.Parser so kongplete.Complete is registered (a pre-run hook + the --install-completions flag, or just the explicit subcommand path — whichever fits the existing Kong wiring best).
- Document the new subcommand in
internal/skill/SKILL.md (CLAUDE.md reminds us this drifts silently otherwise).
- Test: a small unit test that asserts
things completions bash exits 0 and emits non-empty output containing the binary name.
Acceptance for PR 1:
PR 2 — feat(release): ship shell completions in the cask (release plumbing)
Once the binary can emit completions, the cask block is small:
homebrew_casks:
- # ...existing config...
generate_completions_from_executable:
executable: bin/things
args: [completions]
base_name: things
shell_parameter_format: arg # `things completions <shell>` — `<shell>` is a positional arg
shells: [bash, zsh, fish]
(shell_parameter_format controls how the shell name is passed to the binary — arg for a positional, or a custom prefix like --shell= if we go with a flag instead. Pick whichever shape PR 1 lands on.)
Acceptance for PR 2:
Non-goals
- PowerShell completions — not a target shell on macOS for this tool
- Argument-value completion that requires reading the Things3 DB (e.g. project/area/tag names) — flag-name completion only for v1; data-driven completion is a much bigger lift and a separate issue if we ever want it
- Completions outside the cask install path (the
install.sh, go install, and source-build paths can rely on things completions <shell> | source if a user wants them — documented in the README)
References
Summary
Ship
bash,zsh, andfishcompletions forthingsso thatthings <TAB>andthings list <TAB>work out of the box for Homebrew users — and stay in sync with the CLI surface automatically.Motivation
thingshas 20+ subcommands and many of them take typed flags (--when,--deadline,--tag,--project, list views liketoday/upcoming/etc.). Without completions, users (and the bundled agent skill workflows) discover the surface only by reading--help. Completions make the CLI dramatically easier to drive interactively.The Homebrew cask is the natural delivery channel: GoReleaser already ships the binary, and
homebrew_caskshas agenerate_completions_from_executable:block that calls the binary at install time to emit completion scripts and drop them in the right Homebrew prefix. Zero post-install steps for the user.Approach
Split into two PRs so the CLI work can land first and the cask wiring is a small follow-up.
PR 1 —
feat(cli): generate shell completions(CLI)Kong (alecthomas/kong) doesn't have built-in shell completion generation like Cobra does. The standard add-on is
willabides/kongplete, which usesposener/completeunder the hood and works with all three target shells.Steps:
github.com/willabides/kongpletetogo.mod.completions <shell>subcommand incmd/things/that invokeskongplete.Completefor the requested shell (bash/zsh/fish) and writes the script to stdout.kong.Parsersokongplete.Completeis registered (a pre-run hook + the--install-completionsflag, or just the explicit subcommand path — whichever fits the existing Kong wiring best).internal/skill/SKILL.md(CLAUDE.md reminds us this drifts silently otherwise).things completions bashexits 0 and emits non-empty output containing the binary name.Acceptance for PR 1:
things completions bash,things completions zsh,things completions fisheach print a valid completion script for the named shellinternal/skill/SKILL.mdlists the new subcommandmake testandmake lintpassPR 2 —
feat(release): ship shell completions in the cask(release plumbing)Once the binary can emit completions, the cask block is small:
(
shell_parameter_formatcontrols how the shell name is passed to the binary —argfor a positional, or a custom prefix like--shell=if we go with a flag instead. Pick whichever shape PR 1 lands on.)Acceptance for PR 2:
goreleaser checkpassesgoreleaser release --snapshot --clean --skip=publishgenerates aCasks/things.rbcontaining agenerate_completions_from_executableblockbrew install ryanlewis/tap/things(orbrew reinstall) installsthingsand writesbash/zsh/fishcompletion files into the Homebrew prefixthings <TAB>, see subcommandsNon-goals
install.sh,go install, and source-build paths can rely onthings completions <shell> | sourceif a user wants them — documented in the README)References
willabides/kongplete— Kong + posener/complete bridgegenerate_completions_from_executabledocsryanlewis/homebrew-tap