Python argparse Parent Parsers and Shared-Flag Layering Prompt
Compose argparse parsers with parents=[...] to share common flags across subcommands and layer config-file, env, and flag precedence
- Target user
- Python tooling authors building multi-command operational CLIs
- Difficulty
- Intermediate
- Tools
- Claude, ChatGPT, Cursor
The prompt
You are a senior Python engineer building an operational CLI. Write a script that uses `argparse` with parent parsers (`parents=[...]`) to share common flags across multiple subcommands, and that resolves configuration from three layered sources. Follow these steps: 1. Create a "common" parent parser with `argparse.ArgumentParser(add_help=False)` holding the shared flags from [COMMON_FLAGS] (e.g. `--config`, `--log-level`, `--profile`, `--dry-run`), then declare the explicit `add_help=False` so the parent does not register its own `-h`. 2. Build the top-level parser and a `subparsers` group; for each subcommand in [SUBCOMMANDS] (e.g. `deploy`, `rollback`, `status`), register it with `parents=[common_parser]` so every subcommand inherits the shared flags without duplication. 3. Add subcommand-specific arguments after the parents are attached, so they layer on top of the inherited flags. 4. Implement config precedence in this exact order, lowest to highest: built-in defaults < values from a config file at [CONFIG_PATH] < environment variables prefixed [ENV_PREFIX] < explicit command-line flags. Only override a lower layer when the higher layer actually supplied a value (distinguish "not provided" from "provided as default"). 5. Use `parser.set_defaults(func=...)` per subcommand so dispatch is a single `args.func(args)` call; resolve the merged config before invoking the handler. 6. On precedence ambiguity or an unknown subcommand, print the resolved-config provenance (which source won for each key) when [DEBUG_FLAG] is set. Output format: a single runnable module that, when called with `--help`, lists shared flags under every subcommand; and that can print the effective merged configuration as JSON when `--show-config` is passed. Guardrail: the merge step must be pure and idempotent — resolving the same inputs twice yields the same config and mutates no global state; default to `--dry-run` true for any subcommand that performs writes so a misconfigured invocation is non-destructive until explicitly confirmed.
Why this prompt works
As an operational CLI grows from one command to ten, the shared flags — --config, --log-level, --profile, --dry-run — start getting copy-pasted into every subparser, and they inevitably drift. argparse’s parent-parser mechanism (parents=[...]) is the canonical fix: define the common flags once in an add_help=False parser and attach it to every subcommand. This prompt makes that pattern explicit and pairs it with the one detail that trips everyone up the first time — forgetting add_help=False on the parent, which causes argparse to register -h twice and blow up at construction time.
The harder, more valuable half is configuration precedence. Real tools draw settings from defaults, a config file, environment variables, and command-line flags all at once, and operators expect a predictable override order. By spelling out the exact lowest-to-highest chain and demanding that the merge only override when a higher layer actually supplied a value, the prompt steers the model away from the classic bug where an unset CLI flag’s default value silently overwrites a perfectly good config-file entry. Using None sentinels to distinguish “not provided” from “default” is the practical trick that makes layered precedence correct rather than approximately correct.
The guardrail keeps the resulting tool trustworthy. A config resolver that mutates global state or yields different results on a second pass is impossible to test and frightening to run. Requiring a pure, idempotent merge — plus a --show-config JSON dump and provenance output for debugging — turns configuration from a black box into something an engineer can inspect before acting. Defaulting write-capable subcommands to --dry-run ensures that a half-configured invocation reports what it would do instead of doing it, which is exactly the posture you want for deploy and rollback tooling.
Related prompts
-
Bash Script Code Review Prompt
Get a senior-engineer review of any Bash script — safety, idempotency, error handling, portability.
-
Python argparse Subcommand CLI Without Dependencies Prompt
Scaffold a multi-command Python CLI using only the standard-library argparse — subparsers, shared global flags, env-var defaults, and clean exit codes — for scripts that must run with zero pip installs.
-
Python Layered Config Precedence Resolver Prompt
Build a Python config resolver that merges defaults, config file, environment variables, and CLI flags into a typed dataclass with deterministic precedence