{
  "$defs": {
    "DiskHealth": {
      "description": "The disk half of [`Health`].",
      "properties": {
        "available_bytes": {
          "description": "Bytes available to an unprivileged writer, from `statvfs` `f_bavail`.",
          "format": "uint64",
          "minimum": 0,
          "type": "integer"
        },
        "reserve_bytes": {
          "description": "Bytes that must stay free before a write is refused. Zero means the guard is\ndisabled.",
          "format": "uint64",
          "minimum": 0,
          "type": "integer"
        },
        "under_pressure": {
          "description": "Whether a write would be refused right now. Precomputed rather than left to\nthe client, so every consumer applies the same comparison the write path does.",
          "type": "boolean"
        }
      },
      "required": [
        "available_bytes",
        "reserve_bytes",
        "under_pressure"
      ],
      "type": "object"
    },
    "ExitEvent": {
      "description": "The terminal `exit` SSE event. Emitted before the stream ends, so a client\nthat sees the body close without one knows the connection failed rather than\nthe command finishing.",
      "properties": {
        "exit_code": {
          "format": "int32",
          "type": [
            "integer",
            "null"
          ]
        },
        "offset": {
          "description": "Total bytes published, so a client can assert it saw all of them.",
          "format": "uint64",
          "minimum": 0,
          "type": "integer"
        },
        "signal": {
          "format": "int32",
          "type": [
            "integer",
            "null"
          ]
        },
        "truncated": {
          "type": "boolean"
        },
        "writers_may_be_alive": {
          "type": "boolean"
        }
      },
      "required": [
        "exit_code",
        "signal",
        "truncated",
        "writers_may_be_alive",
        "offset"
      ],
      "type": "object"
    },
    "FileReadQuery": {
      "description": "Query string for `GET /v1/fs/file`, which is [`FsQuery`] plus an optional line\nrange.\n\nA separate type rather than two more fields on [`FsQuery`], because a line range\nmeans nothing on `PUT /v1/fs/file` or on either tar route and a shared type would\npublish it on all four. `mode` is absent here for the same reason pointing the\nother way: it is a property of a write.\n\nThe semantics are the AI SDK harness contract's, verbatim, because that is the\nconsumer: **1-based and inclusive on both ends**, and an `end_line` past the\nfile's last line reads through EOF without an error. A caller asking for lines\n1..1000 of a 12-line file gets the 12 lines and a 200, not a 416.",
      "properties": {
        "end_line": {
          "default": null,
          "description": "Last line to return, 1-based inclusive. Absent means through EOF.\n\nPast the last line is **not** an error: the read returns through EOF. A range\nending before `start_line` is refused with 400, because it can only be a\ncaller who computed one of the two wrong — there is no file for which it is\nthe right question.",
          "format": "uint64",
          "minimum": 0,
          "type": [
            "integer",
            "null"
          ]
        },
        "path": {
          "type": "string"
        },
        "start_line": {
          "default": null,
          "description": "First line to return, 1-based inclusive. Absent means 1.\n\nZero is refused with 400 rather than treated as 1. A caller who sends 0 is\nworking from a 0-based mental model, and silently reinterpreting it would\nhand back a window one line off from the one they will compute offsets\nagainst.",
          "format": "uint64",
          "minimum": 0,
          "type": [
            "integer",
            "null"
          ]
        }
      },
      "required": [
        "path"
      ],
      "type": "object"
    },
    "FsQuery": {
      "description": "Query string for every route in this module.\n\n`path` is required. A request missing it is 400, never 404: clients map 404\nonto `FileNotFoundError`, so answering 404 for a protocol typo made a missing\nquery key look like an absent artifact — that is how one defect hid for a full\nreview round.",
      "properties": {
        "mode": {
          "default": null,
          "description": "Octal mode for a written file, carried as a string so `0644` and `644`\nboth parse and neither is read as decimal 644.",
          "type": [
            "string",
            "null"
          ]
        },
        "path": {
          "type": "string"
        }
      },
      "required": [
        "path"
      ],
      "type": "object"
    },
    "GapEvent": {
      "description": "One `gap` SSE event: the byte range a lagging or late subscriber lost.",
      "properties": {
        "from": {
          "format": "uint64",
          "minimum": 0,
          "type": "integer"
        },
        "to": {
          "format": "uint64",
          "minimum": 0,
          "type": "integer"
        }
      },
      "required": [
        "from",
        "to"
      ],
      "type": "object"
    },
    "Health": {
      "description": "`GET /v1/health` response.",
      "properties": {
        "bootstrapped": {
          "type": "boolean"
        },
        "busy": {
          "default": false,
          "description": "Whether any exec is still running right now.\n\nHere so that an orchestrator *outside* the VM can decide whether to keep the\nVM alive, and the \"outside\" is the whole design. The platform measures\nidleness by inbound traffic through the endpoint proxy, and that proxy\nterminates outside the guest and forwards over loopback (measured;\n`docs/PLATFORM.md`, \"The platform's own hook arrives over loopback\"). A\nrequest a guest process sends to the daemon's own port never reaches the\nproxy, so no amount of in-guest traffic can reset the idle timer. A route\nthat promised otherwise would be a keepalive that does not keep anything\nalive, discovered when a multi-hour run auto-suspends mid-work.\n\nWhat does reset it is a poll from outside, and this field is what makes such\na poll *informed* rather than unconditional: the orchestrator polls, which is\nitself the inbound traffic, and reads whether the workload is busy to decide\nwhether to keep polling. The assertion is therefore repeated and explicitly\nthe caller's, which is what the daemon self-keepaliving would not be — a hung\nprocess would then bill to the 8-hour ceiling with nobody asking.\n\nComputed from the exec registry rather than remembered: true iff at least one\nregistered exec has not yet published a result. An exec that exited and is\nwaiting to be acked is not busy — its output is being *held*, not produced —\nso an orchestrator does not keep a VM alive for a command that finished.\n\n`#[serde(default)]`, unlike every field above it, and the asymmetry is not an\noversight. The daemon is baked into an image while the client is installed\nseparately, so a current client routinely talks to a daemon from whenever that\nimage was built — and a required field would make `health()` fail outright\nagainst a daemon that predates it, turning a missing signal into an\nunreachable VM. False is also the right absence: a daemon that cannot say\nwhether it is busy has not asserted that it is.",
          "type": "boolean"
        },
        "disk": {
          "anyOf": [
            {
              "$ref": "#/$defs/DiskHealth"
            },
            {
              "type": "null"
            }
          ],
          "description": "Free space on the daemon's working filesystem, and the reserve it is judged\nagainst.\n\nReported so disk pressure is something an orchestrator *watches* rather than\nsomething it discovers from a failed write. anthropics/claude-code#59856\nfilled two 10 GB disks to 100% with never-collected session directories and\nthe first symptom was `useradd: No space left on device` — by which point\nevery writer in the sandbox was already broken. A number on a health endpoint\nis what makes that curve visible while there is still time to act.\n\n`None` when free space could not be measured, which is deliberately distinct\nfrom zero: unmeasurable is not full, and a monitor that conflated them would\npage on a missing `statvfs`."
        },
        "execs": {
          "default": 0,
          "description": "How many execs are registered, in any phase.\n\nAlongside `busy` because the two answer different questions and a monitor\nwants both: `busy: false, execs: 0` is a fresh or drained VM, while\n`busy: false, execs: 7` is a VM holding seven unacked results that somebody\nstill has to collect. Terminating the second loses output nobody read.\n\nDefaulted for the same reason as `busy`: a client routinely talks to a daemon\nbaked into an older image, and zero is the honest reading of a daemon that\ndoes not report a count.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "hooks": {
          "default": [],
          "description": "Every lifecycle-hook invocation the daemon observed, oldest first.\n\nThe platform writes no CloudWatch logs for the validate hook, so \"did my\nvalidate hook even run?\" has no answer anywhere else. Each entry is the\ndaemon's own observation — the hook path that was posted and the daemon's\nclock when it arrived — never anything the guest printed.\n\nOne trust caveat travels with this field and is stated rather than implied:\nthe hook routes are unauthenticated and reachable over loopback from inside\nthe guest, so a hostile workload can *forge additional* entries by posting\nthe hook paths itself. It cannot remove or alter real ones — the daemon\nrecords before it responds and the log is append-capped, keeping the\nearliest entries — so the platform's real firings are the front of the list\nand later spam is what the cap drops.\n\nDefaulted for `busy`'s reason: an older daemon omits the field, and an empty\nlist is the honest reading of a daemon that reports no observations.",
          "items": {
            "$ref": "#/$defs/HookObservation"
          },
          "type": "array"
        },
        "hooks_dropped": {
          "default": 0,
          "description": "How many hook invocations were dropped once the log reached its cap.\n\nNon-zero means the list above is the *earliest* invocations only — the cap\nkeeps first-N so a guest spamming the unauthenticated hook routes cannot\ngrow daemon memory or push the platform's real firings out of the record.\n\nDefaulted like `hooks`: an older daemon omits it, and zero is the honest\nreading of a daemon that dropped nothing it could tell us about.",
          "format": "uint64",
          "minimum": 0,
          "type": "integer"
        },
        "identity_degraded": {
          "description": "Whether any startup identity repair step failed. True means the VM is serving\nwith a value from the shared image still in place — a duplicate machine-id or\nboot_id — which is a security-relevant condition an operator may want to\ndrain the VM over, but is never a reason for the daemon to refuse to serve.",
          "type": "boolean"
        },
        "identity_repaired": {
          "description": "False when identity repair was switched off by config. Distinguished from a\nrepair that ran and found nothing so a monitor can tell \"opted out\" from\n\"nothing to do\".",
          "type": "boolean"
        },
        "version": {
          "type": "string"
        }
      },
      "required": [
        "version",
        "bootstrapped",
        "disk",
        "identity_degraded",
        "identity_repaired",
        "busy",
        "execs",
        "hooks",
        "hooks_dropped"
      ],
      "type": "object"
    },
    "HookObservation": {
      "description": "One lifecycle-hook invocation, as the daemon observed it.\n\nA daemon-reported fact in the same trust class as an exec's exit code: the\ndaemon's word about a request it served, carrying nothing the guest printed.",
      "properties": {
        "fired_at": {
          "description": "Seconds since the epoch on the daemon's clock when the invocation arrived.\n\nThe daemon's clock rather than any caller's, and recorded before the handler\ndoes any work — a run hook that was invoked and refused still fired.",
          "format": "uint64",
          "minimum": 0,
          "type": "integer"
        },
        "hook": {
          "description": "Which hook, spelled the way the platform's routes spell it: `ready`,\n`validate`, `run`, `suspend`, `resume`, or `terminate`.",
          "type": "string"
        }
      },
      "required": [
        "hook",
        "fired_at"
      ],
      "type": "object"
    },
    "KillResponse": {
      "description": "`POST /v1/exec/{id}/kill` response.\n\nA named type rather than the `serde_json::json!` literal this used to be: an\nad-hoc `Value` has no schema to derive, so the one route whose body a client\nmost needs to branch on — `killed` distinguishes \"signalled\" from \"the group\nwas already gone\", and both are 200 — would have been the one route the\npublished document could not describe.",
      "properties": {
        "exec_id": {
          "type": "string"
        },
        "killed": {
          "description": "Whether a signal was actually delivered. `false` with a 200 means the\nprocess group had already exited, which is the outcome a kill wanted.",
          "type": "boolean"
        }
      },
      "required": [
        "exec_id",
        "killed"
      ],
      "type": "object"
    },
    "OutputEvent": {
      "description": "One `output` SSE event.",
      "properties": {
        "offset": {
          "format": "uint64",
          "minimum": 0,
          "type": "integer"
        },
        "output": {
          "type": "string"
        },
        "stream": {
          "$ref": "#/$defs/StreamKind"
        }
      },
      "required": [
        "offset",
        "stream",
        "output"
      ],
      "type": "object"
    },
    "Phase": {
      "description": "Where an exec sits in its lifecycle. Mirrors `ExecPhase` in the model crate.\n\n`JsonSchema` rides along with `Serialize` on every type from here down that\ncrosses the wire. schemars reads the same `#[serde(...)]` attributes serde\ndoes, so the published schema describes what the daemon actually emits — the\n`rename_all` below is the reason this matters rather than a formality.",
      "oneOf": [
        {
          "const": "running",
          "description": "Child spawned, still running (or its pipes still held by a grandchild).",
          "type": "string"
        },
        {
          "const": "exited",
          "description": "Child exited and output is buffered and readable.",
          "type": "string"
        },
        {
          "const": "acked",
          "description": "Caller acked; output has been released and the entry awaits collection.",
          "type": "string"
        }
      ]
    },
    "PollResponse": {
      "description": "Captured output and exit status of a finished exec.",
      "properties": {
        "exec_id": {
          "type": "string"
        },
        "exit_code": {
          "description": "Exit code, or `None` when the child died to a signal.",
          "format": "int32",
          "type": [
            "integer",
            "null"
          ]
        },
        "phase": {
          "$ref": "#/$defs/Phase"
        },
        "signal": {
          "description": "Signal number that killed the child, when one did.",
          "format": "int32",
          "type": [
            "integer",
            "null"
          ]
        },
        "stderr": {
          "type": "string"
        },
        "stdout": {
          "type": "string"
        },
        "truncated": {
          "description": "Set when either stream hit `max_output_bytes` and was cut. An explicit\nflag rather than a sentinel string in the output: a marker inside the\nbytes is indistinguishable from output that happens to contain it.",
          "type": "boolean"
        },
        "writers_may_be_alive": {
          "description": "Set when the post-exit linger deadline expired with the pipes still open,\nmeaning some grandchild is alive and may write more that nobody will see.\nReported rather than hidden, because a harness that sees empty output from\na command it knows produced some needs to be able to tell why.",
          "type": "boolean"
        }
      },
      "required": [
        "exec_id",
        "phase"
      ],
      "type": "object"
    },
    "ProcGroup": {
      "description": "One entry of `GET /v1/procs`: an exec's process group as the daemon sees it.\n\nThe exec registry knows the group (`pgid`) and whether the direct child has\nexited; `/proc` knows which pids are still in that group. Both halves are here\nbecause the interesting case is their disagreement — `child_exited: true` with a\nnon-empty `pids` is a command that finished while something it started did not,\nwhich is exactly what a caller asking \"did this step leave anything behind\"\nneeds to see and could not before.",
      "properties": {
        "child_exited": {
          "description": "Whether the exec's own child has exited. Read from the terminal marker an\nack cannot take, so an acked exec still reads as exited here.",
          "type": "boolean"
        },
        "exec_id": {
          "type": "string"
        },
        "pgid": {
          "description": "The process group id captured at spawn. `None` when the child was reaped\nbefore it could be read, in which case `pids` is empty because there is no\ngroup to scan for.",
          "format": "uint32",
          "minimum": 0,
          "type": [
            "integer",
            "null"
          ]
        },
        "pids": {
          "description": "Live pids whose process group is `pgid`, read from `/proc`. Zombies are not\nlive and are not listed. Empty once the group is gone, and empty for an\nentry whose `pgid` is `None`.",
          "items": {
            "format": "uint32",
            "minimum": 0,
            "type": "integer"
          },
          "type": "array"
        },
        "reap": {
          "description": "Whether the exec was started with `reap_group_on_exit`.",
          "type": "boolean"
        },
        "started_at": {
          "description": "Seconds since the epoch on the daemon's clock when the child was spawned.\nThe same convention as a hook observation's `fired_at`.",
          "format": "uint64",
          "minimum": 0,
          "type": "integer"
        }
      },
      "required": [
        "exec_id",
        "pgid",
        "started_at",
        "child_exited",
        "reap",
        "pids"
      ],
      "type": "object"
    },
    "ProcsResponse": {
      "description": "`GET /v1/procs` response.",
      "properties": {
        "procs": {
          "description": "Every registered exec, in registry order, whether or not anything in its\ngroup is still alive. An exec that exited cleanly with nothing left behind\nis listed with `child_exited: true` and `pids: []`.",
          "items": {
            "$ref": "#/$defs/ProcGroup"
          },
          "type": "array"
        }
      },
      "required": [
        "procs"
      ],
      "type": "object"
    },
    "RunHookEnvelope": {
      "description": "The envelope the platform posts to the run hook.\n\nThe `runHookPayload` string given to `RunMicrovm` is not delivered as the\nrequest body: the platform wraps it, so the body is\n`{\"runHookPayload\": \"<the caller's string>\"}` and the caller's own JSON is one\n`serde_json` parse deeper. Measured 2026-08-05 — a daemon that reads\n`agent_token` from the top level answers 400, and the platform then terminates\nthe VM with \"Run lifecycle hook returned HTTP status 400\" before any traffic is\nforwarded, so the mistake is invisible from the outside.",
      "properties": {
        "runHookPayload": {
          "type": [
            "string",
            "null"
          ]
        }
      },
      "type": "object"
    },
    "StartRequest": {
      "description": "A start request. `command` is either an argv array or, with `shell: true`, a\nsingle script string.",
      "properties": {
        "command": {
          "description": "argv when `shell` is false, or the script when it is true.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "cwd": {
          "default": null,
          "description": "Omitted means inherit the daemon's working directory. See the module docs.",
          "type": [
            "string",
            "null"
          ]
        },
        "env": {
          "additionalProperties": {
            "type": "string"
          },
          "default": {},
          "type": "object"
        },
        "exec_id": {
          "description": "Caller-minted idempotency key. Harbor retries, and a retry must not\nproduce a second child.",
          "type": "string"
        },
        "group": {
          "default": null,
          "format": "uint32",
          "minimum": 0,
          "type": [
            "integer",
            "null"
          ]
        },
        "reap_group_on_exit": {
          "default": false,
          "description": "Whether to signal the exec's whole process group once its own child exits.\n\nOff by default, and the default is the contract this daemon has always had:\na backgrounded grandchild that inherited the output pipe keeps running and\nkeeps writing, and the linger deadline is what bounds how long the daemon\nwaits on it. That is the \"backgrounded server keeps logging\" guarantee, and\ncallers rely on it. Set to `true`, the daemon runs the same SIGTERM-then-\nSIGKILL escalation `POST /v1/exec/{id}/kill` uses against the group as soon\nas the child's exit is observed, so nothing the command left behind outlives\nit and the linger sees EOF rather than `writers_may_be_alive`. A timed-out\nexec is already escalated and is not escalated twice.",
          "type": "boolean"
        },
        "shell": {
          "default": false,
          "type": "boolean"
        },
        "stdin": {
          "default": false,
          "description": "Whether to give the child a writable stdin pipe. Defaults to false, which\nkeeps `Stdio::null()`.\n\nOpt-in rather than always-on, and not only for tidiness: a child holding an\nopen stdin pipe nobody will ever write to is a child that blocks forever\nthe first time it reads. `/bin/sh` reading a script from stdin, `git`\ndeciding it can prompt, any tool that probes for input — all of them behave\ndifferently against a pipe than against `/dev/null`. Every existing caller\ngets today's behavior by not setting this.",
          "type": "boolean"
        },
        "timeout_sec": {
          "default": null,
          "description": "Wall-clock budget. Validated before the child spawns — the predecessor\nraised on a bad value inside the waiter thread, by which point the child\nwas already running and became an orphan.",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "user": {
          "default": null,
          "description": "Numeric uid to demote to. Optional; omitted means run as the daemon's own\nuser.",
          "format": "uint32",
          "minimum": 0,
          "type": [
            "integer",
            "null"
          ]
        }
      },
      "required": [
        "exec_id",
        "command"
      ],
      "type": "object"
    },
    "StartResponse": {
      "properties": {
        "exec_id": {
          "type": "string"
        },
        "phase": {
          "$ref": "#/$defs/Phase"
        }
      },
      "required": [
        "exec_id",
        "phase"
      ],
      "type": "object"
    },
    "StdinRequest": {
      "description": "`POST /v1/exec/{id}/stdin` body.\n\nBoth fields optional and both meaningful together: a final chunk plus EOF in\none request is the common case for feeding a prompt, and forcing two round\ntrips would leave a window where the child has the bytes but not the EOF that\ntells it the input is complete.",
      "properties": {
        "data_b64": {
          "default": null,
          "description": "Base64 so arbitrary bytes survive JSON. A JSON string cannot carry\nnon-UTF-8, and stdin is bytes.",
          "type": [
            "string",
            "null"
          ]
        },
        "signal": {
          "default": null,
          "description": "`\"eof\"` closes the pipe after any `data_b64` is written. Named rather than\na bare boolean so the field has somewhere to grow.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "type": "object"
    },
    "StdinResponse": {
      "description": "`POST /v1/exec/{id}/stdin` response.\n\n`pub` rather than private, like every other type in this module the schema\nroute publishes: the generator names them by type, so a response shape that\nstays private is a shape a consumer cannot be told about.",
      "properties": {
        "eof": {
          "type": "boolean"
        },
        "exec_id": {
          "type": "string"
        },
        "written": {
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        }
      },
      "required": [
        "exec_id",
        "written",
        "eof"
      ],
      "type": "object"
    },
    "StreamKind": {
      "description": "Which pipe a streamed chunk came from. Both share one offset space, so a\nclient holds one cursor rather than two that can disagree about ordering.",
      "enum": [
        "stdout",
        "stderr"
      ],
      "type": "string"
    },
    "StreamQuery": {
      "description": "`GET /v1/exec/{id}/stream` query.",
      "properties": {
        "offset": {
          "default": null,
          "description": "Byte offset to resume from. Absent means 0, i.e. everything still in the\nreplay window.",
          "format": "uint64",
          "minimum": 0,
          "type": [
            "integer",
            "null"
          ]
        }
      },
      "type": "object"
    },
    "TunnelQuery": {
      "description": "`?port=<n>[&identity=true]` — the guest port to relay to, and whether to prove identity.",
      "properties": {
        "identity": {
          "default": false,
          "description": "Whether to run a Noise KK handshake before relaying any bytes.\n\nOn this struct rather than in a second query type because one route has one query\ncontract, and the schema is generated from exactly that: a separate type would need a\nsecond extractor and would not appear in `docs/schema.json` at all.\n\nAbsent means `false`, which is what keeps every layer-2 client working unchanged. True\nagainst a VM launched without a seed is refused with [`close::NO_IDENTITY`] rather than\nsilently downgraded — a caller who asked to verify identity and got an unverified\ntunnel would believe a proof it never received. See [`super::identity`] for what the\nhandshake proves and its honest limit.",
          "type": "boolean"
        },
        "port": {
          "description": "The guest port. Dialled on `127.0.0.1` only.\n\n`0` parses and is refused *after* the upgrade with [`close::BAD_PORT`], rather than\nrejected as a parse error: a caller who named it gets a reason naming the port\ninstead of a 400 that could equally mean a missing parameter.",
          "format": "uint16",
          "maximum": 65535,
          "minimum": 0,
          "type": "integer"
        }
      },
      "required": [
        "port"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "auth": {
    "bootstrap": {
      "before_bootstrap": "503 on every bearer route, never 404",
      "how": "the platform posts the token to the run hook at launch",
      "note": "the token is compared on raw bytes in constant time, so a non-ASCII header is answered rather than dropped",
      "wrong_token": "401"
    },
    "header": "authorization",
    "scheme": "bearer"
  },
  "daemon_version": "0.1.0",
  "definition_collisions": [],
  "generated_from": "the daemon's own serde types, via schemars",
  "hook_prefix": "/aws/lambda-microvms/runtime/v1",
  "limits": {
    "exec_ttl_secs": 900.0,
    "kill_grace_secs": 10.0,
    "max_body_bytes": 536870912,
    "max_drain_bytes": 65536,
    "max_output_bytes": 8388608,
    "max_stdin_write_bytes": 1048576,
    "max_tar_bytes": 8589934592,
    "max_tar_members": 100000,
    "output_linger_secs": 5.0,
    "sse_keepalive_secs": 15.0,
    "stdin_write_timeout_secs": 5.0,
    "stream_replay_bytes": 1048576
  },
  "protocol_version": "1",
  "routes": [
    {
      "auth": "none (platform hook)",
      "method": "POST",
      "path": "/aws/lambda-microvms/runtime/v1/ready",
      "request": null,
      "response": null,
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "acknowledged. The platform terminates the VM on any other status, so there is no failure a hook can usefully report."
        }
      ],
      "summary": "image-build readiness probe; answers 200 even before bootstrap, because the question is whether the daemon started. Every hook invocation is recorded and reported on /v1/health as `hooks`."
    },
    {
      "auth": "none (platform hook)",
      "method": "POST",
      "path": "/aws/lambda-microvms/runtime/v1/validate",
      "request": null,
      "response": null,
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "acknowledged. The platform terminates the VM on any other status, so there is no failure a hook can usefully report."
        }
      ],
      "summary": "image-build validation probe; same reasoning as ready. Recorded on /v1/health's `hooks`, which is the only trace this hook leaves — the platform writes no CloudWatch logs for it."
    },
    {
      "auth": "none (platform hook)",
      "method": "POST",
      "path": "/aws/lambda-microvms/runtime/v1/run",
      "request": {
        "media_type": "application/json",
        "schema": {
          "$ref": "#/$defs/RunHookEnvelope"
        }
      },
      "response": null,
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "the token was installed, or an identical token was replayed. A replay is success because the platform may retry its own hook, and answering 409 would fail a launch that is fine."
        },
        {
          "code": 400,
          "error": "",
          "meaning": "the body is not JSON, carries no runHookPayload, the payload is not a JSON object, agent_token is absent or not a string or empty, env is present but not an object, or an env value is not a string. The body names which of those it was, and never quotes a value — the payload carries the token. An unknown key is NOT one of these: it is ignored, because the platform terminates the VM on any 400 here, before any traffic is forwarded, so a newer client's unrecognised field must not kill the launch."
        },
        {
          "code": 409,
          "error": "",
          "meaning": "a different token is already installed. Refused, and nothing changes — including the launch env, which only the first successful bootstrap sets: bootstrap is one-shot so a losing racer never replaces the winner's token, and cannot rewrite the environment every later child runs in either."
        }
      ],
      "summary": "one-shot token bootstrap, plus the optional launch environment. The platform wraps the caller's string, so the payload's own fields are one JSON parse deeper than the request body: {\"runHookPayload\": \"{\\\"agent_token\\\": \\\"...\\\", \\\"env\\\": {\\\"KEY\\\": \\\"VALUE\\\"}}\"}. `agent_token` is required and non-empty; `env` is optional and becomes the BASE environment of every later exec, with each request's own `env` overlaid on top of it. Values must be strings. Unknown keys are ignored, so a newer client can still bootstrap this daemon. The whole payload is capped by the platform at 4096 bytes inclusive, measured in UTF-8 bytes — the token and the env share that budget. `env` is installed only by the first successful bootstrap: a replay cannot edit it and a conflicting token cannot either."
    },
    {
      "auth": "none (platform hook)",
      "method": "POST",
      "path": "/aws/lambda-microvms/runtime/v1/suspend",
      "request": null,
      "response": null,
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "acknowledged. The platform terminates the VM on any other status, so there is no failure a hook can usefully report."
        }
      ],
      "summary": "acknowledged and logged"
    },
    {
      "auth": "none (platform hook)",
      "method": "POST",
      "path": "/aws/lambda-microvms/runtime/v1/resume",
      "request": null,
      "response": null,
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "acknowledged. The platform terminates the VM on any other status, so there is no failure a hook can usefully report."
        }
      ],
      "summary": "acknowledged. Measured: the token, filesystem, exec records, and even backgrounded processes survive a suspend/resume cycle. What does not survive is the guest's view of time, which jumps — so any timeout or lease held by a running command expires at once on resume."
    },
    {
      "auth": "none (platform hook)",
      "method": "POST",
      "path": "/aws/lambda-microvms/runtime/v1/terminate",
      "request": null,
      "response": null,
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "acknowledged. The platform terminates the VM on any other status, so there is no failure a hook can usefully report."
        }
      ],
      "summary": "acknowledged; begins graceful shutdown with in-flight requests draining"
    },
    {
      "auth": "bearer",
      "method": "POST",
      "path": "/v1/exec/start",
      "request": {
        "media_type": "application/json",
        "schema": {
          "$ref": "#/$defs/StartRequest"
        }
      },
      "response": {
        "media_type": "application/json",
        "schema": {
          "$ref": "#/$defs/StartResponse"
        }
      },
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "started, or a retry of an already-started exec_id. Idempotent: a retry does not spawn a second child and does not disturb the first one's output."
        },
        {
          "code": 400,
          "error": "malformed_request",
          "meaning": "the body is not a valid start request, exec_id is empty, timeout_sec is not a positive finite number, or command is empty with shell false"
        },
        {
          "code": 401,
          "error": "",
          "meaning": "the presented bearer token does not match the installed one"
        },
        {
          "code": 503,
          "error": "",
          "meaning": "no token is installed yet, so the control API is closed. Never 404: a client mapping 404 onto \"not found\" would report a phantom absent artifact."
        },
        {
          "code": 413,
          "error": "",
          "meaning": "the request body exceeds limits.max_body_bytes, enforced on the wire"
        },
        {
          "code": 500,
          "error": "spawn_failed",
          "meaning": "the child could not be spawned, e.g. ENOENT on argv[0]. Deliberately not 404: a client reads 404 here as \"no such exec\"."
        }
      ],
      "summary": "start a command under a caller-minted exec_id. Idempotent on that id: a retry returns success without spawning a second child."
    },
    {
      "auth": "bearer",
      "method": "GET",
      "path": "/v1/exec/{id}",
      "request": null,
      "response": {
        "media_type": "application/json",
        "schema": {
          "$ref": "#/$defs/PollResponse"
        }
      },
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "the current phase, plus the outcome once the exec has exited and before it is acked. Strictly read-only."
        },
        {
          "code": 401,
          "error": "",
          "meaning": "the presented bearer token does not match the installed one"
        },
        {
          "code": 503,
          "error": "",
          "meaning": "no token is installed yet, so the control API is closed. Never 404: a client mapping 404 onto \"not found\" would report a phantom absent artifact."
        },
        {
          "code": 404,
          "error": "unknown_exec",
          "meaning": "no exec is registered under this id, or its entry was collected after an ack"
        }
      ],
      "summary": "poll status and output. Read-only: polling never mutates the entry, and output survives until an explicit ack."
    },
    {
      "auth": "bearer",
      "method": "GET",
      "path": "/v1/exec/{id}/stream",
      "query": {
        "media_type": "application/x-www-form-urlencoded",
        "schema": {
          "$ref": "#/$defs/StreamQuery"
        }
      },
      "request": null,
      "response": {
        "media_type": "text/event-stream",
        "note": "resume with ?offset=N to receive exactly the bytes after N. The next offset to resume from is a chunk's offset plus the length of its decoded bytes. A body that ends without an exit event means the connection failed, not the command — that distinction is the reason this is SSE and not a chunked byte stream."
      },
      "sse_events": [
        {
          "event": "output",
          "meaning": "a run of bytes at a known offset. `output` is base64 because output is arbitrary bytes and a JSON string cannot carry non-UTF-8 — and because a lossy decode would split a multi-byte character at a chunk boundary. Resume from offset + len(decoded).",
          "schema": {
            "$ref": "#/$defs/OutputEvent"
          }
        },
        {
          "event": "gap",
          "meaning": "bytes in [from, to) are gone: the request resumed before the replay window, or this subscriber fell behind the live channel. Reported rather than hidden, because a client that cannot tell missing output from no output will read a truncated log as a complete one.",
          "schema": {
            "$ref": "#/$defs/GapEvent"
          }
        },
        {
          "event": "exit",
          "meaning": "the terminal event, emitted before the body ends. A body that closes without it means the connection failed, not the command. `offset` is the total bytes published, so a client can assert it saw all of them.",
          "schema": {
            "$ref": "#/$defs/ExitEvent"
          }
        }
      ],
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "an SSE stream that replays from ?offset= and then follows live output. Attaching and detaching do not affect the exec."
        },
        {
          "code": 400,
          "error": "malformed_request",
          "meaning": "offset is not a non-negative integer"
        },
        {
          "code": 401,
          "error": "",
          "meaning": "the presented bearer token does not match the installed one"
        },
        {
          "code": 503,
          "error": "",
          "meaning": "no token is installed yet, so the control API is closed. Never 404: a client mapping 404 onto \"not found\" would report a phantom absent artifact."
        },
        {
          "code": 404,
          "error": "unknown_exec",
          "meaning": "no exec is registered under this id, or its entry was collected after an ack"
        }
      ],
      "summary": "follow output as Server-Sent Events from a byte offset"
    },
    {
      "auth": "bearer",
      "method": "POST",
      "path": "/v1/exec/{id}/stdin",
      "request": {
        "media_type": "application/json",
        "schema": {
          "$ref": "#/$defs/StdinRequest"
        }
      },
      "response": {
        "media_type": "application/json",
        "schema": {
          "$ref": "#/$defs/StdinResponse"
        }
      },
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "bytes written, and eof echoed back so a client can confirm the pipe was closed rather than inferring it"
        },
        {
          "code": 400,
          "error": "malformed_request",
          "meaning": "the body is not a valid stdin request, data_b64 is not valid base64, or signal is something other than \"eof\""
        },
        {
          "code": 401,
          "error": "",
          "meaning": "the presented bearer token does not match the installed one"
        },
        {
          "code": 503,
          "error": "",
          "meaning": "no token is installed yet, so the control API is closed. Never 404: a client mapping 404 onto \"not found\" would report a phantom absent artifact."
        },
        {
          "code": 404,
          "error": "unknown_exec",
          "meaning": "no exec is registered under this id, or its entry was collected after an ack"
        },
        {
          "code": 408,
          "error": "stdin_write_timeout",
          "meaning": "the child did not read within limits.stdin_write_timeout_secs. Retryable, and some bytes may already have been written."
        },
        {
          "code": 409,
          "error": "stdin_not_requested",
          "meaning": "the exec was started without stdin: true, so its stdin is /dev/null. The fix is at start time, which is why this is 409 and not 400."
        },
        {
          "code": 410,
          "error": "stdin_closed",
          "meaning": "stdin was already closed by an earlier eof, or the child stopped reading. 410 rather than 409: retrying will never succeed."
        },
        {
          "code": 413,
          "error": "stdin_write_too_large",
          "meaning": "the decoded write exceeds limits.max_stdin_write_bytes"
        },
        {
          "code": 500,
          "error": "stdin_write_failed",
          "meaning": "the write to the pipe failed for a reason other than a broken pipe"
        }
      ],
      "summary": "write to a child's stdin, or signal EOF. A separate request from the output stream on purpose: a dropped attach must not cost the ability to feed the process. EOF is explicit rather than inferred, because a child reading stdin cannot exit until the daemon drops its own handle."
    },
    {
      "auth": "bearer",
      "method": "POST",
      "path": "/v1/exec/{id}/ack",
      "request": null,
      "response": {
        "media_type": "application/json",
        "schema": {
          "$ref": "#/$defs/PollResponse"
        }
      },
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "output released and the TTL clock started. This is the only way output leaves the daemon's custody."
        },
        {
          "code": 401,
          "error": "",
          "meaning": "the presented bearer token does not match the installed one"
        },
        {
          "code": 503,
          "error": "",
          "meaning": "no token is installed yet, so the control API is closed. Never 404: a client mapping 404 onto \"not found\" would report a phantom absent artifact."
        },
        {
          "code": 404,
          "error": "unknown_exec",
          "meaning": "no exec is registered under this id, or its entry was collected after an ack"
        },
        {
          "code": 409,
          "error": "still_running",
          "meaning": "the exec has not exited and output is still being written. A silent success here would drop it."
        },
        {
          "code": 409,
          "error": "already_acked",
          "meaning": "an earlier ack released the output. 200 with an empty body would read as \"the command produced no output\"."
        }
      ],
      "summary": "release output and enter TTL collection. Only acked entries are ever collected, so output nobody read is never destroyed."
    },
    {
      "auth": "bearer",
      "method": "POST",
      "path": "/v1/exec/{id}/kill",
      "request": null,
      "response": {
        "media_type": "application/json",
        "schema": {
          "$ref": "#/$defs/KillResponse"
        }
      },
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "the process group was signalled, or killed is false because it had already exited — which is the outcome a kill was asking for"
        },
        {
          "code": 401,
          "error": "",
          "meaning": "the presented bearer token does not match the installed one"
        },
        {
          "code": 503,
          "error": "",
          "meaning": "no token is installed yet, so the control API is closed. Never 404: a client mapping 404 onto \"not found\" would report a phantom absent artifact."
        },
        {
          "code": 404,
          "error": "unknown_exec",
          "meaning": "no exec is registered under this id, or its entry was collected after an ack"
        }
      ],
      "summary": "SIGTERM then SIGKILL to the whole process group, not just the direct child — a shell that backgrounded a server leaves the interesting process outside the child pid"
    },
    {
      "auth": "bearer",
      "method": "GET",
      "path": "/v1/procs",
      "request": null,
      "response": {
        "media_type": "application/json",
        "schema": {
          "$ref": "#/$defs/ProcsResponse"
        }
      },
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "every registered exec with its group's live pids, in registry order. An empty list is a daemon that has run nothing since it started, not an error."
        },
        {
          "code": 401,
          "error": "",
          "meaning": "the presented bearer token does not match the installed one"
        },
        {
          "code": 503,
          "error": "",
          "meaning": "no token is installed yet, so the control API is closed. Never 404: a client mapping 404 onto \"not found\" would report a phantom absent artifact."
        }
      ],
      "summary": "process accounting: every registered exec with its process group's live pids, read from /proc so the guest needs no `ps`. `child_exited` beside a non-empty `pids` is a command that finished while something it backgrounded did not — the shape /v1/health's `busy` cannot show, and the exec_id beside it is the one to pass to /v1/exec/{id}/kill. `reap` echoes the start request's `reap_group_on_exit`. Entries whose pgid was never captured list no pids. Read-only."
    },
    {
      "auth": "bearer",
      "method": "GET",
      "path": "/v1/tcp",
      "query": {
        "media_type": "application/x-www-form-urlencoded",
        "schema": {
          "$ref": "#/$defs/TunnelQuery"
        }
      },
      "request": null,
      "response": null,
      "statuses": [
        {
          "code": 101,
          "error": "",
          "meaning": "the upgrade succeeded. The guest dial happens AFTER the upgrade, so a 101 does not yet mean the guest port answered: a refused dial arrives as close code 4502 with a reason naming the port. That ordering is deliberate — on the endpoint path every WebSocket failure a caller can observe is 1006 with no reason, so an HTTP 502 here would be invisible to the only client that matters."
        },
        {
          "code": 400,
          "error": "malformed_request",
          "meaning": "?port is absent or is not a u16. Port 0 parses and is refused after the upgrade with close code 4400, because a caller that named it deserves a reason rather than a parse error."
        },
        {
          "code": 401,
          "error": "",
          "meaning": "the presented bearer token does not match the installed one"
        },
        {
          "code": 503,
          "error": "",
          "meaning": "no token is installed yet, so the control API is closed. Never 404: a client mapping 404 onto \"not found\" would report a phantom absent artifact."
        }
      ],
      "summary": "upgrade to a WebSocket relayed to 127.0.0.1:<port> in the guest, so a caller outside the VM can speak an arbitrary TCP protocol to a server inside it. Binary frames carry bytes in both directions and a frame is a byte range rather than a message — TCP has no message boundaries and neither does this. The dial is loopback-only and never resolves a name: a relay that could reach another host would be an open proxy inside the VM reachable with the agent token. One connection per WebSocket, deliberately: multiplexing would reimplement per-stream ids, flow control, and close handshakes that the platform already provides per connection. Outcomes arrive as close codes — 4502 nothing listening, 4400 port 0, 4500 a mid-relay failure — because a WebSocket route leaves HTTP behind after its 101. Rests on a measured platform property: binary frames survive a port-scoped token byte-exact (docs/PLATFORM.md, 2026-08-29). With `identity=1` the relay first completes a Noise KK handshake against the per-VM key delivered in the launch payload, which proves the far end is this VM without trusting the endpoint proxy and makes every later frame ciphertext; 4401 means this VM was launched without a seed and 4403 means the handshake was refused. The handshake runs before the dial, so a refused caller never reaches a guest service."
    },
    {
      "auth": "bearer",
      "method": "GET",
      "path": "/v1/fs/file",
      "query": {
        "media_type": "application/x-www-form-urlencoded",
        "schema": {
          "$ref": "#/$defs/FileReadQuery"
        }
      },
      "request": null,
      "response": {
        "media_type": "application/octet-stream",
        "note": "the file's bytes, streamed"
      },
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "the file's bytes, streamed rather than buffered — or the requested line range of them, also streamed. A range whose end_line is past the last line answers 200 through EOF, never 416: 416 is about a range the file cannot satisfy, and reading through EOF is the harness contract."
        },
        {
          "code": 400,
          "error": "",
          "meaning": "the path query parameter is missing, it names a directory — use /v1/fs/tar for that — start_line or end_line is not an integer, start_line is 0 (the range is 1-based), or end_line is before start_line. Never 404 for any of them: a protocol error must not look like an absent file."
        },
        {
          "code": 401,
          "error": "",
          "meaning": "the presented bearer token does not match the installed one"
        },
        {
          "code": 503,
          "error": "",
          "meaning": "no token is installed yet, so the control API is closed. Never 404: a client mapping 404 onto \"not found\" would report a phantom absent artifact."
        },
        {
          "code": 404,
          "error": "",
          "meaning": "the path is genuinely absent. The one place in the fs surface where a client's FileNotFoundError is the right mapping."
        },
        {
          "code": 500,
          "error": "",
          "meaning": "the file could not be opened or stat'ed"
        }
      ],
      "summary": "read one file, or a 1-based inclusive line range of it. ?start_line=&end_line= are the AI SDK harness's readTextFile semantics: an end_line past the last line reads through EOF without error, and omitting both returns the whole file byte-identically. Still streamed — the range never buffers the file to slice it."
    },
    {
      "auth": "bearer",
      "method": "PUT",
      "path": "/v1/fs/file",
      "query": {
        "media_type": "application/x-www-form-urlencoded",
        "schema": {
          "$ref": "#/$defs/FsQuery"
        }
      },
      "request": {
        "media_type": "application/octet-stream",
        "note": "the file's bytes, streamed to disk rather than buffered"
      },
      "response": null,
      "statuses": [
        {
          "code": 204,
          "error": "",
          "meaning": "written, with the mode applied"
        },
        {
          "code": 400,
          "error": "",
          "meaning": "the path query parameter is missing, or mode is not a valid octal file mode. Checked before a byte lands, so a rejected mode leaves nothing behind."
        },
        {
          "code": 401,
          "error": "",
          "meaning": "the presented bearer token does not match the installed one"
        },
        {
          "code": 503,
          "error": "",
          "meaning": "no token is installed yet, so the control API is closed. Never 404: a client mapping 404 onto \"not found\" would report a phantom absent artifact."
        },
        {
          "code": 413,
          "error": "",
          "meaning": "the request body exceeds limits.max_body_bytes, enforced on the wire"
        },
        {
          "code": 507,
          "error": "",
          "meaning": "the target filesystem is under the configured disk reserve, and the body names the available and reserved byte counts. 507 rather than 500 because a 500 is indistinguishable from a daemon defect and a client retries it, which is right for a defect and actively harmful for a full disk; and rather than 413 because the write is not too large for the protocol, only for the space left."
        },
        {
          "code": 500,
          "error": "",
          "meaning": "the parent could not be created, or the write or chmod failed"
        }
      ],
      "summary": "write one file. Deliberately not confined to a root: the same token authorizes exec, so a root prefix would add no security while breaking harnesses that write to home directories and /etc."
    },
    {
      "auth": "bearer",
      "method": "GET",
      "path": "/v1/fs/tar",
      "query": {
        "media_type": "application/x-www-form-urlencoded",
        "schema": {
          "$ref": "#/$defs/FsQuery"
        }
      },
      "request": null,
      "response": {
        "media_type": "application/x-tar",
        "note": "uncompressed, streamed from a spool file"
      },
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "an uncompressed tar of the tree, streamed from a spool file. Symlinks are packed as symlinks, matching what extraction accepts."
        },
        {
          "code": 400,
          "error": "",
          "meaning": "the path query parameter is missing, or it is not a directory — use /v1/fs/file for that"
        },
        {
          "code": 401,
          "error": "",
          "meaning": "the presented bearer token does not match the installed one"
        },
        {
          "code": 503,
          "error": "",
          "meaning": "no token is installed yet, so the control API is closed. Never 404: a client mapping 404 onto \"not found\" would report a phantom absent artifact."
        },
        {
          "code": 404,
          "error": "",
          "meaning": "the directory is genuinely absent"
        },
        {
          "code": 413,
          "error": "",
          "meaning": "the tree exceeds limits.max_tar_members or limits.max_tar_bytes, measured by a walk before anything is allocated"
        },
        {
          "code": 500,
          "error": "",
          "meaning": "the tree could not be walked or packed"
        }
      ],
      "summary": "download a tree as tar. Symlinks are packed as symlinks, which is the producing half of what extraction accepts."
    },
    {
      "auth": "bearer",
      "method": "PUT",
      "path": "/v1/fs/tar",
      "query": {
        "media_type": "application/x-www-form-urlencoded",
        "schema": {
          "$ref": "#/$defs/FsQuery"
        }
      },
      "request": {
        "media_type": "application/x-tar",
        "note": "uncompressed; spooled to an unlinked temp file, never buffered"
      },
      "response": null,
      "statuses": [
        {
          "code": 204,
          "error": "",
          "meaning": "extracted under ?path="
        },
        {
          "code": 400,
          "error": "",
          "meaning": "the path query parameter is missing or not absolute, the body was truncated, or a member violated the extraction contract — an escaping path, an absolute or out-of-tree link target, or a device or fifo member. The refused member's name is in the body."
        },
        {
          "code": 401,
          "error": "",
          "meaning": "the presented bearer token does not match the installed one"
        },
        {
          "code": 503,
          "error": "",
          "meaning": "no token is installed yet, so the control API is closed. Never 404: a client mapping 404 onto \"not found\" would report a phantom absent artifact."
        },
        {
          "code": 413,
          "error": "",
          "meaning": "the archive exceeds limits.max_body_bytes on the wire, or limits.max_tar_members or limits.max_tar_bytes once decoded"
        },
        {
          "code": 507,
          "error": "",
          "meaning": "the target filesystem is under the configured disk reserve, and the body names the available and reserved byte counts. 507 rather than 500 because a 500 is indistinguishable from a daemon defect and a client retries it, which is right for a defect and actively harmful for a full disk; and rather than 413 because the write is not too large for the protocol, only for the space left."
        },
        {
          "code": 500,
          "error": "",
          "meaning": "extraction failed for a filesystem reason"
        }
      ],
      "summary": "upload and extract a tar under ?path=, confined to that root — the one confined write path, because member paths come from the archive rather than from the caller. Mirrors the CPython tarfile `data` filter: in-tree symlinks preserved, absolute link targets refused, relative targets resolved lexically so a symlink written earlier in the same archive cannot redirect a later member."
    },
    {
      "auth": "none",
      "method": "GET",
      "path": "/v1/health",
      "request": null,
      "response": {
        "media_type": "application/json",
        "schema": {
          "$ref": "#/$defs/Health"
        }
      },
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "always, whether or not the daemon is bootstrapped. bootstrapped is how a client learns whether the control API is open yet; busy is how an orchestrator outside the VM learns whether a workload is still running, so its own poll doubles as the inbound traffic the platform's idle policy measures. An in-guest request cannot serve that purpose: the endpoint proxy terminates outside the guest."
        }
      ],
      "summary": "liveness, daemon version, whether bootstrap has completed, and whether any exec is still running. `busy` exists so an orchestrator OUTSIDE the VM can hold it alive: the platform measures idleness by inbound traffic through the endpoint proxy, which terminates outside the guest, so a request from inside the guest cannot reset the idle timer. Polling this from outside is both the traffic and the decision. `hooks` lists every lifecycle hook the daemon observed, oldest first, with `fired_at` epoch seconds on the daemon's clock, and `hooks_dropped` counts invocations past the cap. Hook routes are unauthenticated and loopback-reachable from inside the guest, so a hostile workload can forge ADDITIONAL entries — never remove or alter real ones; the cap keeps the earliest, which are the platform's."
    },
    {
      "auth": "none",
      "method": "GET",
      "path": "/v1/schema",
      "request": null,
      "response": {
        "media_type": "application/octet-stream",
        "note": "this document"
      },
      "statuses": [
        {
          "code": 200,
          "error": "",
          "meaning": "this document. Unauthenticated by design: a client needs the contract before it has a token, and none of it is secret."
        }
      ],
      "summary": "this document: every route, shape, status code, and operative limit"
    }
  ],
  "title": "microvms-agentd wire protocol",
  "unmatched_path": {
    "code": 404,
    "meaning": "no such route. Bearer routes are behind route_layer, so an unmatched path falls through to this rather than being answered 401 — a typo must not send a client chasing credentials."
  },
  "version_header": "microvms-agentd-version"
}
