AI-Assisted argparse CLI Design for Python Ops Tools
Design clean, discoverable argparse CLIs with AI help — subcommands, sane defaults, dry-run flags, and validation that stops bad invocations before they run on prod.
- #python
- #bash
- #cli
- #argparse
Most internal ops tools start as a script with three positional arguments that everyone has to memorize in the right order. Six months later it has fifteen options crammed in as environment variables and if len(sys.argv) checks. I’ve started using AI to design the argparse layer up front, and it turns a Friday-afternoon hack into something a teammate can actually run safely. The catch, as always: the AI drafts fast like a junior engineer, and I review every default and validation rule before this thing runs against production.
Describe the tool, not the code
I don’t ask the AI to “write argparse code.” I describe the tool’s job and the operations it performs, then ask it to propose a command structure. For a node-management tool I wrote: “This tool drains, cordons, and reboots Kubernetes nodes. Propose a subcommand-based CLI with safe defaults and a dry-run option.”
The AI returned a clean drain / cordon / reboot subcommand layout with a global --dry-run and --cluster flag. Describing intent gets better structure than describing syntax, because the AI reasons about the workflow rather than just transcribing flags.
Use subparsers for distinct operations
The first thing I have it generate is the subcommand skeleton. Subparsers keep each operation’s flags isolated and give you free --help per command.
import argparse
def build_parser():
parser = argparse.ArgumentParser(prog="nodectl", description="Manage cluster nodes")
parser.add_argument("--cluster", required=True, help="Target cluster name")
parser.add_argument("--dry-run", action="store_true",
help="Print actions without executing them")
sub = parser.add_subparsers(dest="command", required=True)
drain = sub.add_parser("drain", help="Drain a node")
drain.add_argument("node", help="Node name")
drain.add_argument("--grace-period", type=int, default=120,
help="Seconds to wait for pods to terminate")
sub.add_parser("cordon", help="Cordon a node").add_argument("node")
return parser
I review the defaults specifically. The AI initially set --grace-period to 30, which is fine for a web pod and disastrous for a stateful workload mid-flush. I bumped it to 120 after checking our actual pod termination times. The AI had no way to know that — it guessed, and the guess was wrong for our environment.
Make dry-run the safe default for destructive tools
For anything that mutates production, I ask the AI to wire --dry-run through the execution path so the default invocation is loud but safe.
def run_drain(args):
cmd = ["kubectl", "drain", args.node,
"--grace-period", str(args.grace_period)]
if args.dry_run:
print("[dry-run] would run:", " ".join(cmd))
return
subprocess.run(cmd, check=True)
Pro Tip: ask the AI to make --dry-run the implied default and require an explicit --confirm for destructive actions. Inverting the default so the dangerous path needs a flag — not the safe one — has saved me from more 2am mistakes than any other single change.
Validate inputs before doing anything
argparse handles types, but not semantics. A node name that doesn’t exist, a cluster you’re not connected to — those should fail fast with a clear message. I prompt: “Add validation that runs before any action and produces actionable error messages.”
def validate(args):
if not re.fullmatch(r"[a-z0-9-]+", args.node):
sys.exit(f"error: invalid node name: {args.node!r}")
if args.cluster not in known_clusters():
sys.exit(f"error: unknown cluster {args.cluster!r}; "
f"known: {', '.join(known_clusters())}")
The AI is good at producing thorough validators, but it over-validates by default — its first pass rejected perfectly legal node names with dots in them. I loosened the regex after checking our naming convention. Review the rules against reality, not against what the AI assumes reality looks like.
Custom types and choices keep invocations honest
For constrained inputs, choices and custom type functions catch errors at parse time with a readable message. This pairs naturally with parsing arguments in bash scripts the right way when you have a mixed shell-and-Python toolkit.
def positive_int(value):
iv = int(value)
if iv <= 0:
raise argparse.ArgumentTypeError(f"must be positive, got {iv}")
return iv
drain.add_argument("--max-pods", type=positive_int, default=10)
reboot.add_argument("--strategy", choices=["graceful", "force"], default="graceful")
If you’d rather build on a richer framework, the same design principles apply to Typer and Click — the AI can port an argparse design to either.
Keep secrets out of flags entirely
A tempting anti-pattern the AI will happily generate if you let it: a --token flag. Tokens on the command line leak into shell history and process listings. I tell the AI explicitly: “Never accept secrets as CLI flags. Read them from the environment or a secrets manager.”
token = os.environ.get("NODECTL_TOKEN")
if not token:
sys.exit("error: set NODECTL_TOKEN in the environment")
And I never paste a real token into the chat to “test it.” The AI designs the plumbing; I supply the credential at runtime, locally. This is the same boundary I keep everywhere — see the bash and Python automation guides for the full pattern.
Generate the help text and shell completion
Once the structure is solid, the AI fills in help strings and can generate argcomplete setup so the CLI tab-completes. This is genuine grunt work it does well, and it makes the tool discoverable without a wiki page. I still read every help string — a misleading --force description is its own kind of bug.
Conclusion
AI designs argparse CLIs the way a sharp junior engineer would: a sensible subcommand layout in seconds, thorough validation, decent help text. And like a junior, it picks the wrong default grace period, over-validates names, and reaches for a --token flag if you don’t stop it. Describe intent, review every default and validation rule, keep secrets off the command line, and make dry-run the safe path. The speed is real; the judgment stays yours. Reusable CLI-design prompts live in the prompts library and prompt packs.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.