Skip to content

feat: shell completions (bash/zsh/fish) shipped via the Homebrew cask #88

@ryanlewis

Description

@ryanlewis

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:

  1. Add github.com/willabides/kongplete to go.mod.
  2. 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.
  3. 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).
  4. Document the new subcommand in internal/skill/SKILL.md (CLAUDE.md reminds us this drifts silently otherwise).
  5. 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:

  • things completions bash, things completions zsh, things completions fish each print a valid completion script for the named shell
  • Eval'ing the script in an interactive shell produces TAB-completion for top-level subcommands and known flags
  • internal/skill/SKILL.md lists the new subcommand
  • make test and make lint pass

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:

  • goreleaser check passes
  • goreleaser release --snapshot --clean --skip=publish generates a Casks/things.rb containing a generate_completions_from_executable block
  • After the next tag: brew install ryanlewis/tap/things (or brew reinstall) installs things and writes bash/zsh/fish completion files into the Homebrew prefix
  • Open a fresh shell, type things <TAB>, see subcommands

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions