Skip to content

Rich shell autocompletion for talm CLI #170

@lexfrei

Description

@lexfrei

Motivation

talm CLI today ships with cobra's default completion (subcommand names, flag names) — but no value-aware completion. Every operator workflow that survives a sleepy 3am rotation involves:

  • Remembering the exact filename of the node patch (nodes/cp-01.yaml vs nodes/cp01.yaml)
  • Hand-copying node IPs / endpoints from talosconfig because the shell can't suggest them
  • Re-typing --mode=staged / --mode=try / etc. without tab-completion
  • Recalling preset names for talm init -p ...

cobra exposes everything needed to make this work out of the box. talm currently registers exactly one completion hook (pkg/commands/talosctl_wrapper.go:44 borrowing the parent's ValidArgsFunction). The cost of filling the rest is small; the daily friction relief is large.

Scope

Positional args

  • talm apply <FILE...> — complete to project files that carry the talm modeline (typically nodes/*.yaml). Scan from CWD upward to the project root (same root-detection logic that init already uses).
  • talm template <FILE...> — same set.
  • talm upgrade <FILE...> — same set.

Flag values

File-shaped flags (cobra has filename completion as a built-in directive — use it where applicable):

  • --file / -f on apply, template, upgrade — restrict to *.yaml / *.yml.
  • --values on template — restrict to *.yaml / *.yml.
  • --template / -t on template — complete to chart template paths under charts/<chart>/templates/.
  • --with-secrets on apply, template, init*.yaml filter.
  • --talosconfig (global) — file completion.

talosconfig-derived flags:

  • --nodes (global) — parse the in-scope talosconfig (--talosconfig value, $TALOSCONFIG, default ~/.talos/config, project-local talosconfig), extract every node from every context, dedup, return.
  • --endpoints (global) — same source, endpoint fields.

Lazy: only resolve talosconfig when the flag is actually being completed.

Enum flags:

  • --mode on apply{auto, no-reboot, reboot, staged, try} from helpers.Mode's known set.
  • --preset / -p on init — enum of valid preset names (currently embedded in talm's preset registry).
  • --talos-version on apply / template / init / upgrade — known machinery contract values (v1.10, v1.11, v1.12, ...) parsed from siderolabs/talos/pkg/machinery/config.

Out of scope (initial phase)

  • --set / --set-string / --set-json / --set-literal / --set-file value completion (would need to introspect values.yaml schema — large enough for its own follow-up).
  • Dynamic image-tag completion for --image (would require a network call).

Design

cobra API used per category:

  • File-shaped flags: cmd.RegisterFlagCompletionFunc(name, func) with the []string{"yaml", "yml"} filter via cobra.ShellCompDirectiveFilterFileExt.
  • Positional args with modeline filter: cmd.ValidArgsFunction = func(cmd, args, toComplete) ([]string, cobra.ShellCompDirective) — walk CWD-to-project-root, list *.yaml, filter to files whose head matches the talm modeline regex (already implemented in processModelineAndUpdateGlobals).
  • talosconfig-derived: cmd.RegisterFlagCompletionFunc("nodes", ...) and parse with the existing talosconfig loader.
  • Static enums: cobra.FixedCompletions([]string{"auto", "no-reboot", ...}, cobra.ShellCompDirectiveNoFileComp).

Where it lives

One file per command: pkg/commands/apply_completion.go, template_completion.go, etc. Each init() (or an explicit registerCompletions(cmd) called from the command's init()) attaches its completions. Keeps completion co-located with the command, avoids a god-file.

The shared talosconfig parser (nodes + endpoints extraction) goes in pkg/commands/completion_helpers.go since multiple commands need it.

Tests

cobra completion functions are pure: (cmd, args, toComplete) -> ([]string, ShellCompDirective). Unit-test each:

  • pkg/commands/apply_completion_test.go — feed fixtures for --mode, --nodes (with a fake talosconfig), positional file argument (with a fake CWD layout), assert returned values + directive.
  • Per-shell smoke test (optional): pipe talm completion bash into bash -n to prove the generated script parses; skip in CI if it adds too much.

How users enable it

Nothing new on the talm side — completion is on once talm completion <shell> is sourced:

# bash
talm completion bash | source
# zsh
talm completion zsh > "${fpath[1]}/_talm"
# fish
talm completion fish | source
# powershell
talm completion powershell | Out-String | Invoke-Expression

cobra already generates talm completion <shell> for free — confirm it's present in pkg/commands/root.go, add if missing.

Acceptance

  • All four shells (bash, zsh, fish, powershell) emit completion scripts via talm completion <shell> and the scripts parse.
  • Unit tests cover each completion func with realistic input.
  • README gets a small "Shell completion" section pointing at talm completion --help.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/commandsIssues or PRs related to pkg/commands (CLI subcommands, flag parsing, root detection)kind/featureCategorizes issue or PR as related to a new feature

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions