Feature
Feature
Bridge-Agents
A Bridge-Agent is a persistent, addressable A2A endpoint that fronts one persona to the outside world. It answers questions from public content, reveals availability, and takes in requests — always under a hard human gate, never acting on its own. The engine that runs it is generic (CORE); everything that makes it this persona lives in a per-agent instance folder (USER).
Ein Bridge-Agent ist ein persistenter, adressierbarer A2A-Endpunkt, der eine Persona nach außen vertritt. Er beantwortet Fragen aus öffentlichem Inhalt, zeigt Verfügbarkeit und nimmt Anfragen entgegen — stets unter einem harten menschlichen Gate, nie aus eigenem Antrieb handelnd. Die Engine, die ihn betreibt, ist generisch (CORE); alles, was ihn zu dieser Persona macht, lebt in einem Instanz-Ordner pro Agent (USER).
A persistent, addressable A2A endpoint that fronts one persona — under a human gate. Its body is a runnable instance under agents/<name>/, its self is the persona in the system prompt, and its interface is a published AgentCard.
Ein persistenter, adressierbarer A2A-Endpunkt, der eine Persona vertritt — unter einem menschlichen Gate. Sein Körper ist eine lauffähige Instanz unter agents/<name>/, sein Selbst ist die Persona im System-Prompt, und seine Schnittstelle ist eine veröffentlichte AgentCard.
Read the representative-agent guide →Den Representative-Agent-Guide lesen →
Two meanings of "agent"
Zwei Bedeutungen von „Agent"
Bridge-Agent, not sub-agent
Bridge-Agent, kein Sub-Agent
The word "agent" names two different things. A sub-agent is ephemeral, inward-facing machinery: it runs one task inside your session and returns a summary — a function with tools, pointed at your work. A Bridge-Agent is a persistent, addressable entity that faces outward: its body is a runnable instance, its self is the persona in the system prompt, and its interface is a published AgentCard. This page is about the outward kind.
Das Wort „Agent" benennt zwei verschiedene Dinge. Ein Sub-Agent ist ephemere, nach innen gerichtete Maschinerie: er erledigt eine Aufgabe in deiner Session und liefert eine Zusammenfassung — eine Funktion mit Werkzeugen, auf deine Arbeit gerichtet. Ein Bridge-Agent ist eine persistente, adressierbare Entität, die nach außen blickt: sein Körper ist eine lauffähige Instanz, sein Selbst ist die Persona im System-Prompt, seine Schnittstelle eine veröffentlichte AgentCard. Diese Seite handelt vom nach außen gerichteten Typ.
Sub-agent
Sub-Agent
Lives in .claude/agents/. One task, one summary, then gone. It works for you, in your session — a tool the orchestrator dispatches and reabsorbs. It has no address, no card, and no life beyond the turn that spawned it.
Lebt in .claude/agents/. Eine Aufgabe, eine Zusammenfassung, dann verschwunden. Er arbeitet für dich, in deiner Session — ein Werkzeug, das der Orchestrator startet und wieder aufnimmt. Er hat keine Adresse, keine Card und kein Leben über die Turn hinaus, die ihn erzeugt hat.
Bridge-Agent
Bridge-Agent
Lives in agents/<name>/. A long-running A2A service on a stable address. It fronts a persona to the world: body = the instance, self = IDENTITY/SOUL in the system prompt, interface = the AgentCard other agents and visitors discover.
Lebt in agents/<name>/. Ein langlaufender A2A-Dienst auf einer stabilen Adresse. Er vertritt eine Persona nach außen: Körper = die Instanz, Selbst = IDENTITY/SOUL im System-Prompt, Schnittstelle = die AgentCard, die andere Agenten und Besucher entdecken.
Two faces, one self
Zwei Gesichter, ein Selbst
The same machinery serves two directions over one persona. Which face you deploy sets the trust boundary — the caps and the denylist tighten or relax, but the shape stays the same.
Dieselbe Maschinerie bedient zwei Richtungen über eine Persona. Welches Gesicht du deployst, setzt die Vertrauensgrenze — die Caps und die Denylist ziehen an oder lockern sich, aber die Form bleibt gleich.
Outer — visitors & foreign agents
Außen — Besucher & fremde Agenten
Anonymous visitors, foreign agents, a website widget. The representative face: it discloses only public, grounded facts and captures requests for a human to act on. Every request is assumed hostile.
Anonyme Besucher, fremde Agenten, ein Website-Widget. Das repräsentierende Gesicht: es gibt nur öffentliche, belegte Fakten preis und nimmt Anfragen auf, über die ein Mensch entscheidet. Jede Anfrage gilt als feindlich.
Inner — the peer mesh
Innen — das Peer-Mesh
Your own fleet and trusted peer bridges talking agent-to-agent. Same runtime, same self, opposite direction and a very different trust boundary — the caps relax while the contract holds.
Deine eigene Flotte und vertraute Peer-Bridges im Agent-zu-Agent-Dialog. Dieselbe Runtime, dasselbe Selbst, entgegengesetzte Richtung und eine ganz andere Vertrauensgrenze — die Caps lockern, während der Vertrag hält.
Capabilities
Fähigkeiten
What it can do
Was er kann
A representative agent does four things — and, on the honest card, advertises only the ones this instance actually implements. It never acts on anyone's behalf.
Ein Representative-Agent tut vier Dinge — und wirbt auf der ehrlichen Card nur mit denen, die diese Instanz tatsächlich umsetzt. Er handelt nie im Namen von irgendjemandem.
Answer from public content
Aus öffentlichem Inhalt antworten
The agent answers questions about its persona grounded in the public content of its grounding dir — the only files it can read. It speaks in the persona's voice and stays inside the persona's disclosure boundary; it cannot reach the bridge's private tree (identity, work, memory, customer data).
Der Agent beantwortet Fragen zu seiner Persona, belegt aus dem öffentlichen Inhalt seines Grounding-Verzeichnisses — den einzigen Dateien, die er lesen kann. Er spricht in der Stimme der Persona und bleibt innerhalb ihrer Offenlegungsgrenze; den privaten Baum der Bridge (Identity, Work, Memory, Kundendaten) erreicht er nicht.
Honest card: the AgentCard advertises only skills the prompt and tools actually implement — it must never claim a capability the instance cannot deliver.
Ehrliche Card: die AgentCard wirbt nur mit Skills, die Prompt und Werkzeuge wirklich umsetzen — sie darf nie eine Fähigkeit behaupten, die die Instanz nicht liefern kann.
Show availability
Verfügbarkeit zeigen
It can reveal when the persona is reachable or open to new work — a public, grounded fact, surfaced on request. Nothing is booked or confirmed here; availability is disclosed, never committed.
Er kann zeigen, wann die Persona erreichbar oder offen für neue Arbeit ist — ein öffentlicher, belegter Fakt, auf Anfrage sichtbar gemacht. Es wird hier nichts gebucht oder bestätigt; Verfügbarkeit wird offengelegt, nie zugesagt.
Capture requests — fixed recipient
Anfragen erfassen — fester Empfänger
An intake tool captures requests for the persona alone — no recipient argument, so a prompt-injected visitor cannot steer the agent into messaging a third party. Intake is durable-first: it persists the request and exits 0 even if a later notification fails. No booking or reply is ever sent autonomously — every outward action goes through a human gate.
Ein Intake-Werkzeug erfasst Anfragen ausschließlich für die Persona — kein Empfänger-Argument, sodass ein prompt-injizierter Besucher den Agenten nicht dazu bringen kann, eine dritte Partei anzuschreiben. Intake ist durable-first: es speichert die Anfrage und endet mit 0, selbst wenn eine spätere Benachrichtigung scheitert. Es wird nie autonom gebucht oder geantwortet — jede Aktion nach außen läuft über ein menschliches Gate.
Federate with peers (the mesh)
Mit Peers föderieren (das Mesh)
Over its inner face the same agent talks agent-to-agent with your own fleet and trusted peer bridges. Because every agent publishes a discoverable AgentCard over A2A, a peer can find it, read what it offers, and address it directly — a mesh of self-describing endpoints rather than a hardcoded integration.
Über sein inneres Gesicht spricht derselbe Agent Agent-zu-Agent mit deiner eigenen Flotte und vertrauten Peer-Bridges. Weil jeder Agent über A2A eine auffindbare AgentCard veröffentlicht, kann ein Peer ihn finden, lesen, was er anbietet, und ihn direkt adressieren — ein Mesh selbstbeschreibender Endpunkte statt einer fest verdrahteten Integration.
Instance anatomy
Anatomie einer Instanz
Anatomy of an instance
Anatomie einer Instanz
Each agent is fully declarative — three parts under agents/<name>/. The runtime that reads them, agents/_runtime/, is generic and never contains persona-specific content.
Jeder Agent ist vollständig deklarativ — drei Teile unter agents/<name>/. Die Runtime, die sie liest, agents/_runtime/, ist generisch und enthält nie persona-spezifischen Inhalt.
The card & the knobs
Die Card & die Stellschrauben
The card spec plus every runtime knob: the AgentCard fields (name, description, version, provider, skills), the network binding (host, port, public_url), the model and per-turn timeout, the grounding_dir, the scoped allowed_tools, and the public-endpoint caps (max_concurrency, max_input_chars, max_turns, max_contexts). Key fields — host, port, public URL, model, grounding dir, environment, and CORS — can be overridden by an environment variable at launch, so the same files run in dev and on the host.
Die Card-Spezifikation plus jede Runtime-Stellschraube: die AgentCard-Felder (name, description, version, provider, skills), die Netzwerk-Bindung (host, port, public_url), das Modell und der Pro-Turn-timeout, das grounding_dir, die skopierten allowed_tools und die Public-Endpoint-Caps (max_concurrency, max_input_chars, max_turns, max_contexts). Schlüsselfelder — Host, Port, Public-URL, Modell, Grounding-Dir, Environment und CORS — lassen sich beim Start per Umgebungsvariable überschreiben, sodass dieselben Dateien in Dev und auf dem Host laufen.
The persona
Die Persona
Appended to the model's base prompt (--append-system-prompt), so the model keeps its capabilities and gains the persona's voice, facts, and disclosure boundary. It defines who the agent is and what it may reveal. Declared grounding files can be inlined here (inline_grounding:) so the agent answers from context.
An den Basis-Prompt des Modells angehängt (--append-system-prompt), sodass das Modell seine Fähigkeiten behält und Stimme, Fakten und Offenlegungsgrenze der Persona hinzugewinnt. Es definiert, wer der Agent ist und was er preisgeben darf. Deklarierte Grounding-Dateien lassen sich hier inlinen (inline_grounding:), sodass der Agent aus dem Kontext antwortet.
Scoped CLIs, by absolute path
Skopierte CLIs, per absolutem Pfad
Instance-specific scoped tools, written as small argparse CLIs. The runtime never invokes them relative to the working directory — it invokes them by absolute path. A ${tools_dir} placeholder in agent.yaml and the prompt is substituted for the resolved absolute path, because the agent's cwd is the grounding dir, not the instance folder. The CORE template ships one reference tool — _template/tools/intake_notify.py, the fixed-recipient intake pattern (see Safety) — to copy into your instance and back with your own transport.
Instanz-spezifische, skopierte Werkzeuge als kleine argparse-CLIs. Die Runtime ruft sie nie relativ zum Arbeitsverzeichnis auf — sondern per absolutem Pfad. Ein ${tools_dir}-Platzhalter in agent.yaml und im Prompt wird durch den aufgelösten absoluten Pfad ersetzt, weil das cwd des Agenten das Grounding-Verzeichnis ist, nicht der Instanz-Ordner. Das CORE-Template liefert ein Referenzwerkzeug — _template/tools/intake_notify.py, das Fixed-Recipient-Intake-Muster (siehe Sicherheit) — zum Kopieren in deine Instanz und Hinterlegen mit eigenem Transport.
The runtime — agents/_runtime/, _template/, the tests and deps — is CORE: generic, shipped to open-bridge, never persona-specific. Each agents/<name>/ instance is USER: your persona and PII, kept local. Copy _template to start a new one.
Die Runtime — agents/_runtime/, _template/, die Tests und Deps — ist CORE: generisch, zu open-bridge ausgeliefert, nie persona-spezifisch. Jede agents/<name>/-Instanz ist USER: deine Persona und PII, lokal gehalten. Kopiere _template, um eine neue anzulegen.
Quickstart
Schnellstart
How to use it
Wie man ihn nutzt
Copy the template, run the runtime against your instance, then probe the two discovery endpoints. Editing agent.yaml and system-prompt.md in between is what makes the agent this persona.
Kopiere das Template, starte die Runtime gegen deine Instanz und prüfe dann die beiden Discovery-Endpunkte. Das Editieren von agent.yaml und system-prompt.md dazwischen macht den Agenten zu dieser Persona.
# 1 · copy the template to start an instance $ cp -r agents/_template agents/<name> # then edit agents/<name>/agent.yaml + system-prompt.md # 2 · run the runtime against your instance $ cd agents && uv run python -m _runtime.server --agent <name> --port 8011 # 3 · probe the AgentCard and the health endpoint $ curl -s localhost:8011/.well-known/agent-card.json | head $ curl -s localhost:8011/health {"status":"ok","agent":"<name>"}
The card lists supported_interfaces and only the skills the instance implements; /health is a plain GET. Deploy behind a tunnel that maps the public_url host to this port (see Limits).
Die Card führt supported_interfaces und nur die von der Instanz umgesetzten Skills auf; /health ist ein einfacher GET. Deploye hinter einem Tunnel, der den public_url-Host auf diesen Port abbildet (siehe Grenzen).
Runtime & protocol
Runtime & Protokoll
The runtime & protocol
Die Runtime & das Protokoll
The brain is claude -p; the shell around it is plain, standard, and spec-faithful — nothing exotic to run an A2A endpoint.
Das Gehirn ist claude -p; die Hülle drumherum ist schlicht, standardkonform und spec-treu — nichts Exotisches, um einen A2A-Endpunkt zu betreiben.
One subprocess per turn
Ein Subprozess pro Turn
For every turn the runner spawns a fresh claude -p subprocess, feeds it the assembled prompt, and reads back exactly one answer. claude -p is stateless, so conversation memory is kept by the executor keyed on the client's stable context_id and folded into each prompt as a short transcript. The persona is injected with --append-system-prompt; the grounding dir is the subprocess cwd.
Für jede Turn startet der Runner einen frischen claude -p-Subprozess, füttert ihn mit dem zusammengesetzten Prompt und liest genau eine Antwort zurück. claude -p ist zustandslos, also hält der Executor das Gesprächsgedächtnis, geschlüsselt über die stabile context_id des Clients, und faltet es als kurzes Transkript in jeden Prompt. Die Persona wird per --append-system-prompt injiziert; das Grounding-Verzeichnis ist das cwd des Subprozesses.
Plain Starlette + a2a-sdk 1.x
Schlichtes Starlette + a2a-sdk 1.x
The server is a plain Starlette app — a2a-sdk 1.x has no wrapper application. It composes the SDK's JSON-RPC and agent-card routes over a DefaultRequestHandler and an in-memory task store, with a CORS middleware and two small correctness shims (0.3-dialect compat and restored A2A-spec error codes). It speaks A2A spec v1.0.
Der Server ist eine schlichte Starlette-App — a2a-sdk 1.x hat keine Wrapper-Applikation. Er setzt die JSON-RPC- und Agent-Card-Routen des SDK über einem DefaultRequestHandler und einem In-Memory-Task-Store zusammen, mit CORS-Middleware und zwei kleinen Korrektheits-Shims (0.3-Dialekt-Kompatibilität und wiederhergestellte A2A-Spec-Fehlercodes). Er spricht A2A-Spec v1.0.
The AgentCard is served at /.well-known/agent-card.json (with a legacy alias). In a2a-sdk 1.x the single url field is gone: the card advertises a list of supported_interfaces[], each an interface with a public URL and a JSON-RPC transport binding. Over that, the runtime upholds one hard contract every turn — exactly one non-empty answer, delivered within timeout: never a hang, never a blank bubble. A raised line buffer, an overall deadline, and an accumulated-text fallback hold that line; a hermetic regression net (no real claude, no network) locks it in CI.
Die AgentCard wird unter /.well-known/agent-card.json ausgeliefert (mit Legacy-Alias). In a2a-sdk 1.x ist das einzelne url-Feld weg: die Card wirbt mit einer Liste supported_interfaces[], jede ein Interface mit öffentlicher URL und JSON-RPC-Transport-Bindung. Darüber hält die Runtime jede Turn einen harten Vertrag ein — genau eine nicht-leere Antwort, geliefert innerhalb von timeout: nie ein Hänger, nie eine leere Blase. Ein erhöhter Zeilenpuffer, eine Gesamt-Deadline und ein Fallback auf den akkumulierten Text halten die Linie; ein hermetisches Regressionsnetz (kein echtes claude, kein Netz) sichert sie in CI.
MCP → A2A
MCP → A2A
The MCP→A2A gateway
Der MCP→A2A-Gateway
Bridge-Agents speak A2A, but most people sit behind an MCP-only frontend — Claude connectors, ChatGPT developer mode, Gemini, any MCP client. agents/_gateway/ is a thin, stateless translation layer that makes your A2A bridges reachable from those frontends through three tools and one registry — no model, no reasoning, no persistent state inside the gateway itself.
Bridge-Agents sprechen A2A, aber die meisten Menschen sitzen hinter einem reinen MCP-Frontend — Claude-Connectors, ChatGPT-Entwicklermodus, Gemini, jeder MCP-Client. agents/_gateway/ ist eine schlanke, zustandslose Übersetzungsschicht, die deine A2A-Bridges über drei Werkzeuge und eine Registry aus diesen Frontends erreichbar macht — kein Modell, kein Reasoning, kein persistenter Zustand im Gateway selbst.
Three tools, one registry
Drei Werkzeuge, eine Registry
list_bridges returns the registry entries visible at the caller's access tier. get_bridge_card(bridge) fetches and normalizes that bridge's AgentCard — it reads both card dialects, so v1 and legacy cards resolve the same way. ask_bridge(bridge, message, conversation?) sends one A2A ask; passing back the same conversation id continues the thread, stateless on the gateway's side — it is threaded through to the target agent's own A2A contextId.
list_bridges liefert die Registry-Einträge, die für den Access-Tier des Aufrufers sichtbar sind. get_bridge_card(bridge) holt und normalisiert die AgentCard dieser Bridge — sie liest beide Card-Dialekte, sodass v1- und Legacy-Cards gleich aufgelöst werden. ask_bridge(bridge, message, conversation?) schickt eine A2A-Anfrage; dieselbe conversation-ID zurückgeben setzt den Thread fort, zustandslos auf Gateway-Seite — sie wird an die eigene A2A-contextId des Zielagenten durchgereicht.
Standard tier — no header
Standard-Tier — kein Header
With no Authorization header, a caller sees and asks only bridges the registry marks min_tier: anonymous, and cards come back as normalized summaries.
Ohne Authorization-Header sieht und fragt ein Aufrufer nur Bridges, die die Registry als min_tier: anonymous markiert, und Cards kommen als normalisierte Zusammenfassungen zurück.
Elevated tier — bearer token
Erweitertes Tier — Bearer-Token
An Authorization: Bearer <token> header matching the configured token list unlocks every registered bridge, including min_tier: authenticated ones, and get_bridge_card additionally returns the full raw card. An invalid token is a hard unauthorized error — never a silent downgrade to anonymous. The client's token is never forwarded upstream; a bridge that needs its own credentials declares them separately in the registry.
Ein Authorization: Bearer <token>-Header, der zur konfigurierten Token-Liste passt, schaltet jede registrierte Bridge frei, auch min_tier: authenticated-Bridges, und get_bridge_card liefert zusätzlich die vollständige Rohkarte. Ein ungültiges Token ist ein harter unauthorized-Fehler — nie ein stiller Downgrade auf anonym. Das Token des Clients wird nie upstream weitergereicht; eine Bridge, die eigene Credentials braucht, deklariert sie separat in der Registry.
# 1 · declare which bridges the gateway may reach $ cd agents/_gateway && cp registry.example.yaml registry.yaml # then edit registry.yaml — card URL + min_tier per bridge # 2 · run it (optional: a bearer token enables the elevated tier) $ export GATEWAY_AUTH_TOKENS="some-random-token" $ uv run python -m gateway --registry registry.yaml --port 8900 # 3 · point any MCP client at it (Streamable HTTP) $ claude mcp add --transport http bridge-gateway http://127.0.0.1:8900/mcp
Behind a public tunnel, the MCP SDK's DNS-rebinding protection answers a tunnel hostname with HTTP 421 unless you allowlist it: GATEWAY_ALLOWED_HOSTS="<your-gateway-host>,127.0.0.1:8900,localhost:8900" — list the loopback host:port too, or local health probes start 421ing the moment the tunnel hostname is configured.
Hinter einem öffentlichen Tunnel beantwortet der DNS-Rebinding-Schutz des MCP-SDK einen Tunnel-Hostnamen mit HTTP 421, sofern er nicht auf der Allowlist steht: GATEWAY_ALLOWED_HOSTS="<dein-gateway-host>,127.0.0.1:8900,localhost:8900" — auch den Loopback-host:port aufführen, sonst 421en lokale Health-Probes, sobald der Tunnel-Hostname konfiguriert ist.
The gateway adds reach, not privilege — it is a client like any other in front of the target agent and bypasses none of the agent's own guardrails (grounding confinement, scoped tools, human-gated intake; see the safety model below). A per-bridge concurrency gate, a timeout budget under the client's own tool-call timeout, and typed error envelopes (unknown_bridge, tier_denied, unauthorized, busy, timeout, unreachable, upstream_error) keep a stuck or hostile upstream from silently hanging the client. Put an edge rate-limit in front of a public deployment, and keep min_tier: authenticated on anything you don't want anonymous traffic to reach.
Der Gateway erweitert die Reichweite, nicht die Rechte — er ist ein Client wie jeder andere vor dem Zielagenten und umgeht keine der eigenen Leitplanken des Agenten (Grounding-Begrenzung, skopierte Werkzeuge, menschlich gegatetes Intake; siehe das Sicherheitsmodell unten). Ein Per-Bridge-Concurrency-Gate, ein Timeout-Budget unter dem eigenen Tool-Call-Timeout des Clients und typisierte Fehler-Umschläge (unknown_bridge, tier_denied, unauthorized, busy, timeout, unreachable, upstream_error) verhindern, dass ein hängendes oder feindliches Upstream den Client still hängen lässt. Setze ein Edge-Rate-Limit vor ein öffentliches Deployment und halte min_tier: authenticated auf allem, das du nicht anonymem Traffic aussetzen willst.
Safety
Sicherheit
The safety model
Das Sicherheitsmodell
A public endpoint is assumed hostile on every request. Several independent layers ensure a visitor can never make the agent read private files, exfiltrate secrets, or act on anyone's behalf — defense-in-depth on top of the model's own refusal.
Ein öffentlicher Endpunkt gilt bei jeder Anfrage als feindlich. Mehrere unabhängige Schichten stellen sicher, dass ein Besucher den Agenten nie dazu bringen kann, private Dateien zu lesen, Geheimnisse zu exfiltrieren oder in jemandes Namen zu handeln — Defense-in-Depth über der modelleigenen Verweigerung.
Read-confinement: cwd = grounding_dir
Lese-Begrenzung: cwd = grounding_dir
The single most important control. The subprocess runs with its working directory set to the grounding dir — the folder of public content the agent may know. That cwd confines the read-only file tools (Read, Glob, Grep) to public content: they cannot reach the bridge's private tree. Scoped instance tools still resolve because they are invoked by absolute path, not relative to cwd.
Die wichtigste einzelne Kontrolle. Der Subprozess läuft mit seinem Arbeitsverzeichnis auf das Grounding-Verzeichnis gesetzt — den Ordner mit dem öffentlichen Inhalt, den der Agent kennen darf. Dieses cwd begrenzt die Nur-Lese-Dateiwerkzeuge (Read, Glob, Grep) auf öffentlichen Inhalt: den privaten Baum der Bridge erreichen sie nicht. Skopierte Instanz-Werkzeuge lösen dennoch auf, weil sie per absolutem Pfad aufgerufen werden, nicht relativ zum cwd.
Scoped allowed_tools
Skopierte allowed_tools
allowed_tools grants read-only file access plus only the intended instance tools, each by absolute path — no generic shell, no write tool, no arbitrary send. The default is Read,Glob,Grep; an intake CLI is added explicitly (copy _template/tools/intake_notify.py).
allowed_tools gewährt Nur-Lese-Dateizugriff plus nur die vorgesehenen Instanz-Werkzeuge, je per absolutem Pfad — keine generische Shell, kein Write-Tool, kein beliebiges Senden. Default ist Read,Glob,Grep; ein Intake-CLI wird explizit ergänzt (kopiere _template/tools/intake_notify.py).
Read-only-shell denylist (backstop)
Read-only-Shell-Denylist (Backstop)
--permission-mode acceptEdits keeps a headless agent from hanging, but it auto-allows any shell command the engine classifies as read-only — independent of allowed_tools. So the runtime ships a broad --disallowedTools denylist of the known file-reader, search, hashing, VCS, secret-store, and network binaries. It is a backstop, never the control — it raises the bar but can never be complete.
--permission-mode acceptEdits verhindert, dass ein Headless-Agent hängt, erlaubt aber automatisch jedes Shell-Kommando, das die Engine als read-only einstuft — unabhängig von allowed_tools. Also liefert die Runtime eine breite --disallowedTools-Denylist der bekannten Datei-Leser-, Such-, Hash-, VCS-, Secret-Store- und Netzwerk-Binaries. Sie ist ein Backstop, nie die Kontrolle — sie hebt die Latte, kann aber nie vollständig sein.
Project-only settings
Nur Projekt-Settings
The runner passes --setting-sources project, so it loads only the project's settings — never the host user's allowlist or hooks. A host preference can therefore never silently widen this internet-facing agent.
Der Runner übergibt --setting-sources project, lädt also nur die Projekt-Settings — nie die Allowlist oder Hooks des Host-Users. Eine Host-Einstellung kann diesen ins Internet gerichteten Agenten damit nie stillschweigend erweitern.
Fixed-recipient intake
Intake mit festem Empfänger
The intake tool captures requests for the persona alone — the fixed recipient comes from operator config only (no recipient argument exists), so a prompt-injected visitor can never steer the agent into messaging a third party. Capture is durable-first; the notify is best-effort and never raises; unconfigured stays capture-only and loud; the audit log is PII-free. CORE ships this as a stdlib-only scaffold, _template/tools/intake_notify.py, whose send() seam an instance fills with its transport — locked by a testable seven-clause contract (tests/test_intake_notify.py). No booking or reply is ever sent autonomously; every outward action goes through a human gate.
Das Intake-Werkzeug erfasst Anfragen ausschließlich für die Persona — der feste Empfänger kommt nur aus der Operator-Config (ein Empfänger-Argument existiert nicht), sodass ein prompt-injizierter Besucher den Agenten nie zum Anschreiben Dritter verleiten kann. Erfassung ist durable-first; die Benachrichtigung ist best-effort und wirft nie; unkonfiguriert bleibt es capture-only und laut; das Audit-Log ist PII-frei. CORE liefert das als stdlib-only-Scaffold, _template/tools/intake_notify.py, dessen send()-Naht eine Instanz mit ihrem Transport füllt — abgesichert durch einen testbaren Sieben-Klausel-Vertrag (tests/test_intake_notify.py). Es wird nie autonom gebucht oder geantwortet; jede Aktion nach außen läuft über ein menschliches Gate.
Public-endpoint caps & honest card
Public-Endpoint-Caps & ehrliche Card
The executor enforces max_concurrency, max_input_chars, max_turns, and a bounded max_contexts LRU, so an ungated endpoint cannot exhaust memory or spawn unbounded subprocesses — add a per-IP edge rate-limit at your CDN. And the AgentCard stays honest: it advertises only capabilities the instance can deliver.
Der Executor erzwingt max_concurrency, max_input_chars, max_turns und ein begrenztes max_contexts-LRU, sodass ein ungeschützter Endpunkt weder Speicher erschöpfen noch unbegrenzt Subprozesse starten kann — ergänze ein Per-IP-Edge-Rate-Limit an deinem CDN. Und die AgentCard bleibt ehrlich: sie wirbt nur mit Fähigkeiten, die die Instanz liefern kann.
The layers above are defense-in-depth; the real fix for read-confinement is an OS sandbox that confines reads to the grounding dir and blocks network and secret-store access with the mechanism the host supports — a container as an unprivileged user on Linux, or a sandbox-exec profile / dedicated low-privilege user on the host OS. Name it as the goal; the denylist buys time until it is in place.
Die obigen Schichten sind Defense-in-Depth; der echte Fix für die Lese-Begrenzung ist eine OS-Sandbox, die Lesezugriffe auf das Grounding-Verzeichnis begrenzt und Netzwerk- sowie Secret-Store-Zugriff mit dem vom Host unterstützten Mechanismus blockiert — ein Container als unprivilegierter User auf Linux oder ein sandbox-exec-Profil / dedizierter Low-Privilege-User auf dem Host-OS. Benenne sie als Ziel; die Denylist kauft Zeit, bis sie steht.
Honest limits
Ehrliche Grenzen
What it does not promise
Was es nicht verspricht
The feature is built carefully, and it is documented just as carefully. Three limits to know before you lean on it:
Das Feature ist sorgfältig gebaut — und ebenso sorgfältig dokumentiert. Drei Grenzen, die man kennen sollte, bevor man sich darauf verlässt:
It is not autonomous
Er ist nicht autonom
A representative agent never books, replies, or acts on anyone's behalf. It discloses public facts and captures a request for a fixed recipient — every outward action waits on a human gate. That is a deliberate boundary, not a missing feature.
Ein Representative-Agent bucht, antwortet oder handelt nie im Namen von jemandem. Er legt öffentliche Fakten offen und erfasst eine Anfrage für einen festen Empfänger — jede Aktion nach außen wartet auf ein menschliches Gate. Das ist eine bewusste Grenze, kein fehlendes Feature.
Read-confinement is not yet kernel-enforced
Lese-Begrenzung ist noch nicht kernel-erzwungen
The cwd, the scoped tools, and the denylist are defense-in-depth, but the denylist is a backstop that can never be complete. The real read-confinement is an OS sandbox (a container as an unprivileged user, or a sandbox-exec profile) — until it is in place, treat the grounding dir, not the process, as the boundary.
Das cwd, die skopierten Tools und die Denylist sind Defense-in-Depth, aber die Denylist ist ein Backstop, der nie vollständig sein kann. Die echte Lese-Begrenzung ist eine OS-Sandbox (ein Container als unprivilegierter User oder ein sandbox-exec-Profil) — bis sie steht, ist das Grounding-Verzeichnis die Grenze, nicht der Prozess.
Latency is a knob, not instant
Latenz ist ein Stellknopf, nicht sofort
A broad question that makes the model read the whole grounding and reason a full answer can take ~60–90s with a strong model. SSE keepalive holds the connection and the contract still guarantees one answer, but speed is a tuning choice — keep the grounding small, inline it into the prompt, or use a faster model.
Eine breite Frage, die das Modell das ganze Grounding lesen und eine volle Antwort durchdenken lässt, kann mit einem starken Modell ~60–90s dauern. SSE-Keepalive hält die Verbindung und der Vertrag garantiert weiter eine Antwort, aber Tempo ist eine Abstimmungsfrage — Grounding klein halten, in den Prompt inlinen oder ein schnelleres Modell nehmen.
Go deeper
Tiefer einsteigen