REQ-C-022: Async Commands Declare Job Descriptor Schema
Tier: Command Contract | Priority: P0
Source: §49 Async Job / Polling Protocol Absence
Addresses: Severity: High / Token Spend: High / Time: High / Context: Medium
Description
Any command that initiates an asynchronous operation (one that does not complete before the process exits) MUST declare async: true in its registration metadata and MUST return a typed job descriptor in data. The job descriptor MUST include: job_id, status (running|complete|failed|cancelled), terminal (boolean), status_command (exact invocation to check status), cancel_command (exact invocation to cancel), poll_interval_ms, and timeout_ms. The framework auto-generates job status <id> and job cancel <id> subcommands for all registered async commands.
Acceptance Criteria
- An async command's
--schemaoutput includesasync: trueand the job descriptor schema - The job descriptor returned at invocation time includes all required fields
tool job status <id>exits 0 for complete, 3 for still-running, 4 for failed, 5 for not-found- Attempting to register an async command without a job descriptor schema raises a framework error
Schema
Types: manifest-response.md · response-envelope.md
Async commands extend CommandEntry with:
| Field | Type | Description |
|---|---|---|
async |
boolean (true) |
Marks the command as asynchronous |
job_descriptor_schema |
JSON Schema object | Schema for the job descriptor object returned in ResponseEnvelope.data |
The data field of the initial response conforms to:
| Field | Type | Required | Description |
|---|---|---|---|
job_id |
string | yes | Stable identifier for this job instance |
status |
"running" | "complete" | "failed" | "cancelled" |
yes | Current job state |
terminal |
boolean | yes | true when status is complete, failed, or cancelled |
status_command |
string | yes | Exact invocation to check current status |
cancel_command |
string | yes | Exact invocation to cancel this job |
poll_interval_ms |
integer | yes | Recommended interval between status polls |
timeout_ms |
integer | yes | Time after which the job is considered failed |
Wire Format
$ tool build --schema
{
"async": true,
"parameters": {
"target": { "type": "string", "required": true, "description": "Build target name" }
},
"job_descriptor_schema": {
"type": "object",
"required": ["job_id", "status", "terminal", "status_command", "cancel_command", "poll_interval_ms", "timeout_ms"],
"properties": {
"job_id": { "type": "string" },
"status": { "type": "string", "enum": ["running", "complete", "failed", "cancelled"] },
"terminal": { "type": "boolean" },
"status_command": { "type": "string" },
"cancel_command": { "type": "string" },
"poll_interval_ms":{ "type": "integer" },
"timeout_ms": { "type": "integer" }
}
},
"exit_codes": {
"0": { "name": "SUCCESS", "description": "Job accepted and started", "retryable": false, "side_effects": "partial" }
}
}
Initial response when the command is invoked:
{
"ok": true,
"data": {
"job_id": "build-7f3a",
"status": "running",
"terminal": false,
"status_command": "tool job status build-7f3a",
"cancel_command": "tool job cancel build-7f3a",
"poll_interval_ms": 5000,
"timeout_ms": 600000
},
"error": null,
"warnings": [],
"meta": { "duration_ms": 22 }
}
Example
register command "build":
async: true
job_descriptor_schema:
type: object
required: [job_id, status, terminal, status_command, cancel_command, poll_interval_ms, timeout_ms]
properties:
job_id: { type: string }
status: { type: string, enum: [running, complete, failed, cancelled] }
terminal: { type: boolean }
status_command: { type: string }
cancel_command: { type: string }
poll_interval_ms: { type: integer }
timeout_ms: { type: integer }
parameters:
target: type=string, required=true, description="Build target name"
# framework auto-generates: tool job status <id> and tool job cancel <id>
Related
| Requirement | Tier | Relationship |
|---|---|---|
| REQ-F-049 | F | Enforces: async handler contract that commands with async: true must implement |
| REQ-C-015 | C | Composes: async flag and job_descriptor_schema are part of the --schema output |
| REQ-C-001 | C | Composes: exit codes for job status subcommand are declared alongside the async command |
| REQ-F-004 | F | Wraps: job descriptor is returned as ResponseEnvelope.data |