跳转至

CapOwn Client CLI Contract

Purpose

The capown client CLI is designed primarily for AI agents. Human operators may use it, but the interface should optimize for agent correctness, low ambiguity, and low token cost.

This document defines the output and argument contract for capown. It is more specific than the product overview and architecture documents because it governs the exact interface an agent reads and writes.

Design Principles

Explicit Inputs

Commands must include the context needed to execute or query an operation. Do not hide important routing decisions behind remembered state.

The <worker> argument accepts an exact worker_id (format wrk_*) or an exact owned worker_name. The CLI resolves worker_name to worker_id via GET /api/workers before dispatching - this is a client-side convenience, not an API feature. The dispatch API (target_worker) always expects a canonical worker_id.

Examples:

capown run <worker> <command>
capown read <worker> <path>
capown write <worker> <path> --stdin
capown task <worker> <task_id>

Task IDs are worker-local. The Master does not persist task history. Store both the worker and task_id from dispatch responses. Passing the wrong worker returns a not-found style error.

Structured Data Uses JSON

Use JSON when the result is naturally structured data: lists, records, status objects, capability sets, or task lifecycle data.

Examples:

  • capown workers
  • capown info <worker>
  • capown task <worker> <task_id>

JSON output should be compact and machine-parseable. Do not include fields that are empty, null, or already known from the command unless they are useful for the next agent action.

Raw Data Stays Raw

Do not wrap unstructured payloads in JSON just because the CLI is used by an agent. If the requested result is raw text, return raw text.

Examples:

  • capown run <worker> <command> returns the worker command output.
  • capown read <worker> <path> returns the file content.

The client must not split, summarize, reinterpret, or auto-parse raw output. The agent already has the command context and can decide how to interpret the text.

Do Not Echo Inputs

Responses should describe results, not repeat request payloads.

Do not return:

  • the shell command sent by capown run
  • the file content sent by capown write
  • the full request body
  • full task params

This avoids wasting tokens and avoids accidentally duplicating sensitive or very large input content. Returning the target worker or task id is acceptable when it helps the agent perform the next step.

Minimal CapOwn Errors

CapOwn-layer failures should be short and clearly distinguishable from worker execution output.

Recommended format:

error[<error_code>]: <message>

Examples:

error[worker_offline]: worker is offline
error[auth_denied]: authentication failed
error[schema_invalid]: provide content via --stdin or --file

These errors mean CapOwn failed to route, authenticate, validate, or retrieve a worker response. They are different from command failures inside the target worker environment.

Worker Results Are Not CapOwn Errors

If a worker receives and executes a command, the result belongs to the target environment. The client should return that result directly, even when the remote command exits non-zero.

Example:

Exit code: 1
command not found: foo

This is not a worker_offline or schema_invalid error. It means the task reached the worker and the target environment reported failure.

Output Shape Markers

Every command's help text includes a shape marker that tells the agent what kind of output to expect:

Marker Meaning
[json] Structured result as JSON on stdout
[raw] Unstructured text on stdout (pass-through)
[text] Short acknowledgement text on stdout (not JSON, not raw data)
[raw + stderr status] Raw output on stdout, status/metadata on stderr

Command Output Contract

capown workers[json]

Structured data. Return JSON.

Normal exit code: 0. CapOwn errors exit 1.

Recommended shape:

[
  {
    "worker_name": "worker-1",
    "status": "online",
    "capabilities": ["shell.run", "file.read", "task.status"],
    "mode": "container",
    "workspace": "/workspace"
  }
]

Results are ordered by registration time (oldest first), matching the GET /api/workers API response order.

capown info <worker>[raw/json]

Structured host information. Return JSON if the worker provides structured fields. If the worker only provides plain text, return that text until the worker protocol is upgraded.

capown run <worker> <command>[raw]

Unstructured command output. Return raw worker output.

Do not include the command string in the response.

Soft-timeout running response: When the command does not complete within soft_timeout (default 30s), the Master returns a running status instead of blocking. The client prints task identity and hint to stderr:

task_id: abc123
status: running
output_size: 1024
error_size: 0
hint: Task is still running. To check progress later: capown task wrk_a1b2c3d4e5f6 abc123. To wait longer for the final result: capown wait wrk_a1b2c3d4e5f6 abc123

If a preview is available it is printed to stdout. The exit code is 0. The agent may use capown task <worker> <task_id> to check progress at any time, or capown wait <worker> <task_id> --timeout <seconds> to block until the task finishes (or the wait timeout expires).

Under the hood the CLI resolves worker_name to the canonical worker_id before dispatching. Hints and follow-up commands always use the resolved worker_id. Direct API users should always pass a worker_id.

capown read <worker> <path>[raw]

Unstructured file content. Return raw file content.

Do not wrap file content in JSON by default.

capown write <worker> <path> --stdin / --file <local>[text]

Action acknowledgement. Return a short result, not the input content.

Provide content via:

  • --stdin: pipe or redirect content to stdin
  • --file <local-path>: read content from a local file

Exactly one input source is required. Providing both or neither is a schema error (exit 2).

