REQ-C-026: Commands Declare Conditional Argument Dependencies
Tier: Command Contract | Priority: P1
Source: §54 Conditional / Dependent Argument Requirements
Addresses: Severity: High / Token Spend: High / Time: Medium / Context: Low
Description
Commands MUST declare all conditional argument requirements in their registration metadata using a requires clause, rather than discovering them at runtime. The requires clause specifies: when flag A has value V, flag B is required; when flag A is present, flag B is prohibited (mutual exclusion); when flag A is absent, flag B has a different default; at least one flag of a group is present; exactly one flag of a group is present. The framework validates all declared requires relationships during the validate-before-execute phase (Phase 1), before any side effects. The --schema output MUST include the full requires graph so agents can construct valid calls without trial-and-error discovery.
Acceptance Criteria
- A command with
requires: [{if: "--format=csv", then: "--separator"}]exits 2 with a structured error when--format csvis passed without--separator - The
--schemaoutput includes the full conditional dependency graph - Mutually exclusive flags are enforced in Phase 1: passing both produces exit 2 before any I/O
- An agent calling
--schemacan determine all required flags for a given combination of values without making a failing call first - A command with an
any_ofrule exits 2 before any I/O when no flag of the group is present - A command with a
one_ofrule exits 2 before any I/O when two or more flags of the group are present - A command with a
one_ofrule passes Phase 1 validation when exactly one flag of the group is present - With
one_of: ["exact", "fuzzy"]on two boolean flags,--no-exact --fuzzypasses Phase 1 validation, and--no-exactalone exits 2 because no flag of the group is present - The
ARG_ERRORmessage and its error details name every flag in a violatedany_oforone_ofgroup
Schema
Types: manifest-response.md
CommandEntry is extended with a requires array:
| Field | Type | Description |
|---|---|---|
requires |
ConditionalRule[] |
Ordered list of conditional argument dependency rules |
Each ConditionalRule has one of the following shapes:
| Shape | Fields | Meaning |
|---|---|---|
if_value |
if_flag, if_value, then_required |
When if_flag equals if_value, flags in then_required become required |
if_present |
if_flag, prohibited |
When if_flag is present, flags in prohibited are forbidden |
default_when_absent |
if_flag, target_flag, default |
When if_flag is absent, target_flag uses this default instead of its declared default |
any_of |
any_of |
At least one flag in any_of is present |
one_of |
one_of |
Exactly one flag in one_of is present |
A flag is present when the caller supplies it: on the command line, or through any other explicit input channel the framework treats as supplied. A declared default does not make a flag present. A boolean flag is present only when its value is true: an explicit false (--no-exact, or false through any other explicit input channel) is the same as leaving the flag out. This definition governs every rule that tests presence or absence: if_present, default_when_absent, any_of, and one_of. An if_value rule compares values instead, so if_value: false still matches an explicit false. any_of and one_of each list at least two distinct flag names. A one_of group already forbids combining its members, so it replaces pairwise if_flag/prohibited rules between them rather than adding to them.
Wire Format
$ tool export --schema
{
"parameters": {
"format": { "type": "enum", "required": true, "enum_values": ["csv", "json", "parquet"], "description": "Output format" },
"separator": { "type": "string", "required": false, "description": "Field separator for CSV output" },
"compress": { "type": "boolean", "required": false, "default": false, "description": "Compress output" },
"output": { "type": "string", "required": false, "description": "Output file path" },
"stdout": { "type": "boolean", "required": false, "default": false, "description": "Write to stdout instead of file" }
},
"requires": [
{ "if_flag": "format", "if_value": "csv", "then_required": ["separator"] },
{ "if_flag": "output", "prohibited": ["stdout"] }
],
"exit_codes": {
"0": { "name": "SUCCESS", "description": "Export completed", "retryable": false, "side_effects": "complete" },
"2": { "name": "ARG_ERROR", "description": "Conditional argument rule violated", "retryable": false, "side_effects": "none" }
}
}
A group rule declares that exactly one identifier flag is present:
$ tool quote --schema
{
"parameters": {
"isin": { "type": "string", "required": false, "description": "Instrument ISIN" },
"figi": { "type": "string", "required": false, "description": "Instrument FIGI" },
"symbol": { "type": "string", "required": false, "description": "Instrument ticker symbol" }
},
"requires": [{ "one_of": ["isin", "figi", "symbol"] }],
"exit_codes": {
"0": { "name": "SUCCESS", "description": "Quote returned", "retryable": false, "side_effects": "none" },
"2": { "name": "ARG_ERROR", "description": "Conditional argument rule violated", "retryable": false, "side_effects": "none" }
}
}
Example
register command "export":
parameters:
format: type=enum(csv, json, parquet), required=true
separator: type=string, required=false
compress: type=boolean, required=false, default=false
output: type=string, required=false
stdout: type=boolean, required=false, default=false
requires:
- if format == "csv" → separator is required
- if output present → stdout is prohibited (mutually exclusive)
# tool export --format csv
# → exit 2: ARG_ERROR: --format csv requires --separator
# tool export --format json --output report.json --stdout
# → exit 2: ARG_ERROR: --output and --stdout are mutually exclusive
register command "quote":
parameters:
isin: type=string, required=false
figi: type=string, required=false
symbol: type=string, required=false
requires:
- exactly one of isin, figi, symbol is present
# tool quote --isin US0378331005 --symbol AAPL
# → exit 2: ARG_ERROR: pass exactly one of --isin, --figi, --symbol (got --isin, --symbol)
# tool quote
# → exit 2: ARG_ERROR: pass exactly one of --isin, --figi, --symbol (got none)
Related
| Requirement | Tier | Relationship |
|---|---|---|
| REQ-C-015 | C | Composes: requires graph is part of the --schema output that agents read |
| REQ-F-015 | F | Enforces: requires rules are evaluated in Phase 1 before any side effects |
| REQ-C-006 | C | Specializes: conditional dependency validation is one category of Phase 1 argument validation |
| REQ-F-002 | F | Enforces: requires violations exit with code 2 (ARG_ERROR) |