{
  "$comment": "Every schema this host publishes. Each page is at href; each version is a file at its id.",
  "base": "https://schemas.inorbit.hr/",
  "count": 7,
  "schemas": [
    {
      "path": "agent/signal",
      "area": "agent",
      "name": "signal",
      "title": "Agent signal frame",
      "description": "One sensor reading an agent sends on its session WebSocket: a JSON text frame with type signal, accepted only when the welcome's accepts list names signal. The platform reads it, bounds it, and records it as one reading of a sensor registered for the agent (the recorded reading is $defs/reading). One frame is one reading; there is no batch of frames on the wire, a batch is the readings list of the ingest body (sensors/ingest). A reading is a number and a level, never content: the object is closed so a body, a prompt, a target, a path or a credential is refused. The fields template, series and host are what the dataplane agent sends besides the core's four; the platform ignores them, and the host label of the recorded reading is the agent id from the verified session, never the frame's host.",
      "status": "draft",
      "owner": "",
      "replaced_by": "",
      "href": "https://schemas.inorbit.hr/agent/signal/",
      "latest": 0,
      "versions": [
        {
          "major": 0,
          "id": "https://schemas.inorbit.hr/agent/signal/v0.json",
          "status": "draft"
        }
      ],
      "fields": [
        "type",
        "sensor",
        "template",
        "value",
        "level",
        "series",
        "at",
        "host"
      ]
    },
    {
      "path": "approvals/runner-enrollment",
      "area": "approvals",
      "name": "runner-enrollment",
      "title": "Runner enrollment",
      "description": "What a person approves to enrol a runner's run key: the key itself, the label the runner gave it and the key's fingerprint, so the phone shows the same fingerprint the terminal printed. It travels as the payload of an approval of kind runner_enrollment; the approval pins the SHA-256 of its canonical JSON (keys sorted, no whitespace), and the person's device-key signature over that approval is the enrolment proof. The runner then proves it holds the key and is enrolled once. Strings only, so the canonical JSON is the same in every language. Closed object.",
      "status": "draft",
      "owner": "",
      "replaced_by": "",
      "href": "https://schemas.inorbit.hr/approvals/runner-enrollment/",
      "latest": 0,
      "versions": [
        {
          "major": 0,
          "id": "https://schemas.inorbit.hr/approvals/runner-enrollment/v0.json",
          "status": "draft"
        }
      ],
      "fields": [
        "public_key",
        "label",
        "fingerprint"
      ]
    },
    {
      "path": "runner/host-action",
      "area": "runner",
      "name": "host-action",
      "title": "Runner host action",
      "description": "One action a person approves for one enrolled runner to carry out on its host: the action's dotted id from the catalog, the runner that runs it, its parameters (typed per action) and what it does in one plain sentence. It travels inside a signed approval for a pinned run: the approval names this schema, carries the action as its canonical JSON (keys sorted, no whitespace), pins the SHA-256 of that JSON, and the action's runner_id is the run's own. Integers and strings only, so the canonical JSON is the same in every language. The object and every params object are closed: an action can do only what its params say. Catalog: k8s.delete-failed-pods (params.namespace; absent means every namespace); k8s.rollout-restart (params.namespace and params.deployment: restart one deployment and wait for its rollout; the cluster's own namespaces are refused); systemd.user-restart (params.unit: reload the user's systemd manager and restart one user service; Linux only); docker.prune-images (params.until_hours: remove the images unused and older than that many hours; never volumes); gh.cancel-run (params.repo and params.run_id: cancel one GitHub Actions run of an inorbithr repository); iohr.upgrade (no params: the runner upgrades its own iohr the way it was installed); preview.take (params.branch: take one preview-int/, feat/ or fix/ branch into the owner's Preview checkout, then check the Preview app); roll.task (params.rev, params.task and params.services: run one roll task at one commit of main on the deploy server); build.sweep-targets (params.mode: cap or guard the Rust build output of the core checkout and its worktrees); gh.release-rerun (params.run_id: re-run the failed jobs of one failed sdk release run whose commit passed its examples). agent.install-checks (params.block, params.commit and params.service: install one block of monitor checks from core at one commit of main into the agent's checks file and restart the agent; Linux only). disk.prune (params.target and, for docker-builder, params.until_hours: free disk on the host from one named target; host runs the host prune, docker-builder removes the Docker build cache older than that many hours, k3d-images removes the images no pod uses from each k3d node; it reports the free space before and after and fails when nothing was freed; Linux only). helm.runner-scale (params.release, params.max_runners and optionally params.min_runners: set one ARC runner scale set's maximum and minimum runners on the deploy server's cluster and read the values back). labs.reattribute-document (params.document, params.from, params.evidence_ts and the proven row counts params.expected_documents, params.expected_versions and params.expected_comments: on the deploy server, move one Decisions document's proven rows from one subject to Io with labs:reattribute, only while a dry run counts exactly those rows; the run can be reverted).",
      "status": "draft",
      "owner": "",
      "replaced_by": "",
      "href": "https://schemas.inorbit.hr/runner/host-action/",
      "latest": 0,
      "versions": [
        {
          "major": 0,
          "id": "https://schemas.inorbit.hr/runner/host-action/v0.json",
          "status": "draft"
        }
      ],
      "fields": [
        "action",
        "runner_id",
        "params",
        "effect"
      ]
    },
    {
      "path": "sensors/consent",
      "area": "sensors",
      "name": "consent",
      "title": "Sensor consent",
      "description": "A record of what one client agreed to share with InOrbit as sensor readings, who agreed, for which account (and optionally one Decisions space), and whether and when that agreement ended. A client is a Mac app, a phone, a browser extension, a Claude plugin, an agent or a runner. It is a record of an agreement, not of data: it holds ids, words from closed lists and timestamps, no reading value, no content and no credential, and the object is closed so a field outside these is refused. A consent is off until a person grants it; a revoke is a fact added to the record (revoked_at and revoked_by), never an edit that erases the grant. A consent is in force when it is not revoked and has not expired. This is not the OAuth consent of a sign-in: that one lets a client call the API; this one lets a client send readings. The sensor id and timestamp are those of sensors/reading v0, by reference. The sources and kinds are the words of sensors/sensor v0 and the sources the Sensors API registers, which are the source of truth; they are listed here.",
      "status": "draft",
      "owner": "",
      "replaced_by": "",
      "href": "https://schemas.inorbit.hr/sensors/consent/",
      "latest": 0,
      "versions": [
        {
          "major": 0,
          "id": "https://schemas.inorbit.hr/sensors/consent/v0.json",
          "status": "draft"
        }
      ],
      "fields": [
        "consent_id",
        "account_id",
        "client",
        "granted_by",
        "sources",
        "kinds",
        "sensor_ids",
        "scope",
        "granted_at",
        "expires_at",
        "revoked_at",
        "revoked_by",
        "note",
        "version"
      ]
    },
    {
      "path": "sensors/ingest",
      "area": "sensors",
      "name": "ingest",
      "title": "Sensor ingest request",
      "description": "The body a producer posts to Ingest (POST /v1/atlas/signals): readings from one sensor, at most 500, each accepted or refused on its own (send an Idempotency-Key header to make a retry safe). A reading is a produced_at, exactly one of a number (value) or a state word (state), labels from the sensor's label_keys, and optionally the digest of evidence the producer keeps. It carries no content: no text, prompt, document or credential, and every object is closed so a field outside these is refused. Only the sensor's producer may write, a paused or revoked sensor refuses, and a built-in sensor is read only: the service decides those, the schema cannot.",
      "status": "draft",
      "owner": "",
      "replaced_by": "",
      "href": "https://schemas.inorbit.hr/sensors/ingest/",
      "latest": 0,
      "versions": [
        {
          "major": 0,
          "id": "https://schemas.inorbit.hr/sensors/ingest/v0.json",
          "status": "draft"
        }
      ],
      "fields": [
        "sensor_id",
        "schema_version",
        "account_id",
        "readings"
      ]
    },
    {
      "path": "sensors/reading",
      "area": "sensors",
      "name": "reading",
      "title": "Sensor reading",
      "description": "One reading of a sensor as Readings (GET /v1/atlas/sensors/{sensor_id}/readings, raw) and the live signal stream return it (JSON field names as the API writes them): when it was produced and received, a number or a state word, labels, and the digest of evidence the producer keeps. A reading carries no content: no text, prompt, document or credential, and the object is closed so a field outside these is refused. A registered sensor's reading holds a value or a state, never both; a built-in sensor's reading (builtin. or mon_) is derived: a monitor's holds its latest latency as the value and its verdict as the state, either may be absent before its first run, and there is no cursor. Fields the API leaves at their default (an empty string, false, an empty object) may be absent. The shared definitions below (state_word, label_key, label_value, labels, evidence_digest, timestamp, sensor_id) are the ones the ingest schema refers to, so a reading sent and a reading read cannot drift.",
      "status": "draft",
      "owner": "",
      "replaced_by": "",
      "href": "https://schemas.inorbit.hr/sensors/reading/",
      "latest": 0,
      "versions": [
        {
          "major": 0,
          "id": "https://schemas.inorbit.hr/sensors/reading/v0.json",
          "status": "draft"
        }
      ],
      "fields": [
        "sensor_id",
        "produced_at",
        "received_at",
        "value",
        "state",
        "labels",
        "evidence_digest",
        "skewed",
        "cursor"
      ]
    },
    {
      "path": "sensors/sensor",
      "area": "sensors",
      "name": "sensor",
      "title": "Sensor",
      "description": "One sensor as Get (GET /v1/atlas/sensors/{sensor_id}, under \"sensor\"), List (GET /v1/atlas/sensors, inside each of \"groups\"[].\"sensors\"), Register and the pause, resume and revoke calls return it (JSON field names as the API writes them). A sensor is a named source of readings: what it is, who produces it, how often it reports and whether it is healthy. It carries no content: no text, prompt, document or credential, and the object is closed so a field outside these is refused. Every id carries its prefix (sen_ for a registered sensor, mon_ for a monitor, builtin. for a derived count); a bare UUID is never a sensor id. Fields the API leaves at their default (an empty string, 0, false) are present.",
      "status": "draft",
      "owner": "",
      "replaced_by": "",
      "href": "https://schemas.inorbit.hr/sensors/sensor/",
      "latest": 0,
      "versions": [
        {
          "major": 0,
          "id": "https://schemas.inorbit.hr/sensors/sensor/v0.json",
          "status": "draft"
        }
      ],
      "fields": [
        "sensor_id",
        "account_id",
        "owner",
        "producer_kind",
        "producer_ref",
        "kind",
        "name",
        "unit",
        "source",
        "schema_version",
        "state",
        "interval_seconds",
        "health",
        "rate_per_minute",
        "last_seen_at",
        "label_keys",
        "builtin",
        "created_at",
        "revoked_at"
      ]
    }
  ]
}
