Sub-Agents

Sub-Agents sind Hintergrund-Agent-Runs, die aus einem bestehenden Agent-Run gespawnt werden. Sie laufen in ihrer eigenen Session (agent:<agentId>:subagent:<uuid>) und melden nach Abschluss ihr Ergebnis an den anfragenden Chat-Kanal zurück.

Slash-Befehl

Verwende /subagents, um Sub-Agent-Runs für die aktuelle Session zu inspizieren oder zu steuern:

  • /subagents list
  • /subagents kill <id|#|all>
  • /subagents log <id|#> [limit] [tools]
  • /subagents info <id|#>
  • /subagents send <id|#> <message>
  • /subagents steer <id|#> <message>
  • /subagents spawn <agentId> <task> [--model <model>] [--thinking <level>]

Thread-Bindungs-Steuerung:

Diese Befehle funktionieren auf Kanälen, die persistente Thread-Bindungen unterstützen. Siehe Thread-unterstützende Kanäle unten.

  • /focus <subagent-label|session-key|session-id|session-label>
  • /unfocus
  • /agents
  • /session idle <duration|off>
  • /session max-age <duration|off>

/subagents info zeigt Run-Metadaten (Status, Zeitstempel, Session-ID, Transkript-Pfad, Cleanup).

Spawn-Verhalten

/subagents spawn startet einen Hintergrund-Sub-Agent als Benutzerbefehl, nicht als internes Relay, und sendet ein einziges finales Abschluss-Update zurück an den anfragenden Chat, wenn der Run beendet ist.

  • Der Spawn-Befehl ist nicht-blockierend; er gibt sofort eine Run-ID zurück.
  • Bei Abschluss meldet der Sub-Agent eine Zusammenfassungs-/Ergebnisnachricht an den anfragenden Chat-Kanal.
  • Für manuelle Spawns ist die Zustellung resilient:
    • OpenClaw versucht zuerst direkte agent-Zustellung mit einem stabilen Idempotency-Key.
    • Bei Fehlschlag der direkten Zustellung wird auf Queue-Routing zurückgefallen.
    • Wenn Queue-Routing noch nicht verfügbar ist, wird das Announce mit kurzem exponentiellem Backoff wiederholt, bevor es aufgegeben wird.
  • Der Completion-Handoff an die anfragende Session ist runtime-generierter interner Kontext (nicht benutzergeschriebener Text) und enthält:
    • Result (assistant-Antworttext oder letztes toolResult, wenn die Assistant-Antwort leer ist)
    • Status (completed successfully / failed / timed out / unknown)
    • kompakte Runtime-/Token-Stats
    • eine Zustellungsanweisung, die dem anfragenden Agent sagt, in normaler Assistenten-Stimme umzuschreiben (nicht rohe interne Metadaten weiterleiten)
  • --model und --thinking überschreiben Defaults für diesen spezifischen Run.
  • Verwende info/log, um Details und Ausgabe nach Abschluss zu inspizieren.
  • /subagents spawn ist One-Shot-Modus (mode: "run"). Für persistente Thread-gebundene Sessions verwende sessions_spawn mit thread: true und mode: "session".
  • Für ACP-Harness-Sessions (Codex, Claude Code, Gemini CLI) verwende sessions_spawn mit runtime: "acp" und siehe ACP Agents.

Hauptziele:

  • “Recherche / lange Aufgabe / langsames Tool”-Arbeit parallelisieren, ohne den Haupt-Run zu blockieren.
  • Sub-Agents standardmäßig isoliert halten (Session-Trennung + optionales Sandboxing).
  • Die Tool-Oberfläche schwer missbrauchbar halten: Sub-Agents bekommen standardmäßig keine Session-Tools.
  • Konfigurierbare Verschachtelungstiefe für Orchestrator-Muster unterstützen.

Kostenhinweis: Jeder Sub-Agent hat seinen eigenen Kontext und Token-Verbrauch. Für schwere oder repetitive Aufgaben setze ein günstigeres Modell für Sub-Agents und behalte deinen Haupt-Agent auf einem hochwertigeren Modell. Das kannst du über agents.defaults.subagents.model oder pro-Agent-Overrides konfigurieren.

Tool

Verwende sessions_spawn:

  • Startet einen Sub-Agent-Run (deliver: false, globale Lane: subagent)
  • Führt dann einen Announce-Schritt aus und postet die Announce-Antwort in den anfragenden Chat-Kanal
  • Standard-Modell: erbt vom Aufrufer, es sei denn, du setzt agents.defaults.subagents.model (oder pro Agent agents.list[].subagents.model); ein explizites sessions_spawn.model gewinnt trotzdem.
  • Standard-Thinking: erbt vom Aufrufer, es sei denn, du setzt agents.defaults.subagents.thinking (oder pro Agent agents.list[].subagents.thinking); ein explizites sessions_spawn.thinking gewinnt trotzdem.
  • Standard-Run-Timeout: Wenn sessions_spawn.runTimeoutSeconds weggelassen wird, verwendet OpenClaw agents.defaults.subagents.runTimeoutSeconds falls gesetzt; ansonsten fällt es auf 0 (kein Timeout) zurück.

Tool-Parameter:

  • task (erforderlich)
  • label? (optional)
  • agentId? (optional; unter einer anderen Agent-ID spawnen, wenn erlaubt)
  • model? (optional; überschreibt das Sub-Agent-Modell; ungültige Werte werden übersprungen und der Sub-Agent läuft mit dem Standardmodell mit einer Warnung im Tool-Ergebnis)
  • thinking? (optional; überschreibt das Thinking-Level für den Sub-Agent-Run)
  • runTimeoutSeconds? (Standard ist agents.defaults.subagents.runTimeoutSeconds falls gesetzt, sonst 0; wenn gesetzt, wird der Sub-Agent-Run nach N Sekunden abgebrochen)
  • thread? (Standard false; wenn true, wird eine Kanal-Thread-Bindung für diese Sub-Agent-Session angefordert)
  • mode? (run|session)
    • Standard ist run
    • wenn thread: true und mode weggelassen, wird Standard session
    • mode: "session" erfordert thread: true
  • cleanup? (delete|keep, Standard keep)
  • sandbox? (inherit|require, Standard inherit; require lehnt Spawn ab, es sei denn, die Kind-Runtime ist gesandboxt)
  • sessions_spawn akzeptiert keine Kanal-Zustellungsparameter (target, channel, to, threadId, replyTo, transport). Für die Zustellung verwende message/sessions_send aus dem gespawnten Run.

Thread-gebundene Sessions

Wenn Thread-Bindungen für einen Kanal aktiviert sind, kann ein Sub-Agent an einen Thread gebunden bleiben, sodass Folgenachrichten von Benutzern in diesem Thread weiterhin an dieselbe Sub-Agent-Session geroutet werden.

Thread-unterstützende Kanäle

  • Discord (aktuell der einzige unterstützte Kanal): unterstützt persistente thread-gebundene Subagent-Sessions (sessions_spawn mit thread: true), manuelle Thread-Steuerung (/focus, /unfocus, /agents, /session idle, /session max-age) und Adapter-Keys channels.discord.threadBindings.enabled, channels.discord.threadBindings.idleHours, channels.discord.threadBindings.maxAgeHours und channels.discord.threadBindings.spawnSubagentSessions.

Schneller Ablauf:

  1. Spawne mit sessions_spawn und thread: true (und optional mode: "session").
  2. OpenClaw erstellt oder bindet einen Thread an dieses Session-Ziel im aktiven Kanal.
  3. Antworten und Folgenachrichten in diesem Thread werden an die gebundene Session geroutet.
  4. Verwende /session idle, um Inaktivitäts-Auto-Unfocus zu inspizieren/aktualisieren, und /session max-age für das harte Limit.
  5. Verwende /unfocus zum manuellen Trennen.

Manuelle Steuerung:

  • /focus <target> bindet den aktuellen Thread (oder erstellt einen) an ein Sub-Agent/Session-Ziel.
  • /unfocus entfernt die Bindung für den aktuell gebundenen Thread.
  • /agents listet aktive Runs und Bindungsstatus auf (thread:<id> oder unbound).
  • /session idle und /session max-age funktionieren nur für fokussierte gebundene Threads.

Config-Schalter:

  • Globaler Standard: session.threadBindings.enabled, session.threadBindings.idleHours, session.threadBindings.maxAgeHours
  • Kanal-Override und Spawn-Auto-Bind-Keys sind adapter-spezifisch. Siehe Thread-unterstützende Kanäle oben.

Siehe Konfigurationsreferenz und Slash-Befehle für aktuelle Adapter-Details.

Allowlist:

  • agents.list[].subagents.allowAgents: Liste von Agent-IDs, die über agentId angesprochen werden können (["*"] für beliebige). Standard: nur der anfragende Agent.
  • Sandbox-Vererbungsschutz: Wenn die anfragende Session gesandboxt ist, lehnt sessions_spawn Ziele ab, die ungesandboxt laufen würden.

Entdeckung:

  • Verwende agents_list, um zu sehen, welche Agent-IDs aktuell für sessions_spawn erlaubt sind.

Auto-Archivierung:

  • Sub-Agent-Sessions werden automatisch nach agents.defaults.subagents.archiveAfterMinutes archiviert (Standard: 60).
  • Die Archivierung verwendet sessions.delete und benennt das Transkript in *.deleted.<timestamp> um (gleicher Ordner).
  • cleanup: "delete" archiviert sofort nach dem Announce (behält das Transkript aber per Umbenennung).
  • Auto-Archivierung ist Best-Effort; ausstehende Timer gehen verloren, wenn das Gateway neu startet.
  • runTimeoutSeconds archiviert nicht automatisch; es stoppt nur den Run. Die Session bleibt bis zur Auto-Archivierung.
  • Auto-Archivierung gilt gleichermaßen für Tiefe-1 und Tiefe-2 Sessions.

Verschachtelte Sub-Agents

Standardmäßig können Sub-Agents keine eigenen Sub-Agents spawnen (maxSpawnDepth: 1). Du kannst eine Verschachtelungsebene aktivieren, indem du maxSpawnDepth: 2 setzt, was das Orchestrator-Muster erlaubt: Main → Orchestrator-Sub-Agent → Worker-Sub-Sub-Agents.

Wie aktivieren

{
  agents: {
    defaults: {
      subagents: {
        maxSpawnDepth: 2, // Sub-Agents dürfen Kinder spawnen (Standard: 1)
        maxChildrenPerAgent: 5, // max. aktive Kinder pro Agent-Session (Standard: 5)
        maxConcurrent: 8, // globale Concurrency-Lane-Cap (Standard: 8)
        runTimeoutSeconds: 900, // Standard-Timeout für sessions_spawn wenn weggelassen (0 = kein Timeout)
      },
    },
  },
}

Tiefenebenen

TiefeSession-Key-FormRolleKann spawnen?
0agent:<id>:mainHaupt-AgentImmer
1agent:<id>:subagent:<uuid>Sub-Agent (Orchestrator bei Tiefe 2 erlaubt)Nur wenn maxSpawnDepth >= 2
2agent:<id>:subagent:<uuid>:subagent:<uuid>Sub-Sub-Agent (Leaf Worker)Nie

Announce-Kette

Ergebnisse fließen die Kette hinauf zurück:

  1. Tiefe-2 Worker beendet → meldet an seinen Parent (Tiefe-1 Orchestrator)
  2. Tiefe-1 Orchestrator empfängt das Announce, synthetisiert Ergebnisse, beendet → meldet an Main
  3. Haupt-Agent empfängt das Announce und liefert an den Benutzer

Jede Ebene sieht nur Announces von ihren direkten Kindern.

Tool-Policy nach Tiefe

  • Rolle und Steuerungsbereich werden beim Spawnen in die Session-Metadaten geschrieben. Das verhindert, dass flache oder wiederhergestellte Session-Keys versehentlich Orchestrator-Privilegien zurückerhalten.
  • Tiefe 1 (Orchestrator, wenn maxSpawnDepth >= 2): Bekommt sessions_spawn, subagents, sessions_list, sessions_history, damit er seine Kinder verwalten kann. Andere Session-/System-Tools bleiben gesperrt.
  • Tiefe 1 (Leaf, wenn maxSpawnDepth == 1): Keine Session-Tools (aktuelles Standardverhalten).
  • Tiefe 2 (Leaf Worker): Keine Session-Tools — sessions_spawn ist auf Tiefe 2 immer gesperrt. Kann keine weiteren Kinder spawnen.

Pro-Agent-Spawn-Limit

Jede Agent-Session (auf jeder Tiefe) kann maximal maxChildrenPerAgent (Standard: 5) aktive Kinder gleichzeitig haben. Das verhindert unkontrolliertes Fan-Out von einem einzelnen Orchestrator.

Kaskaden-Stopp

Das Stoppen eines Tiefe-1 Orchestrators stoppt automatisch alle seine Tiefe-2 Kinder:

  • /stop im Haupt-Chat stoppt alle Tiefe-1 Agents und kaskadiert zu ihren Tiefe-2 Kindern.
  • /subagents kill <id> stoppt einen bestimmten Sub-Agent und kaskadiert zu seinen Kindern.
  • /subagents kill all stoppt alle Sub-Agents des Anfragenden und kaskadiert.

Authentifizierung

Sub-Agent-Auth wird nach Agent-ID aufgelöst, nicht nach Session-Typ:

  • Der Sub-Agent-Session-Key ist agent:<agentId>:subagent:<uuid>.
  • Der Auth-Store wird aus dem agentDir dieses Agents geladen.
  • Die Auth-Profile des Haupt-Agents werden als Fallback eingemischt; Agent-Profile überschreiben Haupt-Profile bei Konflikten.

Hinweis: Der Merge ist additiv, so dass Haupt-Profile immer als Fallbacks verfügbar sind. Vollständig isolierte Auth pro Agent wird noch nicht unterstützt.

Announce

