Caldera docs
calderaapp.io

Das Agent-Protokoll

Wie ein Agent mit Caldera spricht. Diese Seite ist die verbindliche Beschreibung von Protokoll-Version 1: Wer einen eigenen Reporter schreibt, baut gegen sie. Sie ist zugleich die API von Caldera, denn Caldera hat keine öffentliche REST-API für Skripte.

Die Form in einem Absatz

Ein Agent meldet sich selbst, in festem Abstand (standardmäßig 30 Sekunden), über HTTPS, nach außen. Caldera verbindet sich nie mit dem Rechner eines Agents. Befehle (pausieren, jetzt ausführen, eine Einstellung ändern, ein Log senden) kommen in der Antwort auf eine Meldung zurück. Der Agent prüft jeden gegen seine eigenen festen Grenzen, wendet ihn an oder lehnt ihn ab und sagt in einer späteren Meldung, was er getan hat. Auf dem Rechner des Agents lauscht nichts.

Regeln für einen Reporter

Sie machen einen Agent von Caldera unabhängig. Ein Reporter, der eine davon bricht, ist falsch, auch wenn alles funktioniert.

  1. Der Reporter liegt nicht im Steuerpfad des Agents. Der Agent startet Läufe, wählt seine Arbeit und hält von selbst an. Er wartet nie auf Caldera, fragt nie um Erlaubnis und nimmt nie Arbeit von dort.
  2. Der Reporter scheitert für sich. Als eigener Prozess betreiben (ein systemd-User-Service, ein Sidecar). Bei jeder Anfrage ein Timeout setzen. Ist Caldera nicht erreichbar, langsam oder antwortet unsinnig: loggen, das nächste Intervall abwarten, erneut versuchen; sonst ändert sich nichts.
  3. Der Zustand des Agents liegt auf dem Rechner des Agents. Pause, Grenzen, Zeitplan und Einstellungen sind die eigenen Dateien des Agents. Was Caldera zeigt, ist eine Kopie der letzten Meldung.
  4. Alles, was Caldera kann, ist ohne Caldera erreichbar und umkehrbar. Eine aus Caldera gesetzte Pause ist dieselbe Pause, die der eigene Kanal des Agents setzt und aufhebt.
  5. Ein Befehl ist ein Wunsch. Gegen die eigenen harten Grenzen des Agents prüfen, anwenden oder ablehnen und antworten. Eine Ablehnung ist eine normale Antwort.
  6. Nur senden, was die Seite zeigen soll. Zustand, Zahlen, Titel. Inhalte privater Daten (Mails, Nachrichten) bleiben beim Agent. Logs sind die einzige Ausnahme, und der Agent entscheidet, welche Logs er herausgibt.

Authentifizierung

Authorization: Bearer caldera_agt_…

Ein Token gehört zu genau einem Agent. Ein Admin legt den Agent in Caldera an (oder erneuert sein Token) und sieht das Token einmal. Es erreicht für diesen Agent die unten beschriebenen Routen für Meldung und Log und, bei einem aus einem Blueprint installierten Agent, die Bundle-Route des eigenen Blueprints, und sonst nichts. Es ist kein persönliches Zugriffstoken und handelt für niemanden.

Die Basis-URL ist der Ursprung der Caldera-App selbst, https://app.calderaapp.io. Die Routen antworten nur an diesem Ursprung.

POST /api/agent/v1/report

Der ganze aktuelle Zustand des Agents. Jedes Feld außer protocol ist optional; was fehlt, zeigt Caldera nicht. Ein null gilt als fehlend, ein Reporter darf ein ungesetztes Feld also so oder so senden; die eine Ausnahme ist settings.values, wo null bedeutet "diese Einstellung ist nicht gesetzt" und erhalten bleibt. Zeiten sind Unix-Sekunden, Anteile Zahlen von 0 bis 1.

{
  "protocol": 1,
  "agent": { "version": "1c1f3c5", "host": "build-1" },
  "state": { "level": "ok", "label": "Ready", "detail": "waiting for work" },
  "health": [{ "name": "Chat bot", "level": "ok", "detail": "connected" }],
  "active": [
    {
      "kind": "Run",
      "model": "Opus",
      "started": 1791030000,
      "steps": 37,
      "detail": "last tool: Bash",
      "subjects": [{ "title": "…", "url": "https://…" }],
      "log": "run-20261003-124101.log"
    }
  ],
  "gauges": [{ "name": "Week", "used": 0.52, "mark": 0.7, "detail": "limit today 70 %" }],
  "runs": [
    {
      "id": "run-20261003-124101",
      "started": 1791024061,
      "ended": 1791024725,
      "kind": "Run",
      "status": "ok",
      "cost_usd": 2.51,
      "output_tokens": 22000,
      "models": { "Opus": 2.51 },
      "subjects": [{ "title": "…", "url": "…", "share": 1.0 }],
      "log": "run-20261003-124101.log"
    }
  ],
  "panels": [
    {
      "title": "Questions for you",
      "type": "list",
      "items": [{ "title": "…", "url": "…", "meta": "…" }]
    }
  ],
  "settings": {
    "schema": [
      {
        "key": "max_7d",
        "label": "Weekly limit",
        "type": "percent",
        "min": 0.1,
        "max": 0.95,
        "help": "…",
        "group": "Quota"
      }
    ],
    "values": { "max_7d": 0.75 }
  },
  "controls": ["pause", "resume", "run_now"],
  "acks": [{ "id": "3f0c…", "ok": true, "message": "Weekly limit set to 80 %." }]
}
  • level: ok, info, warn oder bad. Ein unbekannter Level wird als info gelesen.
  • runs: die letzten Läufe. Caldera behält sie (die neuesten 2000 je Agent), ältere Läufe überleben also, wenn der Agent jedes Mal nur wenige sendet. Dieselbe id überschreibt: einen Lauf melden, während er läuft, und noch einmal, wenn er endet.
  • panels: was nur dieser Agent hat, in einer von vier Formen:
    • list: items mit title, optional url, meta, badge, level;
    • table: columns (Überschriften) und rows (Zellen als Text oder {"text", "url"});
    • kv: items mit label und value;
    • text: lines.
  • settings.schema[].type: percent, number, bool, datetime (Unix-Sekunden), text, select (mit options: [{"value", "label"}]).
  • controls: die Knöpfe, die Caldera zeigen darf. Unbekannte Einträge werden verworfen.
  • acks: Antworten auf Befehle aus früheren Meldungen.

Alles ist Text. Caldera stellt jede Zeichenkette als Text dar, nie als Markup. Links bleiben nur erhalten, wenn sie mit http:// oder https:// beginnen; alles andere wird verworfen, der Titel bleibt.

Größen. Eine Meldung darf höchstens 256 KB groß sein. Zeichenketten und Listen über ihrer Obergrenze werden gekürzt, nicht abgelehnt (zum Beispiel ein Label bei 80 Zeichen, ein Detail bei 300, eine Liste von Gesundheitseinträgen bei 50). Eine Meldung, die kein gültiges JSON ist, kein Objekt ist oder ein anderes protocol nennt, wird mit 400 abgelehnt. Unbekannte Felder werden ignoriert, ein neuerer Reporter kann also mit einem älteren Server sprechen.

Die Antwort

{ "commands": [{ "id": "3f0c…", "type": "set", "payload": { "max_7d": 0.8 } }], "interval": 30 }
  • interval: das Meldeintervall, das Caldera erbittet, in Sekunden. Auf einen eigenen Bereich begrenzen.
  • commands, jeweils einer von:
    • pause, resume, run_now, mit leerem payload;
    • set: Einstellungswerte, nur Schlüssel aus dem Schema, das der Agent gemeldet hat. Caldera prüft Typ und Grenzen gegen dieses Schema, bevor es einen Befehl sendet; der Agent prüft erneut und entscheidet;
    • log: {"name": "<log>"}, einer der Log-Namen, die der Agent gemeldet hat. Dieses Log an POST /api/agent/v1/log senden; ein Ack ist nicht nötig, der Upload ist die Antwort.

Die id eines Befehls ist eine undurchsichtige Zeichenkette. Zurückgeben, nicht auswerten.

Ein Befehl wird höchstens einmal zugestellt. Geht die Antwort auf eine Meldung verloren, geht der Befehl mit ihr verloren, und Caldera lässt ihn fehlschlagen, wenn nach zehn Minuten keine Antwort gekommen ist. Das ist Absicht: run_now darf nie zweimal laufen, nur weil ein Netz eine Antwort verloren hat. Eine Person kann ihn erneut senden.

POST /api/agent/v1/log

{ "command": "3f0c…", "name": "run-20261003-124101.log", "text": "…" }

Höchstens 512 KB Text: das Ende des Logs senden. Caldera behält es 30 Tage, und nur Admins des Workspace können es lesen.

Fehler

Jeder Fehler ist ein JSON-Umschlag {"error": {"code", "message"}}.

Status Wann
400 Der Body ist keine gültige Meldung und kein gültiger Log-Upload.
401 Kein Agent-Token, ein unbekanntes oder eines, das erneuert oder gelöscht wurde.
403 Der Workspace ist für Caldera nicht freigeschaltet.
404 Die Route wurde an einer Adresse aufgerufen, die nicht Calderas eigene ist, oder das Log nennt einen unbekannten Befehl.
413 Der Body ist größer, als die Route annimmt.
429 Mehr als 60 Meldungen oder 10 Logs pro Minute von einem Agent.

Keiner davon darf den Agent anhalten. Loggen und im nächsten Intervall erneut versuchen.

Änderungen am Protokoll

Version 1 wächst additiv oder gar nicht: ein neues optionales Feld, ein neuer Panel-Typ, ein neuer Befehlstyp, der ohne Caldera erreichbar und umkehrbar ist. Eine Änderung, die einen ausgelieferten Reporter brechen würde, ist Version 2, unter einem neuen Pfad, wobei Version 1 bleibt, bis ihre Reporter umgezogen sind.

Ergänzungen für Blueprints

Jede Ergänzung unten ist optional: Ein einfacher Reporter der Version 1, der nichts davon sendet oder liest, funktioniert weiter. Die Runtime caldera.pyz spricht alles davon; ein eigener Reporter braucht nichts davon.

In der Meldung: applied

{ "applied": { "version": "1.1.0", "outcome": "ok", "message": "updated to 1.1.0" } }
  • version: die Blueprint-Version, die der Agent jetzt ausführt, die, die funktioniert.
  • outcome des letzten Update-Versuchs des Agents: ok, rolled_back (die neue Version hat die Gesundheitsprüfung nicht bestanden, oder wurde im Zeitfenster schlechter, oder eine Person hat caldera rollback ausgeführt: der Agent ist zurück auf der alten) oder failed (nichts hat sich geändert: das Bundle konnte nicht geholt werden, wurde abgelehnt, oder ein Update wurde unterbrochen und zurückgenommen).
  • message: eine Zeile, höchstens 300 Zeichen, Text. Vor dem ersten Update lautet sie installed.

Es wird in jeder Meldung gesendet, damit das letzte Ergebnis nicht an einer fehlgeschlagenen Meldung verloren geht. agent.version trägt dieselbe Version.

In der Antwort: desired

{ "commands": [], "interval": 30, "desired": { "blueprint": "ops-agent", "version": "1.1.0" } }

Die Version, die Caldera den Agent ausführen lassen möchte. Der Agent wendet sie an, wenn er sie noch nicht ausführt, blueprint sein eigener ist und version eine Semantic Version ist (alles andere wird ignoriert und nie als Pfad benutzt). Eine Version, von der der Agent zurückgerollt hat oder die er abgelehnt hat, wird nicht erneut angewendet, bis desired eine andere nennt: sonst würde die nächste Meldung ein lokales caldera rollback rückgängig machen. Ein fehlgeschlagener Abruf (Caldera nicht erreichbar) ist die Ausnahme: er wird nach zehn Minuten wiederholt. Um aus Caldera zurückzurollen, wird in desired die vorherige Version genannt.

Caldera sendet desired, solange der Wunsch eines Admins besteht, und lässt es sonst weg.

GET /api/agent/v1/bundle/:version

Die Dateien einer Version des eigenen Blueprints des Agents. Authorization: Bearer caldera_agt_…; die Version eines anderen Blueprints antwortet 404, ebenso eine unbekannte.

  • 200, Content-Type: application/zip, Body: das Bundle (unten), und X-Caldera-Sha256: <hex>, die Prüfsumme des Bodys. Der Agent lehnt einen Body ab, der nicht passt.
  • Das Bundle enthält die Dateien des Blueprints und sonst nichts: keine Geheimnisse, kein agent.env. Die gibt es nur in der Install-Antwort.
  • Höchstens 20 MB (die Runtime lehnt Größeres ab).

POST /api/agent/v1/install/preview und POST /api/agent/v1/install

Zwei Aufrufe ohne Token: Der Einmal-Install-Code ist die Berechtigung, einmal gültig, fünfzehn Minuten lang, für eine Installation einer Blueprint-Version. Beide nehmen

{ "code": "caldera_inst_…" }

Zuerst die Vorschau. Sie liest, was der Code installieren würde, und legt nichts an und verbraucht nichts, damit die CLI nach den Geheimnissen fragen und ein belegtes Verzeichnis bemerken kann, bevor der Code benutzt wird. Antwort 200:

{
  "blueprint": "ops-agent",
  "version": "1.0.0",
  "description": "…",
  "agentName": "ops-agent-1",
  "runtime": "process",
  "secrets": [{ "name": "SERVICE_KEY", "purpose": "…", "optional": true }],
  "bindings": [{ "product": "<product id>", "role": "member", "scopes": ["content:read"] }]
}

Weder ein Geheimniswert noch ein Token noch ein Dateiname steht darin. agentName wird zum Verzeichnisnamen: Kleinbuchstaben, Ziffern und Bindestriche.

Dann einlösen. Antwort 200, einmalig:

{
  "agent": { "name": "ops-agent-1" },
  "blueprint": "ops-agent",
  "version": "1.0.0",
  "env": {
    "CALDERA_TOKEN": "caldera_agt_…",
    "CALDERA_BINDING_<PRODUCT>_URL": "https://…",
    "CALDERA_BINDING_<PRODUCT>_WORKSPACE": "3f0c…",
    "CALDERA_BINDING_<PRODUCT>_TOKEN": "…"
  },
  "bundle": "<base64 of the zip>",
  "sha256": "<hex of the zip>"
}
  • agent.name ist der der Vorschau. Die Runtime lehnt eine Installation ab, die einen anderen nennt.
  • env wird zu .caldera/agent.env. CALDERA_TOKEN ist das Token des Agents. Jede Anbindung des Manifests fügt drei Variablen hinzu, mit <PRODUCT> als Produkt-ID in Großbuchstaben: CALDERA_BINDING_<PRODUCT>_URL (der Ursprung des Produkts), CALDERA_BINDING_<PRODUCT>_WORKSPACE (die Workspace-ID, zu der der Bot gehört; die API des Produkts adressiert sie per ID) und CALDERA_BINDING_<PRODUCT>_TOKEN (das Token des Bots, ein Jahr gültig, für dieses Produkt gestempelt). CALDERA_URL schreibt die Runtime aus der Adresse, die ihr genannt wurde. Namen sind [A-Z][A-Z0-9_]*; ein Wert mit Zeilenumbruch wird abgelehnt.
  • Das Bundle ist das Archiv der Version, Byte für Byte, und sha256 gilt für genau diese Bytes. Es ist dasselbe Archiv, das GET /bundle/:version später ausliefert.
  • Ein unbekannter, abgelaufener und benutzter Code bekommen dieselbe Antwort 404, bei beiden Aufrufen, damit sich ein Code nicht abtasten lässt. Begrenzt je Adresse (429): zwanzig Aufrufe pro Minute, beide zusammen.
  • Das Einlösen ist eine Transaktion: Sie beansprucht den Code, legt den Agent an und legt je Anbindung einen Bot an (oder verwendet einen gleichnamigen wieder), mit je einem Token. Eine Ablehnung rollt alles zurück, und der Code bleibt benutzbar: 403, wenn ein angebundenes Produkt für den Workspace nicht freigeschaltet ist oder die Person, die den Code ausgestellt hat, keine Agents mehr installieren darf; 409, wenn der Workspace mehr als zehn Bots hätte, wenn ein Bot dieses Namens mit anderer Rolle existiert oder wenn der Workspace schon einen Agent dieses Namens hat. Die Nachricht sagt, welcher Fall es ist.
  • Ein nicht eingelöster Code hinterlässt keinen Agent, und da die Vorschau zuerst kommt, auch kein Setup, das bei der Abfrage der Geheimnisse abgebrochen wird. Nach dem Einlösen kann noch die Arbeit des Rechners selbst scheitern (Entpacken, Dateien schreiben); die Runtime sagt dann, dass der Agent in Caldera ohne Rechner existiert, und eine Person löscht ihn dort und stellt einen neuen Code aus.

Was die Runtime über Anbindungen meldet

Für jede Anbindung fügt die Runtime ihrer Meldung einen Gesundheitseintrag Binding <product> hinzu, höchstens einmal in fünf Minuten, aus einer Anfrage an das Produkt mit dem Token des Bots: GET <url>/api/v1/workspaces/<workspace>. ok bei 200 und bei 403 (ein Token, dessen Scopes dieses Lesen nicht abdecken, funktioniert trotzdem); bad bei 401 (widerrufenes, abgelaufenes oder gelöschtes Token) und 404 (der Bot ist kein Mitglied mehr); warn, wenn das Produkt nicht erreichbar ist. Caldera zeigt bad als defekte Anbindung am Agent; nur die eigenen Einstellungen des Produkts können sie reparieren. Diese Einträge zählen nie zum eigenen Level des Agents für das Rollback-Zeitfenster.

GET /cli/caldera.pyz

Die CLI und Runtime selbst, von der App am Ursprung von Caldera ausgeliefert (ohne Token: Das Archiv ist für alle gleich und enthält kein Geheimnis), mit /cli/caldera.pyz.sha256 daneben (<hex> caldera.pyz) und /cli/caldera.pyz.sig, der OpenSSH-Signatur des Releases (Namespace caldera-runtime) genau dieser Bytes, die eine Runtime prüft, bevor sie sich ersetzt. Die Signatur antwortet 404, wenn der Build nicht signiert wurde. Die Release-Version, für die das Archiv gebaut wurde, nennt die Antwort als runtime.version. Alle drei antworten 404 an jeder anderen Adresse als Calderas eigener.

Das Bundle

Ein Zip-Archiv mit caldera.agent.yaml an der Wurzel (das Manifest). Die Runtime behandelt es als nicht vertrauenswürdig und lehnt das ganze Bundle ab, ohne etwas auf der Platte zu hinterlassen, wenn ein Eintrag

  • einen absoluten Pfad, ein ..-Segment, einen Backslash, einen Laufwerksbuchstaben oder ein NUL hat;
  • ein Symlink, ein Gerät oder eine andere nicht reguläre Datei ist;
  • doppelt vorkommt oder unter .caldera/ liegt (dem eigenen Verzeichnis der Runtime);
  • das Archiv mehr als 5000 Einträge hat, entpackt mehr als 100 MB ergibt (beim Entpacken gezählt, nicht aus den Headern gelesen) oder eine Datei mehr als 50 MB ergibt;
  • eine Datei fehlt, die das Manifest nennt (instructions, mcp, eine Compose-Datei), oder das Manifest ungültig ist oder seine Version nicht die ist, nach der gefragt wurde.

Der Server wendet dieselben Regeln beim Hochladen an; die Runtime verlässt sich nicht darauf.

Was die Runtime dem Agent mitgibt

Die Runtime startet den Prozess des Agents (runtime.command, eine Argumentliste, nie eine Shell) in current/<workdir> mit der folgenden Umgebung. Der Agent braucht nichts davon, um zu laufen; so arbeitet er ohne Caldera mit.

Variable Ist
alles in .caldera/agent.env außer CALDERA_TOKEN die Token und URLs der Anbindungen. Der Agent bekommt nie das Token, das für die Runtime spricht.
alles in .caldera/secrets.env die Geheimnisse, die die Person bei caldera init eingegeben hat
CALDERA_SETTING_<KEY> der aktuelle Wert jeder Einstellung (true/false bei bool, leer wenn ungesetzt)
CALDERA_SETTINGS_FILE JSON aller Einstellungen, bei jeder Änderung neu geschrieben
CALDERA_PAUSE_FILE existiert, solange der Agent pausiert; die Runtime stoppt den Prozess, das Prüfen ist also optional
CALDERA_RUN_NOW_FILE von run_now angelegt; der Agent löscht sie, wenn er handelt
CALDERA_STATE_DIR, CALDERA_AGENT_DIR das Zustandsverzeichnis und das Verzeichnis des Agents
CALDERA_AGENT_STARTED Unix-Zeit (Sekunden, 3 Nachkommastellen), zu der dieser Prozess gestartet wurde, für eine Gesundheitsprüfung, die die neue Version arbeiten sehen muss

Der Agent meldet, indem er die JSON-Datei schreibt, die das Manifest als status nennt, in der Form einer Meldung: state, health, active, gauges, runs, panels. Andere Schlüssel werden nicht weitergegeben; eine Datei, die kein Objekt ist, kostet eine Gesundheitszeile. Die Runtime ergänzt agent, settings, controls, acks, applied und einen Gesundheitseintrag Process, und ersetzt state durch Paused oder Not running, wenn das zutrifft.

Was die Runtime mit den Befehlen dieser Seite tut, damit sich der Server darauf verlassen kann:

  • pause/resume: dieselbe Datei .caldera/paused, die caldera pause und caldera resume schreiben. run_now wird abgelehnt, solange pausiert ist. Ein Befehl, den die controls des Manifests nicht anbieten, wird mit einem Ack abgelehnt.
  • set: Jeder Schlüssel muss eine deklarierte Einstellung sein und jeder Wert innerhalb seiner Grenzen, sonst ändert sich nichts. null löscht eine Einstellung nur, wenn das Manifest ihr keinen Standardwert gibt.
  • log: nur im Manifest unter logs deklarierte Namen, nur aus einer Datei, die innerhalb des Agent-Verzeichnisses und außerhalb von .caldera/ aufgelöst wird; alles andere wird mit dem Text There is no such log. beantwortet.

