REQ-C-023: Editor-Requiring Commands Declare Non-Interactive Alternative
Tier: Command Contract | Priority: P1
Source: §62 $EDITOR and $VISUAL Trap
Addresses: Severity: Critical / Token Spend: High / Time: Critical / Context: Low
Description
Any command that invokes $EDITOR or $VISUAL MUST declare requires_editor: true in its registration metadata AND MUST declare at least one non-interactive alternative flag (e.g., --message <text>, --from-file <path>, --content <text>). The framework verifies this at registration and raises an error if requires_editor: true without a declared alternative. In non-TTY mode, the framework automatically uses the non-interactive alternative; if no value is provided for it, the command exits 4 with the alternative flag listed in the error.
Acceptance Criteria
- A command with
requires_editor: truebut no declared alternative raises a registration error - In non-TTY mode,
git commitequivalent exits 4 withhint: "use --message <text> instead" - Passing
--message "text"in non-TTY mode bypasses the editor and proceeds normally - In TTY mode, the editor is invoked normally when neither alternative flag is provided
Schema
Types: manifest-response.md
Editor-requiring commands extend CommandEntry with:
| Field | Type | Required | Description |
|---|---|---|---|
requires_editor |
boolean (true) |
yes | Marks the command as invoking $EDITOR or $VISUAL when no alternative is supplied |
non_interactive_alternatives |
string[] | yes | Flag names that bypass the editor (e.g. ["message", "from-file"]) |
Wire Format
$ tool commit --schema
{
"requires_editor": true,
"non_interactive_alternatives": ["message", "from-file"],
"parameters": {
"message": { "type": "string", "required": false, "description": "Commit message text; bypasses editor" },
"from-file": { "type": "string", "required": false, "description": "Path to file containing commit message" }
},
"exit_codes": {
"0": { "name": "SUCCESS", "description": "Commit created", "retryable": false, "side_effects": "complete" },
"4": { "name": "NO_TTY", "description": "Editor unavailable in non-TTY mode; use --message", "retryable": true, "side_effects": "none" }
}
}
Example
register command "commit":
requires_editor: true
non_interactive_alternatives: [message, from-file]
parameters:
message: type=string, required=false, description="Commit message text; bypasses editor"
from-file: type=string, required=false, description="Path to file containing commit message"
# tool commit (non-TTY, no --message, no --from-file)
# → exit 4: {"code": "NO_TTY", "message": "Editor not available", "suggestion": "use --message <text> or --from-file <path>"}
# tool commit --message "Fix typo" (non-TTY)
# → exit 0: commit created without editor
# register command "bad-commit":
# requires_editor: true
# (no non_interactive_alternatives)
# → framework error: requires_editor: true requires at least one non_interactive_alternative
Related
| Requirement | Tier | Relationship |
|---|---|---|
| REQ-F-055 | F | Enforces: $EDITOR and $VISUAL are suppressed in non-TTY mode at the framework level |
| REQ-F-009 | F | Provides: non-TTY detection used to enforce the declared non_interactive_alternatives |
| REQ-C-015 | C | Composes: requires_editor and non_interactive_alternatives are part of --schema output |
| REQ-C-024 | C | Specializes: editor invocation is one category of interactive operation with a declared headless fallback |