# ADR-0041: allow_hyphen_values for 15 text-accepting CLI fields across 8 structs
- **Status**: Accepted
- **Date**: 2026-06-19
- **Context**: Clap v4 treats any token starting with `-` as a CLI flag by default. 15 fields across 8 argument structs (`EditArgs`, `SearchArgs`, `ReplaceArgs`, `CalcArgs`, `RegexArgs`, `TransformArgs`, `ReadArgs`, `QueryArgs`) accept free-text user content but lacked `allow_hyphen_values = true`. This caused `ARGUMENT_PARSE_ERROR` (exit 2) when values contained leading hyphens — common in Markdown bullet points (`- item`), negative numbers (`-5 + 3`), YAML entries (`- key: value`), and diff content (`--- a/file`). In LLM agent pipelines, the failure cascaded: exit 2 masked by `jaq` pipe (the downstream `jaq` receives `null` and prints `{"edits": null}` with exit 0), agent workaround via truncating `write`, catastrophic data loss (file of 22,597 bytes overwritten by 13 bytes). The problem was first observed in v0.1.22 but existed since the introduction of `--old`/`--new` in v0.1.12. No test ever passed a value starting with `-` to any of the 15 affected fields, so the bug was invisible to the regression suite. `CaseArgs.subvert` was evaluated but excluded: its `num_args = 2..` attribute creates a greedy parser that swallows subsequent flags as values when combined with `allow_hyphen_values`, breaking the `--to` flag parsing.
- **Decision**: Add `allow_hyphen_values = true` to all 15 affected `#[arg]` attributes in `src/cli_args.rs`. The fields are organized in three tiers by risk and usage frequency:
- **Tier 1 (EditArgs)**: `old`, `new`, `after_match`, `before_match`, `between` — the highest-risk fields because `edit` is the most common mutating command in agent pipelines, and Markdown bullet points are the most frequent source of leading hyphens.
- **Tier 2 (positionals)**: `SearchArgs.pattern`, `ReplaceArgs.pattern`, `ReplaceArgs.replacement`, `CalcArgs.expression`, `RegexArgs.examples` — positional arguments that accept arbitrary user content including negative numbers, regex patterns with character classes like `[-a-z]`, and example strings.
- **Tier 3 (named)**: `TransformArgs.pattern`, `TransformArgs.rewrite`, `TransformArgs.inline_rules`, `ReadArgs.grep`, `QueryArgs.query` — named flags that accept patterns, AST expressions, or regex filters that may start with `-`. Excluded: `CaseArgs.subvert` (`num_args = 2..` incompatible with `allow_hyphen_values`).
- **Consequences**:
- **+** Agents can edit Markdown content with bullet points (`--old "- old item" --new "- new item"`) without exit 2. This is the single most common failure mode reported in agent pipelines.
- **+** `calc "-5 + 3"` and `search "-deprecated"` work without requiring the user to insert a `--` separator or quote workarounds.
- **+** YAML content with leading hyphens can be edited, searched, and replaced directly.
- **+** Negative numbers in `calc` expressions are accepted as values, not rejected as unknown flags.
- **+** The fix eliminates the cascading failure chain: exit 2 → masked by jaq → agent workaround via truncating write → data loss.
- **-** (acceptable) `--old --typo` now treats `--typo` as the value of `--old` instead of reporting it as an unknown flag. This is acceptable for free-text fields where the user intent is always "this is content, not a flag". For non-content flags (e.g. `--backup`, `--dry-run`), the default Clap behavior is preserved and unknown flags are still reported.
- **-** (acceptable) A user who mistypes `--old --new "text"` (forgetting the value for `--old`) will get `--new` as the value of `--old` instead of a helpful error. This is an inherent tradeoff of `allow_hyphen_values` and is documented in the Clap v4 docs. The failure mode is detectable via the `pair_results` field in the edit response.
- **Alternatives considered**:
1. **`--` separator before hyphen-starting values.** Rejected: `--` terminates flag parsing globally, which breaks multi-pair mode (`--old "- a" --new "b" --old "- c" --new "d"` — the `--` would prevent the second `--old` from being parsed as a flag). Also incompatible with the agent pipeline pattern where `--old`/`--new` pairs are generated programmatically.
2. **Quoting convention documented in SKILL/CLAUDE.md.** Rejected: the quoting is already applied by agents (they pass `--old "- text"` with quotes), but Clap rejects the value BEFORE the quotes are processed by the shell. The fix must be at the Clap attribute level, not the shell level. Additionally, changing agent documentation does not fix existing agent workflows that already use the correct quoting.
3. **Apply `allow_hyphen_values` only to Tier 1 (EditArgs).** Rejected: the same bug exists in all 15 fields, and a partial fix would leave 10 fields vulnerable to the same cascading failure. The cost of fixing all 15 is identical (one attribute per field) and the risk is symmetric.
4. **Include `CaseArgs.subvert`.** Rejected: `subvert` uses `num_args = 2..` (greedy, accepts 2+ values). With `allow_hyphen_values = true`, Clap consumes subsequent flags (like `--to camel`) as values of `--subvert`, causing 5/7 case tests to fail with "odd count" validation error. Identifiers rarely start with `-`, so the risk is negligible.
- **Trigger to revisit**: If users report that `--old --typo` (mistyped flag name accepted as value) causes confusion in interactive use, add a `tracing::warn!` when a value matches the pattern `--[a-z]` to alert the user that their value looks like a flag name. If Clap v5 introduces a per-field `warn_on_hyphen_value` attribute, migrate to it for better diagnostics.