Ein Update ist: holen, neben der laufenden Version bereitstellen, current tauschen (ein atomares Umbenennen), neu starten, health ausführen, behalten oder zurücktauschen. state-Pfade liegen in <dir>/state und sind in jede Version eingelinkt; eine Datei, die ein Bundle an einem State-Pfad mitbringt, ist ein Seed und wird nur kopiert, wenn dort nichts liegt. In den 30 Minuten nach einem Update rollt der Agent sich selbst zurück, wenn sein eigener Gesundheits-Level schlechter wird als zu dem Zeitpunkt, an dem das Update behalten wurde. Ein Prozess, der zwischen zwei Schritten beendet wird, wird beim nächsten Start zurückgenommen oder zu Ende geführt. Nichts davon braucht Caldera, außer dem Abruf.

Ergänzungen für die Runtime selbst

Ebenfalls optional und additiv. Sie betreffen das Programm caldera.pyz, so wie applied die Blueprint-Version betrifft.

In der Meldung: runtime

{
  "runtime": {
    "version": "0.32.0",
    "previous": "0.31.0",
    "pinned": "0.32.0",
    "applied": { "version": "0.32.0", "outcome": "ok", "message": "updated to 0.32.0" }
  }
}
  • version: die Runtime-Version, die jetzt läuft. Die Release-Version des Calderas, das die Datei gebaut hat (dev bei einer Runtime aus dem Quelltext). Pflicht innerhalb von runtime; das Feld runtime selbst ist optional.
  • previous: die daneben aufbewahrte Version, auf die caldera rollback-runtime zurückgeht. Fehlt, wenn es keine gibt.
  • pinned: eine Version, die eine Person auf dem Rechner festgehalten hat (caldera pin-runtime). Solange sie gesetzt ist, aktualisiert sich die Runtime auf keine andere Version, was Caldera auch wünscht. Fehlt, wenn nicht festgehalten.
  • applied: wie der letzte Selbst-Update-Versuch endete, mit den Ergebnissen von applied beim Blueprint (ok, rolled_back, failed), wobei version die ist, die jetzt funktioniert, und message eine Zeile (höchstens 300 Zeichen). Fehlt vor dem ersten Versuch; danach in jeder Meldung gesendet, damit eine verlorene Meldung nichts verliert.

Eine Runtime sendet es in jeder Meldung. Eine alte Runtime sendet keines.

In der Antwort: runtime und runtime_desired

{
  "commands": [],
  "interval": 30,
  "runtime": { "version": "0.32.0", "sha256": "<hex of /cli/caldera.pyz>" },
  "runtime_desired": "0.32.0"
}
  • runtime: die Runtime, die dieses Caldera unter /cli/caldera.pyz ausliefert: ihre Release-Version und die SHA-256 dieser Datei (derselbe Wert wie /cli/caldera.pyz.sha256). Eine Information. Die Seite des Agents zeigt, dass eine neuere Runtime verfügbar ist, wenn sich runtime.version von der eigenen runtime.version des Agents unterscheidet.
  • runtime_desired: ein Wunsch, der nur da ist, solange der Druck eines Admins auf "Runtime aktualisieren" gilt, und sonst fehlt. Die Runtime aktualisiert sich nie ungefragt. Er nennt die Version, die der Agent ausführen soll, nämlich die von runtime. Eine einfache Runtime sieht ihn nie.

Beide Felder stehen nur in der Antwort auf eine Meldung, die runtime trägt: Ein Reporter, der kein runtime sendet, bekommt die Antwort, die er immer bekam. Beide fehlen, wenn dieses Caldera keinen Runtime-Build ausliefert.

Wie Caldera den Wunsch hält. Der Druck speichert die ausgelieferte Version als Wunsch, zusammen mit einer Markierung des letzten runtime.applied des Agents (Ergebnis und Nachricht, nicht die Version) zu diesem Zeitpunkt. Mit jeder Meldung entscheidet Caldera:

