CLI Style Design Draft
This is a discussion draft for explaining what ChatStyle should standardize, what it should not standardize, and why these conventions matter for future chatxxx tools under ChatArch. It is not a final API contract; it is a design map to avoid X-Y problems.
Background And Intent
ChatArch is a GitHub organization for building reusable tools. Future projects will often follow the chatxxx CLI shape.
These CLI projects are usually initialized through chattool pypi / chatpypi init. ChatStyle should become the default dependency injected by those templates, so new tools inherit the same CLI behavior convention instead of copying interaction code into every project.
Those tools have different business domains, but they repeatedly face the same CLI interaction questions:
- Should missing arguments trigger prompts?
- When is interactive mode allowed?
- How do scripts and CI disable prompts?
- How should tokens, passwords, and API keys be displayed?
- How should select, checkbox, and confirm behave?
- Where do defaults come from and what should prompts display?
- How should errors guide the next action?
- How should projects generated by
chatpypi initget the same CLI behavior by default?
ChatStyle is not meant to become a complex TUI framework, and it should not abstract every possible CLI framework feature. It should provide a small and stable set of shared interaction conventions and runtime helpers for ChatArch CLI tools. If a capability cannot be reused by multiple chatxxx tools, it should not enter ChatStyle.
One-Sentence Definition
ChatStyle is the interaction convention and lightweight runtime for ChatArch CLI tools.
Downstream projects should be able to say:
We own business logic; ChatStyle owns missing-argument prompting, interactive switches, secret display, multi-select behavior, and common CLI output conventions.
Goals
Consistent Behavior
CLI tools in the same organization should behave consistently in common situations:
-iforces the current command's interactive flow.-Idisables prompts for scripts and CI.- Recoverable missing arguments may prompt only when TTY is available.
- Non-TTY environments never block on input.
- Secrets are always masked when displayed.
- Select and checkbox behavior is consistent.
Lower Template Complexity
Projects generated by chatpypi init should not copy prompt and resolver implementation code. Templates should depend on:
Then commands should use ChatStyle public APIs.
Keep The Base Library Generic
ChatStyle should not know about ChatTool, a specific API, a specific config path, or a specific business command. It provides reusable CLI interaction building blocks.
Stay Automation-Friendly
ChatArch tools are often used by scripts, CI, GitHub Actions, or cron. Interactive convenience must not break automation.
Every prompt capability needs a non-interactive path: complete arguments, defaults, or fast failure.
Non-Goals
ChatStyle does not:
- Build a full TUI application framework.
- Own product command flows.
- Read or write downstream project configuration.
- Run installers, system commands,
sudo, or remote APIs. - Define ChatTool-specific copy.
- Force every project to have the same product branding.
ChatStyle standardizes CLI behavior and baseline presentation, not all business experience. The decision rule is whether a capability belongs to the shared ChatArch CLI convention, not whether it is convenient for one tool.
Conceptual Model
ChatStyle can be described in four layers:
User Intent
↓
Command Input Contract
↓
Interaction Runtime
↓
Presentation Primitives
↓
Business Logic
User Intent
A user expresses intent through:
- Explicit arguments:
--name demo --token xxx - Interactive answers: prompt input for missing values
- Defaults: values from commands, config, or environment
ChatStyle only merges those inputs into complete values. It does not decide what the business command does.
Command Input Contract
The command input contract describes what fields a command needs. This is currently CommandSchema:
CommandField: field name, prompt copy, type, default, required flag, sensitive flag.CommandConstraint: cross-field validation.CommandSchema: field and constraint collection for one command.
This makes missing-argument recovery declarative instead of hand-written if/else in each command.
Interaction Runtime
The interaction runtime decides when to prompt, how to fail, and how to merge inputs:
interactive=True: the user explicitly requests prompts.interactive=False: the user explicitly disables prompts.interactive=None: automatic mode.- TTY available: prompting is possible.
- TTY unavailable: no prompt; use existing defaults or fail fast.
Presentation Primitives
Presentation primitives are the low-level interaction and display blocks:
- text/path input
- confirm
- select
- checkbox
- secret masking
- heading/note/status
- command suggestion
- priority chain
These primitives should stay business-neutral.
Business Logic
Business logic belongs to downstream projects, for example:
- Creating GitHub PRs.
- Publishing PyPI packages.
- Generating certificates.
- Updating DNS records.
- Writing config files.
- Calling product APIs.
ChatStyle does not enter this layer.
Missing Argument Convention
Missing-argument recovery is one of ChatStyle's core values.
Recommended rules:
- Do not set recoverable Click options as
required=True. - Use
CommandField(required=True)for fields required by business logic. - Call
resolve_command_inputs()inside the callback. - Let the resolver prompt or fail based on the interactive policy.
import click
from chatstyle import CommandField, CommandSchema, add_interactive_option, resolve_command_inputs
SCHEMA = CommandSchema(
name="publish",
fields=(
CommandField("package", prompt="package name", required=True),
CommandField("repository", prompt="repository", default="pypi"),
CommandField("token", prompt="api token", sensitive=True, required=True),
),
)
@click.command()
@click.option("--package", required=False)
@click.option("--repository", required=False)
@click.option("--token", required=False)
@add_interactive_option
def publish(package, repository, token, interactive):
values = resolve_command_inputs(
schema=SCHEMA,
provided={"package": package, "repository": repository, "token": token},
interactive=interactive,
usage="Usage: publish --package TEXT [--repository TEXT] [--token TEXT] [-i|-I]",
)
run_publish(values)
Expected behavior:
- Complete arguments: run directly.
- Missing arguments with TTY: prompt for recoverable fields.
- Missing arguments with
-i: force prompts; fail if TTY is unavailable. - Missing arguments with
-I: do not prompt; fail fast. - Missing arguments without TTY: do not prompt; fail fast.
Interactive Switches
ChatStyle standardizes tri-state interactive mode:
| State | Source | Meaning |
|---|---|---|
True |
-i / --interactive |
Force the current command's interactive flow |
False |
-I / --no-interactive |
Disable prompts for automation |
None |
unspecified | Automatic mode; prompt only when TTY is available and recoverable fields are missing |
Important boundaries:
-iis not a global wizard switch. It applies to the current command.-Iis an automation contract and must guarantee no blocking prompts.
Masking And Secrets
Secrets include:
- tokens
- passwords
- API keys
- app secrets
- webhook secrets
- private key fragments
Rules:
- Hide input.
- Mask displayed values.
- Never write raw secrets to logs, exceptions, or summaries.
- If empty input keeps the old value, the prompt must say so.
Choice And Multi-Select
ChatStyle provides a shared choice representation so downstream projects do not need to depend on questionary details.
Principles:
- Use
questionaryfor better UX when available. - Fall back to Click when optional dependencies are unavailable.
- Labels are for humans; values are for programs.
- Empty choices should not become business exceptions; callers decide how to handle them.
- Checkbox supports multi-select but should not grow into a complex TUI state machine.
Output Style
The output layer should provide common presentation, not business interpretation.
Reasonable common helpers:
- heading
- note
- success/warning/error/info status
- key-value summary
- suggested commands
- priority chain
Helpers that need caution:
- setup-specific helpers
- command-specific summaries
- automatic system command execution
- business-specific recovery suggestions
Rethinking Setup
"Setup-stage output, suggested commands, and config-priority display" originally came from setup command scenarios, but these capabilities are not setup-specific.
A better abstraction is:
- Flow-stage display: useful for any long-running command.
- Suggested command display: useful for doctor, deploy, repair, and setup.
- Config-priority display: useful for any CLI that reads config.
So the implementation should avoid giving setup special treatment. The current direction is to move these helpers into generic output/flow APIs:
render_stage("Check environment")
render_suggested_commands(["sudo systemctl restart demo"])
render_priority_chain(["CLI option", "ENV", "config file", "default"])
chatstyle.setup is not part of the first public core; setup-like needs are handled by generic flow/output helpers.
ChatStyle And chattool pypi
ChatStyle's main delivery path is through chattool pypi / chatpypi init when creating ChatArch CLI tools. Templates should generate minimal code:
- Add the
chatstyledependency. - Use Click as the command framework.
- Use
CommandSchemafor inputs. - Use
add_interactive_option()for-i/-I. - Use
resolve_command_inputs()for missing-argument recovery. - Use
mask_secret()and select/checkbox helpers for common interactions.
Templates should not copy ChatStyle internals.
API Layering Proposal
Stable Public API
Good candidates for chatstyle.__init__:
CommandFieldCommandSchemaCommandConstraintresolve_command_inputsadd_interactive_optionask_textask_pathask_confirmask_selectask_checkboxmask_secret
Candidate Public API
Names and boundaries need discussion:
render_headingrender_noterender_statusrender_suggested_commandsrender_priority_chainrender_flow_startrender_stagerender_successrender_warningrender_failurerender_commandscreate_choiceget_separator
Avoid Or Expose Carefully
- Underscore helpers.
- Helpers tied to one business scenario.
- APIs that require optional dependency objects as parameters.
- APIs that execute system commands or write files.
Module Boundary Draft
Suggested long-term modules:
chatstyle.input input contract, resolution, Click integration
chatstyle.tui prompt primitives, choice representation, adapters
chatstyle.render common output, flow stages, suggested commands, priority chains
chatstyle.security secret display and input
chatstyle.core TTY / interactive policy, error helpers, shared constants
chatstyle.patterns cross-module recipes
flow is the core flow-display module; setup-like scenarios are composed from flow / output helpers.
Design Principles
Small Core
Prefer fewer APIs over turning single-project convenience helpers into foundational contracts.
Graceful Degradation
Rich, questionary, and prompt_toolkit are UX improvements, not runtime requirements.
Automation First
Every interactive feature must be bypassable through explicit arguments or -I.
Declarative First
Missing-argument recovery and defaults should be described by schemas instead of copied if/else blocks in callbacks.
Business Outside
ChatStyle does not know what publish, certificate, DNS, PR, or setup means.
Open Questions
- Should
chatstyle.setupbe reintroduced later as a scenario wrapper? - What stable output APIs should exist: heading/note only, or status/summary/table as well?
- Should
CommandSchemasupport richer choice value/label objects instead ofSequence[str]? - Is
prompt_if_missingthe right name, or should it becomeprompt_if_defaulted/confirm_default? - Do errors need structured error codes for automation?
- How complex should the
chatpypi initexample be: text/path/secret only, or also select/checkbox? - Do we need project presets like
standard_cli_schema(), or should everything stay explicit? - Should docs define ChatStyle as "specification first, runtime second"?
Current Recommendation
Short term:
- Keep
CommandSchemaas the core. - Strengthen prompt, mask, interactive, and Click integration tests.
- Keep setup-scenario behavior behind generic flow/output APIs.
- Explain concepts and conventions before APIs in docs.
- Let
chatpypi initdepend on ChatStyle instead of copying implementation.
Long term:
- ChatStyle should become the single source of ChatArch CLI behavior conventions.
- Downstream projects should receive interaction updates through dependency upgrades.
- Every new API should answer: does this belong to the shared ChatArch CLI convention, and is it useful for at least two
chatxxxtools?