Skip to content

Protocol v1 envelopes

Protocol v1 is the wire contract for foxctl I/O. Every skill execution, plugin call, job result, and agent message uses the same JSON envelope. Changing it without a spec update breaks hooks, GUI clients, golden tests, and downstream tools.

{
"version": 1,
"status": "ok",
"command": "namespace/verb",
"data": {},
"meta": {
"ts": "2026-05-12T00:00:00Z",
"duration_ms": 153,
"runner": "exec",
"workspace": "/path/to/workspace",
"job_id": "01H...",
"trace_id": "uuid-or-ulid",
"profiles": ["core/v1"],
"source": "run",
"cas_digest": "sha256:...",
"skill_version": "1.0.0",
"cache_key": "sha256:..."
},
"error": {
"code": null,
"message": null,
"details": {}
}
}

Protocol version. MUST be 1 for Protocol v1.

Tri-state status: ok, error, or progress. See Status rules below.

Command identifier following the pattern namespace/verb (e.g., http/openapi, fs/ls, code/semantic_search). Must match ^[a-z0-9][a-z0-9-]*/[a-z0-9][a-z0-9-]*$.

Command-specific payload. Large outputs exceeding the inline threshold (default 32KB) MUST be artifactized. See Artifactization below.

Execution metadata:

FieldTypeDescription
tsstringRFC3339 UTC timestamp. MUST be present.
duration_msintegerTotal wall time in milliseconds. MUST be ≥ 0.
runnerstringExecution environment: wasi, exec, oci, or null
workspacestringSanitized absolute path to workspace
job_idstringULID for async jobs
trace_idstringOptional distributed tracing correlation ID
profilesarrayActive profiles (e.g., ["core/v1"], ["core/v1", "agent/v1"])
sourcestringHow result was obtained: run, cache, or memory
cas_digeststringOptional; if set MUST match data.artifact
skill_versionstringVersion of the skill that produced the result
cache_keystringCache key on cache hits
seqintegerStreaming only: sequence number starting at 0
finalbooleanStreaming only: marks last progress event

Error information. Present even for ok status, but with null values:

FieldTypeDescription
codestringStandardized error code from the catalog
messagestringHuman-readable description
detailsobjectOptional machine-readable error context
StatusMeaningRequirements
okTerminal successerror.code and error.message SHOULD be null
errorTerminal failureerror.code and error.message are required
progressNon-terminal progress updateInclude meta.seq (integer, starting at 0, monotonically increasing)

Streaming uses NDJSON (newline-delimited JSON):

  • Each line is a complete JSON envelope
  • Zero or more progress events, then exactly one terminal ok or error envelope
  • Lines separated by \n

Progress events keep payloads small and never include secrets.

When a skill produces output exceeding the inline threshold (default 32KB), the payload moves to CAS and the envelope returns a summary plus an artifact digest:

{
"status": "ok",
"command": "http/openapi",
"data": {
"summary": {
"status_code": 200,
"kind": "application/json",
"size_bytes": 1048576,
"record_count": 247,
"preview": {
"first_keys": ["id", "name"],
"sample_record": { "id": 123, "name": "example" }
},
"pagination": {
"has_more": false,
"total_pages": 3,
"total_items": 247,
"strategy_used": "link"
}
},
"artifact": "sha256:abc123..."
}
}

Every artifactized summary MUST include:

  • size_bytes — Total size of artifactized content
  • kind — MIME type or content description
  • preview — Bounded, deterministic sample (first N keys, first record)

For HTTP responses, summaries SHOULD also include status_code, headers, and pagination metadata. For arrays, include record_count and preview samples.

  • Keep previews under 1KB
  • Use deterministic sampling (first N items, not random)
  • Never include sensitive data in previews

All client-visible errors use standardized codes:

