Skip to content

Improve CLI UX: enums, validation, help panels, and completions#33

Merged
alexkroman merged 11 commits into
mainfrom
claude/cli-usability-Y4JiI
Jun 7, 2026
Merged

Improve CLI UX: enums, validation, help panels, and completions#33
alexkroman merged 11 commits into
mainfrom
claude/cli-usability-Y4JiI

Conversation

@alexkroman

Copy link
Copy Markdown
Collaborator

Summary

This PR enhances the CLI's user experience through better type safety, input validation, organized help text, and shell completions. It introduces a new choices module for closed-value enums, adds file-path validation via Typer's exists=True, organizes options into help panels, and implements shell-completion callbacks for dynamic values.

Key Changes

  • New choices module (aai_cli/choices.py): Introduces StrEnum types for closed value sets (TranscriptOutput, TextOrJson, Scope). These enums automatically render as choices in --help, validate input with clean error messages, and enable shell-tab completion — while remaining backward-compatible with existing string comparisons.

  • Type-safe enums for command options: Replaces string type hints with proper enum types:

    • transcribe: speech_modelaai.SpeechModel, summary_modelaai.SummarizationModel, summary_typeaai.SummarizationType, redact_pii_subaai.PIISubstitutionPolicy
    • stream: speech_modelSpeechModel, encodingEncoding, voice_focusNoiseSuppressionModel
    • setup: scopechoices.Scope
    • agent, llm, transcripts: outputchoices.TextOrJson
  • File-path validation: Adds exists=True to file-path options (--config-file, --custom-spelling-file, --system-prompt-file) so Typer validates paths before the command runs, providing early, clear error messages. New test file tests/test_path_validation.py pins this behavior.

  • Help panel organization (aai_cli/help_panels.py): Defines semantic panel names (OPT_MODEL, OPT_FORMATTING, OPT_SPEAKERS, OPT_GUARDRAILS, OPT_ANALYSIS, OPT_CUSTOMIZATION, OPT_CAPTURE, OPT_TURNS, OPT_FEATURES) and assigns options to panels via rich_help_panel=.... This groups related flags under headings in --help, making 40+ options navigable instead of a flat wall.

  • Shell completions:

    • Adds complete_model() in aai_cli/llm.py and complete_voice() in aai_cli/agent/voices.py to suggest known values on Tab.
    • Enables add_completion=True in aai_cli/main.py so --install-completion is available.
    • New test file tests/test_completion.py verifies completion functions.
  • Snapshot updates: Regenerated tests/__snapshots__/test_cli_output_snapshots.ambr to reflect improved help formatting with panels and enum choices (e.g., [text|json] instead of TEXT).

  • Minor improvements:

    • --version flag now works as an eager callback (prints version and exits before subcommand is required).
    • config_builder.py type hints updated to accept Path | str for config files.
    • .mcp.json updated with assemblyai-docs MCP entry.
    • Removed redundant validation logic from output.py (now handled by enums).

Implementation Details

  • Enums inherit from enum.StrEnum so their members are their string values — existing code like field == "text" continues to work without changes.
  • Typer automatically renders enum members as [choice1|choice2|...] in help text and validates input, rejecting unknown values with a clean listing error.
  • File-path validation happens at the Typer layer (exit code 2, "does not exist" message) before the command body runs, distinct from loader-level not-found handling.
  • Help panels are purely organizational; they don't affect functionality, only the layout of `--

https://claude.ai/code/session_01WsMwnsXuSkgrX4UzC3aJqP