Recommended response shape:

ok: written 58291 bytes

Path may be included if useful:

ok: written 58291 bytes to article.md

Do not echo <content>.

capown edit <worker> <path> --old-file <local> --new-file <local> / --json-stdin[text]

Exact string replacement in a remote file. Two input modes:

  1. File mode: --old-file <local-path> --new-file <local-path> — read replacement text from local files. Both must be provided together.
  2. JSON stdin mode: --json-stdin — provide a JSON payload on stdin:
    {"old": "...", "new": "...", "expected_hash": "", "dry_run": false}
    

Mixed modes (e.g. --old-file + --json-stdin) are rejected. Providing neither mode is a schema error.

Existing flags --expected-hash and --dry-run still work. When used with --json-stdin, values from JSON override these flags.

Recommended response:

ok: replaced 1 occurrence in article.md

capown ls <worker> <path> --limit <n>[raw/json]

Directory listings are structured in principle. Prefer JSON once the worker returns structured entries. Until then, returning the raw listing text is acceptable.

--limit caps the maximum entries returned (default: 500). The worker enforces this limit.

If the result is truncated due to the limit, output includes a truncation indicator.

Recommended future shape:

[
  {"name": "src", "type": "dir"},
  {"name": "README.md", "type": "file", "size": 1234}
]

capown dispatch <worker> <command>[text]

Action acknowledgement with fields needed for the next command. Return compact structured text. Do not echo the command.

Recommended minimal text:

ok: dispatched
worker: worker-1
task_id: abc123

capown task <worker> <task_id>[json]

Structured task state. Return JSON.

Task IDs are worker-local. The Master does not persist task history. Store both worker and task_id from the dispatch response.

Recommended shape:

{
  "task_id": "abc123",
  "status": "running",
  "task_type": "shell",
  "updated_at": "2026-07-03T00:00:00+00:00",
  "output_size": 0,
  "error_size": 0,
  "truncated": false
}

Task status may include previews, but previews must be capped. Do not include full command input, full file content, or full request params.

capown cancel <worker> <task_id>[text]

Action confirmation. Terminates a running task on the target worker.

ok: canceled abc123

capown wait <worker> <task_id> --timeout <seconds>[raw + stderr status]

Wait for an existing task to finish. Default timeout is 300s.

On completion: prints the final output to stdout and status to stderr. If the wait timeout expires while the task is still running, prints the same running response as capown run (task_id, status, hint to stderr, preview to stdout).

capown pending [--worker <id>] [--limit <n>][json]

Cluster-wide discovery of pending/running tasks. Queries all online owned workers in real time and returns aggregated task summaries as JSON:

[{"_worker_id":"worker-1","task_id":"abc","status":"running",...}]

Use --worker to filter to a single worker. Master does not persist task data — this is a real-time fan-out only.

capown task-command <worker> <task_id>[raw]

Retrieve the stored full shell command for a completed shell task. Raw command text is printed to stdout. When the command was truncated during storage, truncated: true and command_size are printed to stderr.

echo hello

Truncated output:

echo very_lo...
# stderr:
truncated: true
command_size: 99999

Errors:

  • task_not_found — unknown or expired task id.
  • execution_failed — task is not a shell task, or command history is disabled for this Worker.
  • schema_invalid — missing or non-string task_id.

capown history <worker> [--limit <n>] [--all-statuses] [--preview-bytes <n>][json]

List recent task summaries from one Worker, defaulting to shell tasks only. Returns JSON summaries with input metadata previews. Full command text is never included.

Default --limit is 10. Default statuses are completed, failed, timeout, canceled, pending, and running.

Without --all-statuses, only shell tasks are returned. With --all-statuses, all task types are included.

Each summary includes:

{
  "task_id": "abc123",
  "status": "completed",
  "task_type": "shell",
  "input_preview": "echo hello",
  "input_size": 10,
  "input_truncated": false,
  "input_available": true
}

Exit Codes

Exit code Meaning
0 Success
1 CapOwn routing/auth/transport error, or worker command failure
2 Schema validation error (invalid args, missing required flags)

CapOwn-layer errors are printed to stderr as error[code]: message. Worker command failures may print worker output to stdout and exit nonzero.

Compatibility

The following old command forms are removed:

- capown write <worker> <path> <content>
- capown edit <worker> <path> --old <t> --new <t>
- capown command <worker> <task_id>

Replace with:

capown write <worker> <path> --stdin
capown write <worker> <path> --file <local>
capown edit <worker> <path> --old-file <local> --new-file <local>
capown edit <worker> <path> --json-stdin
capown task-command <worker> <task_id>

Summary

CapOwn client output should be precise, compact, and shaped by the data:

  • Structured results use JSON.
  • Raw command and file outputs stay raw.
  • CapOwn-layer errors use error[code]: message.
  • Responses do not echo input payloads.
  • Commands require explicit worker context.
  • Task IDs are worker-local; the Master does not persist task history.
  • Schema errors exit 2; routing/auth/transport errors exit 1.
  • Every command help text includes an output shape marker ([json], [raw], [text]).