skip to content
$worker

shell

v0.3.6

Unix shell + filesystem worker — exec with denylist/timeout/output caps and background jobs; fs::ls|stat|mkdir|rm|chmod|mv|grep|sed|read|write with host jail, denylist, size caps, and sandbox-target forwarding

iiiverified
406 installs112 in 7d29 today
install
$iii worker add shell@0.3.6
  • macOS: arm64 · x64
  • Linux: arm64 · armv7 · x64

exact versions are immutable; binary and bundle artifacts are digest-pinned.

agent-ready brief for v0.3.6
install + config + dependencies + readme + api reference, all in one place. fetch as agent-context.md for an llm to consume.
the same content rendered as discrete blocks below is exposed as a single markdown document at /workers/shell.md?version=0.3.6. paste it into an llm prompt or pipe it through curl from a worker.

install

install
$iii worker add shell@0.3.6

configuration

iii-config.yaml
- allowed_env:
    - PATH
    - HOME
    - LANG
    - LC_ALL
    - TERM
  allowlist:
    - ls
    - cat
    - pwd
    - echo
    - grep
    - wc
    - head
    - tail
    - sort
    - uniq
    - cut
    - date
    - whoami
    - hostname
    - which
    - jq
    - uname
    - df
    - du
    - ps
    - printenv
    - basename
    - dirname
  default_timeout_ms: 10000
  denylist_patterns:
    - rm\s+-rf\s+/
    - :\(\)\s*\{\s*:\|
    - mkfs
    - dd\s+if=
    - shutdown
    - reboot
    - /etc/passwd
    - /etc/shadow
    - \bfind\b[^|;&]*-exec(dir)?\b
    - \bawk\b[^|;&]*system\s*\(
    - \bsed\b[^|;&]*(-i\b|\be\b)
    - \bcurl\b[^|;&]*(file://|-o\s|--output-dir\b|-F\s+@)
    - \bgit\b[^|;&]*(--upload-pack|--receive-pack|core\.pager|core\.hooksPath|GIT_SSH_COMMAND)
    - \b(node|python3?)\b[^|;&]*\s-(e|c)\b
    - \bnpm\b[^|;&]*\brun\b
  fs:
    allow_unjailed: false
    denylist_paths:
      - /etc/passwd
      - /etc/shadow
    host_root: /tmp
    max_read_bytes: 16777216
    max_write_bytes: 16777216
  inherit_env: false
  job_retention_secs: 3600
  max_concurrent_jobs: 16
  max_output_bytes: 1048576
  max_timeout_ms: 30000
  sandbox:
    enabled: true
  working_dir: null

dependencies

no dependencies for v0.3.6

readme

README.md

shell

Run allowlisted Unix commands, background jobs, and structured filesystem operations from the iii engine, on the host or forwarded into a sandbox microVM.

Install

iii worker add shell

Sandbox-targeted execution and shell::fs::* forwarding need the iii-sandbox worker; iii worker add shell does not pull it in. To surface shell::* to LLM agents, pair with iii-directory:

iii worker add iii-sandbox
iii worker add iii-directory

Configure

Settings load from a YAML file passed with --config (default ./config.yaml). The worker refuses to start unless fs.host_root is set, or fs.allow_unjailed: true is explicitly opted in, because an unset root exposes the whole host filesystem behind only the advisory denylist.

max_timeout_ms: 30000        # hard cap; per-call timeout_ms is clamped to this
default_timeout_ms: 10000    # applied when the caller omits timeout_ms
max_output_bytes: 1048576    # 1 MiB; stdout/stderr past this set *_truncated
inherit_env: false           # when false, only allowed_env keys are forwarded
allowed_env: [PATH, HOME, LANG, LC_ALL, TERM]

# exec gate. argv[0] is matched by basename or exact path; an empty
# allowlist means open. denylist_patterns are advisory regex over
# argv.join(" "), a tripwire for honest mistakes only.
allowlist: [ls, cat, pwd, echo, grep, wc, head, tail, sort, uniq, cut, date]
denylist_patterns:
  - "rm\\s+-rf\\s+/"
  - "mkfs"

max_concurrent_jobs: 16      # exec_bg past this is rejected
job_retention_secs: 3600     # finished jobs pruned after this

fs:
  host_root: /tmp            # jail root for shell::fs::*; required (see above)
  allow_unjailed: false      # opt-in to running with host_root unset
  max_read_bytes: 16777216   # 0 = unlimited
  max_write_bytes: 16777216  # 0 = unlimited
  denylist_paths: [/etc/passwd, /etc/shadow]

sandbox:
  enabled: true              # false -> every target: sandbox call returns S210

Host shell::exec is not a security boundary: any allowlisted interpreter (sh, node, python3) can construct a denylisted token at runtime and bypass the regex. Run untrusted input with target: { kind: "sandbox", sandbox_id }, which forwards through the iii-sandbox microVM. The allowlist and denylist still apply on top of either backend.

Quick start

import { registerWorker } from 'iii-sdk'

const iii = registerWorker(process.env.III_URL ?? 'ws://127.0.0.1:49134')

const result = await iii.trigger({
  function_id: 'shell::exec',
  payload: { command: 'echo', args: ['hello'] },
})

console.log(result)

The example runs on the host. The same payload retargets at a microVM with target: { kind: 'sandbox', sandbox_id: '' }. The other entry points are shell::exec_bg, shell::status, shell::kill, shell::list, plus the shell::fs::* family (ls, stat, read, write, grep, sed, mkdir, rm, chmod, mv).

Functions

Function Purpose
shell::exec Run an allowlisted command in the foreground; returns stdout, stderr, exit code, and timing. Blocks until exit or timeout.
shell::exec_bg Spawn an allowlisted command as a background job; returns { job_id, argv } immediately. Host-targeted jobs ignore timeout_ms (end via shell::kill or natural exit); sandbox jobs honor it.
shell::status Fetch one job's full record: state, exit code, and captured stdout/stderr. not_found means the id never existed or aged out past job_retention_secs.
shell::list Enumerate current jobs as lightweight summaries; argv, stdout, and stderr are redacted.
shell::kill Terminate a running background job by job_id. Sandbox jobs cannot be hard-killed: the record flips to killed but the in-VM process runs until its timeout_ms (or sandbox::stop).
shell::fs::ls List a directory's entries with structured metadata.
shell::fs::stat Read one path's metadata (size, mode, symlink flag).
shell::fs::mkdir Create a directory, optionally with missing parents.
shell::fs::rm Remove a file or directory, optionally recursive.
shell::fs::chmod Change a path's mode, and optionally its uid/gid.
shell::fs::mv Rename or move one path within the jail.
shell::fs::grep Recursive regex search across a tree; returns structured matches. Keys are singular include_glob/exclude_glob; the case flag is ignore_case.
shell::fs::sed Regex find-and-replace across one file or many.
shell::fs::write Stream bytes into a file through an SDK channel; writes via a temp file and renames atomically. No inline content field.
shell::fs::read Stream a file's bytes out through an SDK channel. For an inline read on the web surface, use the harness::fs::read_inline wrapper instead.

Every shell::fs::* call accepts the same optional target as exec, so host and sandbox share one wire shape.

Errors

Returned error bodies carry a stable code field. Allowlist and denylist rejections come back as a plain message (command '' not in allowlist, command matches denylist: ) rather than an S-code.

Code Meaning
S200 In-VM execution failure on a sandbox target.
S210 Invalid request: non-absolute path, empty command or pattern, bad octal mode, malformed payload, or sandbox.enabled: false on a sandbox-targeted call.
S211 Path not found.
S212 Wrong file type for the operation (for example, a file where a directory was expected).
S213 Path already exists.
S214 Directory not empty (non-recursive rm).
S215 Path escapes host_root, hits fs.denylist_paths, or permission denied.
S216 Generic shell-internal failure: host spawn error, channel error, or a bad engine response.
S217 Invalid regex passed to grep/sed.
S218 fs.max_read_bytes / fs.max_write_bytes cap exceeded.
S300 Sandbox VM boot failed (needs a virtualization host: Apple Silicon or /dev/kvm).

Troubleshooting

  • fs.host_root is unset ... refusing to start unjailed: set fs.host_root to a directory, or set fs.allow_unjailed: true.
  • command '' not in allowlist: the basename of argv[0] is not in a non-empty allowlist. Add it, or empty the list to allow anything.
  • S215 path escapes host_root on a path inside the jail: a symlink in the path resolves outside the jail. Resolve it yourself, or move the target inside host_root.
  • S300 on a sandbox target: the host cannot boot microVMs. Sandbox execution requires Apple Silicon or /dev/kvm.
  • Worker never connects: the engine is not running or not bound on the configured --url. Start the engine first; the default WebSocket port is 49134.

For the threat model, streaming wire shapes, and contributor build steps, see ARCHITECTURE.md.

License

Apache 2.0 — see LICENSE.

api reference (json)

agent-api-reference.json
{
  "functions": [
    {
      "description": "Stat a path on host or sandbox",
      "metadata": {},
      "name": "shell::fs::stat",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "AnyValue"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "is_dir": {
            "type": "boolean"
          },
          "is_symlink": {
            "type": "boolean"
          },
          "mode": {
            "type": "string"
          },
          "mtime": {
            "format": "int64",
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "size": {
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "is_dir",
          "is_symlink",
          "mode",
          "mtime",
          "name",
          "size"
        ],
        "title": "FsEntry",
        "type": "object"
      }
    },
    {
      "description": "Find-and-replace on host or sandbox",
      "metadata": {},
      "name": "shell::fs::sed",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "AnyValue"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "FsSedFileResult": {
            "properties": {
              "error": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "path": {
                "type": "string"
              },
              "replacements": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "success": {
                "type": "boolean"
              }
            },
            "required": [
              "path",
              "replacements",
              "success"
            ],
            "type": "object"
          }
        },
        "properties": {
          "results": {
            "items": {
              "$ref": "#/definitions/FsSedFileResult"
            },
            "type": "array"
          },
          "total_replacements": {
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "results",
          "total_replacements"
        ],
        "title": "SedResponse",
        "type": "object"
      }
    },
    {
      "description": "Kill a running background job",
      "metadata": {},
      "name": "shell::kill",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "job_id": {
            "type": "string"
          }
        },
        "required": [
          "job_id"
        ],
        "title": "KillRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "JobStatus": {
            "enum": [
              "running",
              "finished",
              "killed",
              "failed"
            ],
            "type": "string"
          }
        },
        "properties": {
          "job_id": {
            "type": "string"
          },
          "killed": {
            "type": "boolean"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "$ref": "#/definitions/JobStatus"
          }
        },
        "required": [
          "job_id",
          "killed",
          "status"
        ],
        "title": "KillResponse",
        "type": "object"
      }
    },
    {
      "description": "Stream a file to a host path or sandbox via StreamChannelRef",
      "metadata": {},
      "name": "shell::fs::write",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "AnyValue"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "bytes_written": {
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          },
          "path": {
            "type": "string"
          }
        },
        "required": [
          "bytes_written",
          "path"
        ],
        "title": "WriteResponse",
        "type": "object"
      }
    },
    {
      "description": "Spawn an allowlisted command as a background job. Same payload shape as shell::exec; returns { job_id, argv } immediately. Poll with shell::status, terminate with shell::kill, list with shell::list. Do NOT pass argv as an array in 'command' — use 'command' (string) + 'args' (string[]).",
      "metadata": {},
      "name": "shell::exec_bg",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "Target": {
            "oneOf": [
              {
                "properties": {
                  "kind": {
                    "enum": [
                      "host"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "kind"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "kind": {
                    "enum": [
                      "sandbox"
                    ],
                    "type": "string"
                  },
                  "sandbox_id": {
                    "format": "uuid",
                    "type": "string"
                  }
                },
                "required": [
                  "kind",
                  "sandbox_id"
                ],
                "type": "object"
              }
            ]
          }
        },
        "description": "Wire request for `shell::exec_bg`. Same shape as [`ExecRequest`]; documented separately so the engine publishes a distinct schema per function.",
        "properties": {
          "args": {
            "default": null,
            "description": "Arguments passed to the program. See [`ExecRequest::args`]. `None` (or `args: null` / absent) means \"tokenize `command` via shell-words\"; `Some(_)` (including the empty vec) means \"use args verbatim, no shell-words.\" See `parse_argv` in `crate::exec::host`.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "command": {
            "description": "Program name. See [`ExecRequest::command`].",
            "type": "string"
          },
          "target": {
            "allOf": [
              {
                "$ref": "#/definitions/Target"
              }
            ],
            "default": {
              "kind": "host"
            },
            "description": "Where to run. See [`ExecRequest::target`]."
          },
          "timeout_ms": {
            "default": null,
            "description": "Per-call timeout. Host-targeted background jobs IGNORE `timeout_ms`; sandbox-targeted ones forward it through `cfg.resolve_timeout`.",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "command"
        ],
        "title": "ExecBgRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "argv": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "job_id": {
            "type": "string"
          }
        },
        "required": [
          "argv",
          "job_id"
        ],
        "title": "ExecBgResponse",
        "type": "object"
      }
    },
    {
      "description": "Recursive regex search on host or sandbox",
      "metadata": {},
      "name": "shell::fs::grep",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "AnyValue"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "FsMatch": {
            "properties": {
              "content": {
                "type": "string"
              },
              "line": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "path": {
                "type": "string"
              }
            },
            "required": [
              "content",
              "line",
              "path"
            ],
            "type": "object"
          }
        },
        "properties": {
          "matches": {
            "items": {
              "$ref": "#/definitions/FsMatch"
            },
            "type": "array"
          },
          "truncated": {
            "type": "boolean"
          }
        },
        "required": [
          "matches",
          "truncated"
        ],
        "title": "GrepResponse",
        "type": "object"
      }
    },
    {
      "description": "Remove a path on host or sandbox",
      "metadata": {},
      "name": "shell::fs::rm",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "AnyValue"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "removed": {
            "type": "boolean"
          }
        },
        "required": [
          "removed"
        ],
        "title": "RmResponse",
        "type": "object"
      }
    },
    {
      "description": "Change permissions on host or sandbox",
      "metadata": {},
      "name": "shell::fs::chmod",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "AnyValue"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "updated": {
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "updated"
        ],
        "title": "ChmodResponse",
        "type": "object"
      }
    },
    {
      "description": "Create a directory on host or sandbox",
      "metadata": {},
      "name": "shell::fs::mkdir",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "AnyValue"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "created": {
            "type": "boolean"
          }
        },
        "required": [
          "created"
        ],
        "title": "MkdirResponse",
        "type": "object"
      }
    },
    {
      "description": "Move/rename a path on host or sandbox",
      "metadata": {},
      "name": "shell::fs::mv",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "AnyValue"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "moved": {
            "type": "boolean"
          }
        },
        "required": [
          "moved"
        ],
        "title": "MvResponse",
        "type": "object"
      }
    },
    {
      "description": "Run an allowlisted command in the foreground and return its full output. Payload: { command: string (program name), args?: string[], timeout_ms?: number, target?: { kind: 'host'|'sandbox', sandbox_id?: string } }. Returns { stdout, stderr, exit_code, duration_ms, timed_out, stdout_truncated, stderr_truncated }. Do NOT pass argv as an array in 'command' — split program and arguments across the two fields.",
      "metadata": {},
      "name": "shell::exec",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "Target": {
            "oneOf": [
              {
                "properties": {
                  "kind": {
                    "enum": [
                      "host"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "kind"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "kind": {
                    "enum": [
                      "sandbox"
                    ],
                    "type": "string"
                  },
                  "sandbox_id": {
                    "format": "uuid",
                    "type": "string"
                  }
                },
                "required": [
                  "kind",
                  "sandbox_id"
                ],
                "type": "object"
              }
            ]
          }
        },
        "description": "Wire request for `shell::exec`. The schema is published to the engine's tool listing so callers see field types up front instead of guessing from the description.",
        "properties": {
          "args": {
            "default": null,
            "description": "Arguments passed to the program, in order. Every element must be a string; non-string elements are rejected by index. `None` (or `args: null` / absent) means \"tokenize `command` via shell-words\"; `Some(_)` (including the empty vec) means \"use args verbatim, no shell-words.\" See `parse_argv` in `crate::exec::host`.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "command": {
            "description": "Program name (matched against the allowlist by basename or exact path). Must be a string — split arguments into `args`, do not pass argv as an array here.",
            "type": "string"
          },
          "target": {
            "allOf": [
              {
                "$ref": "#/definitions/Target"
              }
            ],
            "default": {
              "kind": "host"
            },
            "description": "Where to run the command. Defaults to the host worker; pass `{ kind: \"sandbox\", sandbox_id }` to forward the call to a microVM."
          },
          "timeout_ms": {
            "default": null,
            "description": "Per-call timeout override, milliseconds. Capped at `cfg.max_timeout_ms`. Negative or fractional values silently fall back to `cfg.default_timeout_ms` (loose wire semantic, preserved on purpose).",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "command"
        ],
        "title": "ExecRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "duration_ms": {
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          },
          "exit_code": {
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          },
          "stderr": {
            "type": "string"
          },
          "stderr_truncated": {
            "type": "boolean"
          },
          "stdout": {
            "type": "string"
          },
          "stdout_truncated": {
            "type": "boolean"
          },
          "timed_out": {
            "type": "boolean"
          }
        },
        "required": [
          "duration_ms",
          "stderr",
          "stderr_truncated",
          "stdout",
          "stdout_truncated",
          "timed_out"
        ],
        "title": "ExecResponse",
        "type": "object"
      }
    },
    {
      "description": "List all background jobs",
      "metadata": {},
      "name": "shell::list",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "AnyValue"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "JobStatus": {
            "enum": [
              "running",
              "finished",
              "killed",
              "failed"
            ],
            "type": "string"
          },
          "JobSummary": {
            "description": "`shell::list` returns one `JobSummary` per record. argv, stdout, and stderr are deliberately omitted: the global JOBS map is process-wide and has no per-caller scope, so any caller could otherwise read every other caller's command line and captured output (which may embed credentials). Full records remain reachable via `shell::status <job_id>` — the random UUID acts as an unguessable capability for that record.",
            "properties": {
              "exit_code": {
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "finished_at_ms": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "id": {
                "type": "string"
              },
              "started_at_ms": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "status": {
                "$ref": "#/definitions/JobStatus"
              },
              "stderr_truncated": {
                "type": "boolean"
              },
              "stdout_truncated": {
                "type": "boolean"
              }
            },
            "required": [
              "id",
              "started_at_ms",
              "status",
              "stderr_truncated",
              "stdout_truncated"
            ],
            "type": "object"
          }
        },
        "properties": {
          "count": {
            "format": "uint",
            "minimum": 0,
            "type": "integer"
          },
          "jobs": {
            "items": {
              "$ref": "#/definitions/JobSummary"
            },
            "type": "array"
          }
        },
        "required": [
          "count",
          "jobs"
        ],
        "title": "ListResponse",
        "type": "object"
      }
    },
    {
      "description": "Get status of a background job",
      "metadata": {},
      "name": "shell::status",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "job_id": {
            "type": "string"
          }
        },
        "required": [
          "job_id"
        ],
        "title": "StatusRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "JobRecord": {
            "properties": {
              "argv": {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "exit_code": {
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "finished_at_ms": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "id": {
                "type": "string"
              },
              "started_at_ms": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "status": {
                "$ref": "#/definitions/JobStatus"
              },
              "stderr": {
                "type": "string"
              },
              "stderr_truncated": {
                "type": "boolean"
              },
              "stdout": {
                "type": "string"
              },
              "stdout_truncated": {
                "type": "boolean"
              }
            },
            "required": [
              "argv",
              "id",
              "started_at_ms",
              "status",
              "stderr",
              "stderr_truncated",
              "stdout",
              "stdout_truncated"
            ],
            "type": "object"
          },
          "JobStatus": {
            "enum": [
              "running",
              "finished",
              "killed",
              "failed"
            ],
            "type": "string"
          }
        },
        "properties": {
          "job": {
            "$ref": "#/definitions/JobRecord"
          }
        },
        "required": [
          "job"
        ],
        "title": "StatusResponse",
        "type": "object"
      }
    },
    {
      "description": "List directory contents on host or sandbox",
      "metadata": {},
      "name": "shell::fs::ls",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "AnyValue"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "FsEntry": {
            "properties": {
              "is_dir": {
                "type": "boolean"
              },
              "is_symlink": {
                "type": "boolean"
              },
              "mode": {
                "type": "string"
              },
              "mtime": {
                "format": "int64",
                "type": "integer"
              },
              "name": {
                "type": "string"
              },
              "size": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "is_dir",
              "is_symlink",
              "mode",
              "mtime",
              "name",
              "size"
            ],
            "type": "object"
          }
        },
        "properties": {
          "entries": {
            "items": {
              "$ref": "#/definitions/FsEntry"
            },
            "type": "array"
          }
        },
        "required": [
          "entries"
        ],
        "title": "LsResponse",
        "type": "object"
      }
    },
    {
      "description": "Stream a file from a host path or sandbox via StreamChannelRef",
      "metadata": {},
      "name": "shell::fs::read",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "AnyValue"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "ContentDirection": {
            "enum": [
              "read",
              "write"
            ],
            "type": "string"
          },
          "ContentRef": {
            "description": "Wire-identical mirror of `iii_sdk::channels::StreamChannelRef`. The SDK type lacks `JsonSchema` in 0.11.3, which would block typed registration of `shell::fs::write`/`read`.",
            "properties": {
              "access_key": {
                "type": "string"
              },
              "channel_id": {
                "type": "string"
              },
              "direction": {
                "allOf": [
                  {
                    "$ref": "#/definitions/ContentDirection"
                  }
                ],
                "default": "read"
              }
            },
            "required": [
              "access_key",
              "channel_id"
            ],
            "type": "object"
          }
        },
        "properties": {
          "content": {
            "$ref": "#/definitions/ContentRef"
          },
          "mode": {
            "type": "string"
          },
          "mtime": {
            "format": "int64",
            "type": "integer"
          },
          "size": {
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "content",
          "mode",
          "mtime",
          "size"
        ],
        "title": "ReadResponseWire",
        "type": "object"
      }
    }
  ],
  "triggers": []
}