CodeMeaningCaller remediation
EARGInvalid or missing parametersFix inputs; see error.details or data.hint
EAUTHAuthentication failed or credentials missingProvide or refresh credentials
ERATELIMIT429 after retry budget exhaustedWait until reset; lower request rate
EPAGINATIONAuto-detection failed; plugin or fields requiredProvide paging config or plugin
ERUNTIMETransport, server, or IO errorsRetry later; check network/server
ENOTFOUNDResource, memory, or spec not foundFix resource references
ETIMEOUTOperation timed outIncrease timeout or reduce payload
EPOLICYWorkspace, path, or network policy violationNarrow request; fix policy config
ESKILLDOWNCircuit breaker or disabled skillBackoff; re-enable when healthy
EPARSEJSON parse error or invalid UTF-8Fix malformed input
EOUTPUT_TOO_LARGEOutput exceeded capture limitReduce output or increase limit
EENVELOPEInvalid or malformed envelopeFix envelope structure
EIOFilesystem or IO errorCheck permissions or disk space
ECANCELEDJob canceled by userUser-initiated cancellation
EOPENAPISpec invalid or operationId missingValidate spec; pick valid operationId
{
"version": 1,
"status": "error",
"command": "http/openapi",
"data": {
"hint": "Missing required parameter 'username'. Expected in path parameters.",
"issue": "parameter_validation_failed"
},
"meta": {
"ts": "2026-05-12T12:34:56Z",
"duration_ms": 42,
"source": "run"
},
"error": {
"code": "EARG",
"message": "Invalid arguments: missing required path parameter 'username'",
"details": {
"missing_params": ["username"],
"expected_in": "path"
}
}
}

All client-visible retry decisions include:

  • Number of attempts in error.details.attempts
  • Backoff strategy in error.details.backoff
  • Retry-After header value in error.details.retry_after
NamespaceCommandsProfile
Skill commandshttp/openapi, fs/ls, fs/read, text/grep, todo/manageCore v1
Plugin protocolplugin/auth, plugin/paginationPlugin v1
Jobsjobs/submit, jobs/tail, jobs/info, jobs/cancelCore v1
Agentagent/spawn, agent/restart, agent/kill, agent/send, agent/watchAgent v1
Blackboardbb/post, bb/watch, bb/search, bb/claim, bb/releaseAgent v1
  • Commands follow pattern: namespace/verb[-noun]
  • Namespace and verb are lowercase alphanumeric with hyphens
  • New verbs MAY be added without altering envelope shape
  • Custom skills MAY define their own commands following the pattern
  • Current version: version: 1 (Core v1)
  • Breaking changes require a major version bump
  • Backward-compatible changes MAY add optional fields
  • Profiles are additive capability sets declared in meta.profiles

Available profiles:

  • core/v1 — Base protocol
  • agent/v1 — Multi-agent extensions (mailbox, blackboard, quotas)
RuleEnforcement
Secrets redactionMUST redact secrets in data, meta, logs, dry-run outputs, and error messages as "***"
Workspace confinementPathValidator gates every file access; canonical absolute paths only
Network policiesSkill manifests declare capabilities.network; default is network: "none"
Output limitsInline output threshold (default 32KB), max capture size (default 1024KB)
WASI isolationWASI skills MUST NOT have network access in Core v1
  • Do not change meta.* fields without a spec update.
  • Do not write logs to stdout from skills — stdout is envelopes only, stderr is logs only.
  • Preserve deterministic ordering in golden outputs.
  • Prefer the stricter Protocol v1 inline-size guidance when docs disagree.
  • Use data.hint to help callers fix problems on error envelopes.
Terminal window
# Validate envelope against schema and invariants
foxctl proto validate --input envelope.json
# Validate that command outputs conform
foxctl run fs/ls --path . | foxctl proto validate
# Strict mode
foxctl proto validate --input envelope.json --strict

Golden fixtures live in test/golden/:

  • ok-inline.json — Successful inline response
  • ok-cas.json — Successful CAS-artifactized response
  • error-*.json — Various error scenarios
  • progress-stream.ndjson — Streaming progress example