Die Meldung zeigt Der Wunsch
Die ausgelieferte Version ist nicht mehr die gewünschte (ein neueres Release hat sie ersetzt) verworfen; runtime_desired nennt nie eine ältere Version als die ausgelieferte
applied seit dem Druck unverändert (eine Runtime in der Probezeit meldet die Version, die sie ausführt, mit dem alten Ergebnis) bleibt bestehen
applied.outcome: ok und runtime.version gleich dem Wunsch erledigt; die Sperre wird gelöscht
applied.outcome: rolled_back oder failed, anders als beim Druck erledigt; die gewünschte Version wird gesperrt

Eine gesperrte Version wird beim nächsten Druck abgelehnt (runtime_version_held), bis Caldera eine andere ausliefert. Der Druck wird außerdem abgelehnt bei einer Runtime, die kein runtime meldet (runtime_too_old), bei einem Caldera ohne Build (runtime_not_served), bei einer Runtime, die schon auf der ausgelieferten Version ist (runtime_up_to_date), und bei einer, die auf eine andere Version festgehalten ist (runtime_pinned). Ein Fehler, der nur am Rechner oder am Netz liegt (kein ssh-keygen, ein fehlgeschlagener Download), wird ebenfalls gesperrt: Die Runtime wiederholt diese von selbst, solange der Wunsch besteht, aber Caldera kann sie nicht von einer abgelehnten Datei unterscheiden, deshalb drückt die Person erneut, nachdem sich das Release geändert hat oder der Rechner repariert ist.

Was die Runtime mit dem Wunsch tut

  1. Ist er gewollt? Der Wunsch wird angewendet, wenn alles zutrifft: runtime_desired ist eine Versionszeichenkette ([0-9A-Za-z][0-9A-Za-z._-]{0,63}, nie als Pfad benutzt), sie ist nicht die laufende Version, nicht die Version, von der die Runtime zurückgerollt hat oder die sie abgelehnt hat (eine Sperre, aufgehoben, wenn runtime_desired eine andere nennt oder die Runtime ersetzt wird), und sie ist nicht durch ein lokales Festhalten ausgeschlossen.
  2. Holen. GET /cli/caldera.pyz und GET /cli/caldera.pyz.sig am Ursprung von Caldera (ohne Token: keines der beiden enthält ein Geheimnis, und die Runtime sendet ihr Token nie dorthin). Die SHA-256 muss gleich der in runtime.sha256 der Antwort sein, wenn diese dieselbe Version nennt, und gleich dem Header X-Caldera-Sha256, wenn er da ist. Die eigene Version der Datei muss gleich dem Wunsch sein.
  3. Die Signatur prüfen, immer, mit ssh-keygen -Y verify -n caldera-runtime -I caldera-release gegen den öffentlichen Schlüssel, der in die Runtime eingebaut ist. Eine falsche oder fehlende Signatur oder kein ssh-keygen: Nichts ändert sich, das Ergebnis ist failed, und die Nachricht sagt, welcher Fall es ist.
  4. Tauschen und neu starten. Die laufende Datei wird als vorherige aufbewahrt, die neue ersetzt sie mit einem Umbenennen, und die Runtime startet sich an Ort und Stelle neu (dieselbe Prozess-ID; die eigenen Prozesse des Agents werden nicht berührt).
  5. Probezeit. Die erste erfolgreiche Meldung der neuen Runtime binnen fünf Minuten macht sie gut (ok). Eine Runtime, die nicht startet, wiederholt abstürzt oder im Zeitfenster nicht erfolgreich meldet, geht von selbst auf die vorherige Datei zurück (rolled_back), und die Version wird gesperrt.

caldera rollback-runtime und caldera pin-runtime <version|off> funktionieren ganz ohne Verbindung. Siehe die Runtime.

In der Meldung: account

{ "account": { "org": "Example Org", "plan": "max", "email": "someone@example.com" } }

Das Claude-Konto, bei dem der Rechner des Agents angemeldet ist. Alle drei Felder sind Text und optional. Siehe Der Hinweis auf das Claude-Konto.