Awesome-omni-skill cli-ux
Agent-first CLI design: JSON envelope output, Rich human UX, progress indicators, and dual-mode routing.
install
source · Clone the upstream repo
git clone https://github.com/diegosouzapw/awesome-omni-skill
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/development/cli-ux" ~/.claude/skills/diegosouzapw-awesome-omni-skill-cli-ux && rm -rf "$T"
manifest:
skills/development/cli-ux/SKILL.mdsource content
CLI UX Design
Purpose
Agent-first CLI design skill for commands that serve both machine consumers (JSON envelopes via
--json) and human operators (Rich terminal output). Covers the dual-output routing pattern, structured JSON envelopes with HATEOAS next actions, Rich progress indicators, data model conventions, and terminal visual language used across the ai-eng CLI.
Trigger
- Command: agent invokes cli-ux skill or user requests CLI command design/review.
- Context: new CLI command, CLI output review, adding
support, improving terminal UX, adding progress indicators.--json
When NOT to Use
- API endpoint design — use
for REST/GraphQL contract-first design.dev:api-design - CI/CD pipeline configuration — use
for pipeline setup.dev:cicd-generate - General code review — use
for implementation review.dev:code-review - Test strategy for CLI commands — use
for test design.dev:test-strategy
Procedure
-
Understand output context — determine if the command needs JSON mode, human mode, or both.
- All user-facing commands MUST support both modes (dual-output).
- Internal/plumbing commands may be JSON-only.
- Read
for the routing pattern.src/ai_engineering/cli_output.py
-
Design data model — every result gets both
andto_dict()
.to_markdown()
: returns a JSON-serializable dict for the envelope.to_dict()
: returns a human-readable markdown string.to_markdown()- Serialization rules:
→Path
, dates →.as_posix()
, enums →.isoformat()
..value - Use Pydantic models or
— never raw dicts as primary data structures.@dataclass
-
Implement dual-output routing — branch on
.is_json_mode()- JSON path:
→ stdout.emit_success(command_name, data_dict, [NextAction(...)]) - JSON errors:
→ stdout.emit_error(command_name, message, error_code, fix, [NextAction(...)]) - Human path:
,result_header()
,kv()
,status_line()
→ stderr.suggest_next() - Rule: JSON goes to stdout, human messaging goes to stderr (CLIG guideline).
- Use
router fromoutput()
for clean branching.cli_output.py
- JSON path:
-
Design JSON envelope — follow the
/SuccessEnvelope
contract.ErrorEnvelope- Success:
.{ ok: true, command: str, result: dict, next_actions: [...] } - Error:
.{ ok: false, command: str, error: { message, code }, fix: str, next_actions: [...] } - HATEOAS
:NextAction
— suggest follow-up commands.{ command: str, description: str, params?: dict } - Use
for large collections to protect agent context windows.truncate_list(items, max_items=20)
- Success:
-
Add progress indicators — wrap long operations in
orspinner()
.step_progress()
: single-step context manager for indeterminate waits.spinner(description)
: multi-step tracker withstep_progress(total, description)
.tracker.step(msg)- Auto-suppressed in JSON mode (
) and non-TTY (CI, piped output).is_json_mode() - Transient by default — spinners disappear when done, leaving clean output.
- Gate hooks (pre-commit, commit-msg, pre-push): NEVER add progress indicators.
-
Apply visual language — consistent Rich markup and color semantics.
- Success:
(green). Error:[success]
(red). Warning:[error]
(yellow). Info:[warning]
(blue).[info] - Brand accent:
(teal[brand]
). Muted:#00D4AA
(dim). Paths:[muted]
(teal underline).[path] - Key-value pairs:
. File counts:kv(key, value)
.file_count(label, count) - Section dividers:
. Result summary:header(title)
.result_header(label, status, detail) - Next steps:
.suggest_next([(command, description), ...]) - Respect
,NO_COLOR
, and non-TTY detection (handled byTERM=dumb
).get_console()
- Success:
-
Validate output contract — verify both output modes work correctly.
- JSON: output is valid JSON, parseable by
.json.loads() - JSON: envelope matches
/SuccessEnvelope
schema.ErrorEnvelope - Human: output is readable, no raw dicts or repr strings.
- Test:
flag produces stdout-only JSON; human mode produces stderr-only Rich output.--json
- JSON: output is valid JSON, parseable by
Output Contract
- CLI command with dual-output support (JSON + human).
- Data model with
andto_dict()
methods.to_markdown() - JSON envelope conforming to
/SuccessEnvelope
.ErrorEnvelope - Progress indicators that auto-suppress in JSON/non-TTY contexts.
Governance Notes
- CLI output modules are framework-managed — changes require governance review.
- JSON envelope schema (
/SuccessEnvelope
) is a contract — do not modify fields without versioning.ErrorEnvelope - Human output primitives (
) are shared — additions are welcome, removals require deprecation.cli_ui.py - All new commands must pass
output validation in tests.--json
Iteration Limits
- Max 3 attempts to resolve the same CLI output issue. After 3 failures, escalate to user with evidence.
Post-Action Validation
- After implementing dual-output, verify JSON is parseable with
.json.loads() - Run the command with and without
to confirm both paths work.--json - If validation fails, fix issues and re-validate (max 3 attempts).
References
— Python stack patterns.standards/framework/stacks/python.md
Implementation Files (repo root-relative)
Read these on-demand when implementing or reviewing CLI commands:
— JSON envelope (src/ai_engineering/cli_envelope.py
,SuccessEnvelope
,ErrorEnvelope
).NextAction
— Rich human output primitives (src/ai_engineering/cli_ui.py
,kv
,status_line
,result_header
).suggest_next
— dual-mode router (src/ai_engineering/cli_output.py
,is_json_mode
).output
— spinner and step_progress context managers.src/ai_engineering/cli_progress.py
— reference implementation (install, doctor commands).src/ai_engineering/cli_commands/core.py