REQ-C-005: Interactive Commands Must Support --yes / --non-interactive
Tier: Command Contract | Priority: P0
Source: §10 Interactivity & TTY Requirements
Addresses: Severity: Critical / Token Spend: High / Time: Critical / Context: Low
Description
Any command that would prompt the user for confirmation or input in interactive mode MUST accept --yes (auto-confirm all prompts) and --non-interactive (fail immediately with exit code 4 if any prompt would be shown). The framework MUST register these flags automatically for any command that declares it uses interactive prompts. Command authors MUST declare prompt usage in registration metadata. A command declaring requires_person: true (REQ-C-036) is the one exception: its attestation exists so that a person, not the calling agent, confirms the command, and --yes does not answer it.
Acceptance Criteria
- A command that prompts for confirmation in interactive mode accepts
--yesand proceeds without prompting, except that a command withrequires_person: trueignores--yesfor its attestation and exits4withPERSON_REQUIREDoff a terminal (REQ-C-036) - With
--non-interactive, a command that would prompt exits with exit code 4 and a JSON error - The
--yesflag is idempotent: passing it to a command that never prompts has no effect, except on a command whoseconfirm_flagisyes(REQ-O-048), where it confirms execution and the command runs instead of previewing - The
--schemaoutput for interactive commands includesinteractive: true
Schema
Types: manifest-response.md
The interactive boolean and the standard --yes / --non-interactive flags appear in the command's schema entry.
{
"interactive": {
"type": "boolean",
"description": "True if the command may prompt for user input in a TTY context"
}
}
Wire Format
$ tool delete-account --user 42 --schema
{
"command": "delete-account",
"interactive": true,
"flags": {
"user": { "type": "integer", "required": true, "description": "User ID to delete" },
"yes": { "type": "boolean", "required": false, "default": false, "description": "Auto-confirm all prompts" },
"non-interactive": { "type": "boolean", "required": false, "default": false, "description": "Fail immediately if a prompt would be shown" }
},
"exit_codes": {
"0": { "name": "SUCCESS", "description": "Account deleted", "retryable": false, "side_effects": "complete" },
"4": { "name": "PRECONDITION", "description": "Prompt required but non-interactive mode is active", "retryable": false, "side_effects": "none" }
}
}
Example
A command that would prompt for confirmation in interactive mode declares interactive: true at registration. The framework auto-registers --yes and --non-interactive.
register command "delete-account":
interactive: true
danger_level: destructive
exit_codes:
SUCCESS (0): description: "Account deleted", retryable: false, side_effects: complete
PRECONDITION(4): description: "Prompt required but non-interactive mode is active", retryable: false, side_effects: none
execute(args, interactive_context):
if not args.yes and interactive_context.is_tty():
confirmed = prompt("Delete user {}? [y/N]".format(args.user))
if not confirmed:
return response(ok=False, exit=PRECONDITION)
delete_user(args.user)
return response(effect="deleted")
# agent call — no prompt, no hang:
# tool delete-account --user 42 --yes
Related
| Requirement | Tier | Relationship |
|---|---|---|
| REQ-F-009 | F | Provides: framework auto-detects non-TTY and suppresses prompts globally |
| REQ-C-002 | C | Composes: destructive commands are the primary case requiring interactive confirmation |
| REQ-C-004 | C | Composes: --dry-run is the preview step before the --yes-confirmed live run |
| REQ-O-021 | O | Extends: --confirm-destructive is a stronger opt-in variant for destructive confirmation |
| REQ-O-048 | O | Composes: a command whose confirm_flag is yes previews without --yes instead of prompting |
| REQ-C-036 | C | Specializes: a person-only attestation is the one prompt --yes does not answer |