claude and others added 11 commits June 7, 2026 15:41
transcribe exposes 40+ options that previously rendered as one flat
Options wall in --help. Tag each flag with rich_help_panel so the
existing code-comment groupings (model, formatting, speakers,
guardrails, analysis, customization, webhooks, translation, advanced,
LLM transform) become visible sections. Everyday flags (--sample,
--json, -o, --show-code) stay in the default Options panel so the
common case stays at the top. Panel headings are centralized in
help_panels.py as a single source of truth.
stream has the same 37-flag wall as transcribe. Tag each flag with
rich_help_panel, reusing the shared panel vocabulary (Model & Language,
Speakers, Guardrails, Webhooks, LLM Transform, Advanced) so the two
sibling commands read consistently, plus three stream-specific panels
(Audio Capture, Turn Detection, Features) for real-time concerns that
file transcription has no equivalent for. Everyday flags (--sample,
--json, -o, --show-code) stay in the default Options panel, mirroring
transcribe.
Use the assemblyai SDK's own enums as the Typer option types for flags
with a fixed value set: --speech-model, --summary-model, --summary-type,
--redact-pii-sub (transcribe) and --speech-model, --encoding,
--voice-focus (stream). Typer now renders the valid choices in --help
(e.g. [best|nano|slam-1|universal]), validates input with a clean
listing error, and completes the values on Tab. A new
config_builder.enum_value() unwraps each member to its canonical string
at the body boundary, so the config/codegen pipelines stay string-based
and --show-code output is unchanged. This also fixes a latent bug: the
old --voice-focus help advertised near_field/far_field, but the SDK
values are hyphenated (near-field/far-field).
Introduce aai_cli/choices.py with TranscriptOutput (text/id/status/
utterances/srt/json) and TextOrJson (text/json) StrEnums, and use them
as the -o/--output option type across transcribe, transcripts get,
stream, agent, and llm. Typer now lists the modes in --help and rejects
a bad value with a clean listing error, replacing the hand-rolled
output.validate_output_field and client.TRANSCRIPT_OUTPUT_FIELDS (both
removed). StrEnum members are strings, so the existing field == 'text'
comparisons and select_transcript_field() calls are unchanged.
Use choices.Scope (user/project/local) for the --scope option on
'aai setup install' and 'aai setup remove', so Typer lists the scopes
in --help and rejects a bad value with a clean listing error. Removes
the hand-rolled _VALID_SCOPES check in both commands; StrEnum members
are strings, so they pass straight through to 'claude mcp add'.
Flip add_completion=True so 'aai --install-completion' / '--show-completion'
work; combined with the enum-typed flags from earlier, choices, file
paths, and command names now complete on Tab. Add autocompletion
callbacks for the two open-set flags whose values aren't enums:
llm.complete_model (suggests KNOWN_MODELS without restricting input,
wired into transcribe/stream/llm --model) and voices.complete_voice
(agent --voice). The existing --list-voices/--list-models flags stay as
a no-completion-needed fallback.
- File-path options (transcribe --config-file/--custom-spelling-file,
  stream --config-file, agent --system-prompt-file) gain exists=True
  + dir_okay=False, so Typer rejects a missing path up front with a
  standard message instead of relying on the loaders' deeper handling.
  Widen config_builder signatures to accept Path. (readable=True was
  dropped: it can't be exercised in CI, which runs as root.)
- Add metavar=KEY=VALUE to --config and metavar=NAME:VALUE to
  --webhook-auth-header so the expected shape shows in --help.
- Add an eager root --version flag alongside the existing 'version'
  command.
client.transcribe() blocks on the SDK's poll-to-completion with no
feedback — on a long file the terminal looks frozen. Wrap the wait in
a new output.status() context manager that shows an ephemeral rich
spinner on stderr, so stdout pipelines (e.g. -o text > out) stay clean.
It's a no-op in JSON or non-interactive mode (piped / agent-run), so
machine output is never decorated. Uses rich, already a dependency.
- .mcp.json was accidentally swept into the --scope commit by an
  'aai setup install' verification run (added an assemblyai-docs entry
  and dropped the trailing newline), which failed the pre-commit
  end-of-file-fixer. Restore it to match origin/main.
- test_shell_completion_is_enabled asserted on rendered --help text,
  which wraps/renders differently in CI's terminal and hid the flag.
  Introspect the Click command's params instead — stable regardless of
  width, and still flips when add_completion is disabled.
@alexkroman alexkroman merged commit be8b6ce into main Jun 7, 2026
10 checks passed
@alexkroman alexkroman deleted the claude/cli-usability-Y4JiI branch June 7, 2026 23:35
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