Sub-Agents melden sich über einen Announce-Schritt zurück:

  • Der Announce-Schritt läuft innerhalb der Sub-Agent-Session (nicht der anfragenden Session).
  • Wenn der Sub-Agent genau ANNOUNCE_SKIP antwortet, wird nichts gepostet.
  • Ansonsten hängt die Zustellung von der Tiefe des Anfragenden ab:
    • Top-Level-anfragende Sessions verwenden einen Folge-agent-Call mit externer Zustellung (deliver=true)
    • verschachtelte anfragende Subagent-Sessions erhalten eine interne Folge-Injektion (deliver=false), damit der Orchestrator Kind-Ergebnisse in-Session synthetisieren kann
    • wenn eine verschachtelte anfragende Subagent-Session nicht mehr existiert, fällt OpenClaw auf den Anfragenden dieser Session zurück, wenn verfügbar
  • Kind-Completion-Aggregation ist auf den aktuellen Anfragenden-Run beschränkt, wenn verschachtelte Completion-Findings erstellt werden, um zu verhindern, dass veraltete Prior-Run-Kind-Outputs in das aktuelle Announce einfließen.
  • Announce-Antworten bewahren Thread-/Topic-Routing, wenn auf Kanal-Adaptern verfügbar.
  • Announce-Kontext wird zu einem stabilen internen Event-Block normalisiert:
    • Quelle (subagent oder cron)
    • Kind-Session-Key/ID
    • Announce-Typ + Task-Label
    • Statuszeile, abgeleitet vom Runtime-Ergebnis (success, error, timeout oder unknown)
    • Ergebnisinhalt vom Announce-Schritt (oder (no output) wenn fehlend)
    • eine Follow-Up-Anweisung, die beschreibt, wann zu antworten vs. still zu bleiben
  • Status wird nicht aus der Modellausgabe abgeleitet; er kommt von Runtime-Ergebnissignalen.

Announce-Payloads enthalten eine Stats-Zeile am Ende (auch wenn gewrappt):

  • Runtime (z.B. runtime 5m12s)
  • Token-Verbrauch (Input/Output/Gesamt)
  • Geschätzte Kosten, wenn Modellpreise konfiguriert sind (models.providers.*.models[].cost)
  • sessionKey, sessionId und Transkript-Pfad (damit der Haupt-Agent History über sessions_history abrufen oder die Datei auf der Festplatte inspizieren kann)
  • Interne Metadaten sind nur für die Orchestrierung gedacht; benutzerseitige Antworten sollten in normaler Assistenten-Stimme umgeschrieben werden.

Tool-Policy (Sub-Agent-Tools)

Standardmäßig bekommen Sub-Agents alle Tools außer Session-Tools und System-Tools:

  • sessions_list
  • sessions_history
  • sessions_send
  • sessions_spawn

Wenn maxSpawnDepth >= 2, erhalten Tiefe-1-Orchestrator-Sub-Agents zusätzlich sessions_spawn, subagents, sessions_list und sessions_history, damit sie ihre Kinder verwalten können.

Override über Config:

{
  agents: {
    defaults: {
      subagents: {
        maxConcurrent: 1,
      },
    },
  },
  tools: {
    subagents: {
      tools: {
        // deny gewinnt
        deny: ["gateway", "cron"],
        // wenn allow gesetzt ist, wird es allow-only (deny gewinnt trotzdem)
        // allow: ["read", "exec", "process"]
      },
    },
  },
}

Nebenläufigkeit

Sub-Agents verwenden eine dedizierte In-Process-Queue-Lane:

  • Lane-Name: subagent
  • Nebenläufigkeit: agents.defaults.subagents.maxConcurrent (Standard 8)

Stoppen

  • Das Senden von /stop im anfragenden Chat bricht die anfragende Session ab und stoppt alle aktiven Sub-Agent-Runs, die daraus gespawnt wurden, mit Kaskadierung zu verschachtelten Kindern.
  • /subagents kill <id> stoppt einen bestimmten Sub-Agent und kaskadiert zu seinen Kindern.

Einschränkungen

  • Sub-Agent-Announce ist Best-Effort. Wenn das Gateway neu startet, geht ausstehende “Announce-Back”-Arbeit verloren.
  • Sub-Agents teilen sich weiterhin die gleichen Gateway-Prozess-Ressourcen; behandle maxConcurrent als Sicherheitsventil.
  • sessions_spawn ist immer nicht-blockierend: es gibt sofort { status: "accepted", runId, childSessionKey } zurück.
  • Sub-Agent-Kontext injiziert nur AGENTS.md + TOOLS.md (kein SOUL.md, IDENTITY.md, USER.md, HEARTBEAT.md oder BOOTSTRAP.md).
  • Maximale Verschachtelungstiefe ist 5 (maxSpawnDepth-Bereich: 1—5). Tiefe 2 wird für die meisten Anwendungsfälle empfohlen.
  • maxChildrenPerAgent begrenzt aktive Kinder pro Session (Standard: 5, Bereich: 1—20).