---
title: Die API auf einem selbst gehosteten Server aufrufen
url: https://platform.claude.com/docs/de/managed-agents/self-hosted/call-the-api
description: Richte das offizielle SDK, cURL oder die ant CLI auf deinen selbst gehosteten Server für Claude Managed Agents aus, starte eine Sitzung und lies die Antwort des Agenten. Verbinde dann eigene Worker, falls du sie brauchst.
---

<Note>
  Um Zugriff auf selbst gehostetes Claude Managed Agents anzufordern, kontaktiere dein Anthropic-Account-Team.
</Note>

Ein selbst gehosteter Claude Managed Agents-Server hat dieselbe API wie der gehostete [Managed Agents](https://platform.claude.com/docs/de/managed-agents/overview)-Dienst von Anthropic. Dein Code ruft ihn mit dem offiziellen SDK, cURL oder der `ant` CLI auf. Zwei Dinge ändern sich: Die „base URL“ (Basis-URL) ist die Adresse deines Servers, und der API-Key ist dein [Server-API-Key](https://platform.claude.com/docs/de/managed-agents/self-hosted#the-three-credentials) anstelle eines Claude API-Keys.

Um Agenten zu erstellen und Sitzungen in einem Browser auszuführen, siehe [Die Konsole auf deinem Server verwenden](https://platform.claude.com/docs/de/managed-agents/self-hosted/console).

## Voraussetzungen

* **Ein laufender Server:** Starte einen mit [Erste Schritte mit selbst gehostetem Claude Managed Agents](https://platform.claude.com/docs/de/managed-agents/self-hosted/quickstart) oder [Auf Kubernetes bereitstellen](https://platform.claude.com/docs/de/managed-agents/self-hosted/kubernetes).
* **Zugriff auf den Server:** Wenn jemand anderes den Server betreibt, frage nach seiner Adresse und danach, wie du dich authentifizierst. Wenn dort Single Sign-on verwendet wird, siehe [Entwicklern die Anmeldung über ein Terminal ermöglichen](https://platform.claude.com/docs/de/managed-agents/self-hosted/configure#let-developers-log-in-from-a-terminal).
* **Die `ant` CLI:** Installiere die neueste Version, wie der [CLI-Schnellstart](https://platform.claude.com/docs/de/cli-sdks-libraries/cli/quickstart#installation) zeigt.

## Deinen Client auf deinen Server ausrichten

Das SDK und die `ant` CLI lesen die Adresse des Servers aus `ANTHROPIC_BASE_URL` und den API-Key aus `ANTHROPIC_API_KEY`. Setze beide Variablen in einem Terminal, das du für diesen Server reservierst.

Führe für den [Schnellstart-Stack](https://platform.claude.com/docs/de/managed-agents/self-hosted/quickstart) diese Befehle in dem Verzeichnis aus, das deine `.env`-Datei enthält:

```bash
export ANTHROPIC_BASE_URL=http://127.0.0.1:8400
export ANTHROPIC_API_KEY=$(grep '^CMA_SERVER__API_KEY=' .env | cut -d= -f2)
```

Setze unter Kubernetes die beiden Variablen, wie [Eine Sitzung ausführen](https://platform.claude.com/docs/de/managed-agents/self-hosted/kubernetes#run-a-session) zeigt, und lass das dortige Port-Forwarding weiterlaufen.

In diesem Terminal erreicht jeder `ant`-Befehl, wie etwa `ant beta:agents list`, deinen Server. Führe Claude Code oder `docker compose` nicht in diesem Terminal aus, da sie dieselben Variablen lesen.

## Eine Sitzung starten

Eine Sitzung benötigt die ID eines Agents und die ID einer Umgebung:

* **Agent:** Erstelle einen, wie [Einen Agenten erstellen](https://platform.claude.com/docs/de/managed-agents/agent-setup#create-an-agent) zeigt, wobei dein Client auf deinen Server ausgerichtet ist. Wenn du direkte HTTP-Anfragen sendest, ersetze `https://api.anthropic.com` in der URL durch `$ANTHROPIC_BASE_URL`.
* **Umgebung:** Der Schnellstart-Stack erstellt eine Umgebung namens `compose-sandbox`, und die Helm-Charts erstellen eine namens `default`. `ant beta:environments list` gibt den Namen und die ID jeder Umgebung aus. Für deine eigenen Worker ist es die ID, die die Admin-CLI in [Eigene Worker betreiben](https://platform.claude.com/docs/de/managed-agents/self-hosted/call-the-api#point-a-worker-at-your-server) ausgegeben hat.

Lege deine beiden IDs anstelle dieser Beispiel-IDs in deiner Shell ab:

```bash
export AGENT_ID=agent_011CYm1BLqPXpQRk5khsSXrs
export ENVIRONMENT_ID=env_01595EKxaaTTGwwY3kyXdtbs
```

Das folgende Beispiel erstellt eine Sitzung und sendet ihre erste Nachricht in derselben Anfrage:

<CodeGroup>
  ```bash cURL
  curl -sS --fail-with-body "$ANTHROPIC_BASE_URL/v1/sessions" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2026-10-21" \
    -H "anthropic-beta: managed-agents-2026-04-01" \
    -H "content-type: application/json" \
    -d '{
      "agent": "'"$AGENT_ID"'",
      "environment_id": "'"$ENVIRONMENT_ID"'",
      "initial_events": [
        {
          "type": "user.message",
          "content": [{"type": "text", "text": "List the files in the working directory."}]
        }
      ]
    }'
  ```

  ```bash CLI
  ant beta:sessions create --agent "$AGENT_ID" --environment-id "$ENVIRONMENT_ID" \
    --initial-event '{type: user.message, content: [{type: text, text: "List the files in the working directory."}]}'
  ```

  ```python Python
  import os

  from anthropic import Anthropic

  client = Anthropic()

  session = client.beta.sessions.create(
      agent=os.environ["AGENT_ID"],
      environment_id=os.environ["ENVIRONMENT_ID"],
      initial_events=[
          {
              "type": "user.message",
              "content": [
                  {"type": "text", "text": "List the files in the working directory."}
              ],
          },
      ],
  )
  print(session.id)
  ```

  ```typescript TypeScript
  import Anthropic from "@anthropic-ai/sdk";

  const client = new Anthropic();

  const session = await client.beta.sessions.create({
    agent: process.env["AGENT_ID"]!,
    environment_id: process.env["ENVIRONMENT_ID"]!,
    initial_events: [
      {
        type: "user.message",
        content: [{ type: "text", text: "List the files in the working directory." }]
      }
    ]
  });
  console.log(session.id);
  ```

  ```csharp C#
  using System;
  using Anthropic;
  using Anthropic.Models.Beta.Agents;
  using Anthropic.Models.Beta.Sessions;
  using Anthropic.Models.Beta.Sessions.Events;

  AnthropicClient client = new();

  var session = await client.Beta.Sessions.Create(new()
  {
      Agent = Environment.GetEnvironmentVariable("AGENT_ID")!,
      EnvironmentID = Environment.GetEnvironmentVariable("ENVIRONMENT_ID")!,
      InitialEvents =
      [
          new BetaManagedAgentsUserMessageEventParams
          {
              Content =
              [
                  new BetaManagedAgentsTextBlock
                  {
                      Text = "List the files in the working directory.",
                  },
              ],
          },
      ],
  });
  Console.WriteLine(session.ID);
  ```

  ```go Go
  package main

  import (
  	"context"
  	"fmt"
  	"os"

  	"github.com/anthropics/anthropic-sdk-go/v2"
  )

  func main() {
  	client := anthropic.NewClient()

  	session, err := client.Beta.Sessions.New(context.Background(), anthropic.BetaSessionNewParams{
  		Agent: anthropic.BetaSessionNewParamsAgentUnion{
  			OfString: anthropic.String(os.Getenv("AGENT_ID")),
  		},
  		EnvironmentID: os.Getenv("ENVIRONMENT_ID"),
  		InitialEvents: []anthropic.BetaSessionNewParamsInitialEventUnion{{
  			OfUserMessage: &anthropic.BetaManagedAgentsUserMessageEventParams{
  				Content: []anthropic.BetaManagedAgentsUserMessageEventParamsContentUnion{{
  					OfText: &anthropic.BetaManagedAgentsTextBlockParam{
  						Text: "List the files in the working directory.",
  					},
  				}},
  			},
  		}},
  	})
  	if err != nil {
  		panic(err)
  	}
  	fmt.Println(session.ID)
  }
  ```

  ```java Java
  import com.anthropic.client.AnthropicClient;
  import com.anthropic.client.okhttp.AnthropicOkHttpClient;
  import com.anthropic.models.beta.sessions.SessionCreateParams;
  import com.anthropic.models.beta.sessions.events.BetaManagedAgentsUserMessageEventParams;

  void main() {
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      var session = client.beta().sessions().create(SessionCreateParams.builder()
          .agent(System.getenv("AGENT_ID"))
          .environmentId(System.getenv("ENVIRONMENT_ID"))
          .addInitialEvent(BetaManagedAgentsUserMessageEventParams.builder()
              .addTextContent("List the files in the working directory.")
              .build())
          .build());
      IO.println(session.id());
  }
  ```

  ```php PHP
  <?php

  use Anthropic\Client;

  $client = new Client();

  $session = $client->beta->sessions->create(
      agent: (string) getenv('AGENT_ID'),
      environmentID: (string) getenv('ENVIRONMENT_ID'),
      initialEvents: [
          [
              'type' => 'user.message',
              'content' => [['type' => 'text', 'text' => 'List the files in the working directory.']],
          ],
      ],
  );
  echo $session->id, "\n";
  ```

  ```ruby Ruby
  require "anthropic"

  client = Anthropic::Client.new

  session = client.beta.sessions.create(
    agent: ENV.fetch("AGENT_ID"),
    environment_id: ENV.fetch("ENVIRONMENT_ID"),
    initial_events: [
      {
        type: :"user.message",
        content: [{type: :text, text: "List the files in the working directory."}]
      }
    ]
  )
  puts session.id
  ```
</CodeGroup>

Die Antwort enthält die ID der Sitzung, die mit `sesn_` beginnt. Der Agent beginnt sofort mit der Arbeit. Seine integrierten Tools, wie `bash`, laufen auf einem Worker, der die Umgebung bedient.

Um die Sitzung zu beobachten, öffne die [Konsole auf deinem Server](https://platform.claude.com/docs/de/managed-agents/self-hosted/console) in einem Browser, wähle **Sessions** und dann die Sitzung aus. Eine Sitzung, die du wie auf dieser Seite mit dem Server-API-Key gestartet hast, wird nur Administratoren angezeigt.

Um die Sitzung stattdessen in deinem Terminal zu verfolgen, übergib ihre ID an [`ant beta:sessions connect`](https://platform.claude.com/docs/de/cli-sdks-libraries/cli/sessions-connect):

```bash
ant beta:sessions connect sesn_011CZkZAtmR3yMPDzynEDxu7
```

Was eine Sitzung sonst noch kann, etwa eine Agent-Version festlegen, findest du unter [Eine Session starten](https://platform.claude.com/docs/de/managed-agents/sessions).

## Eine Nachricht senden und die Antwort lesen

Lege die ID deiner Sitzung anstelle dieser Beispiel-ID in deiner Shell ab:

```bash
export SESSION_ID=sesn_011CZkZAtmR3yMPDzynEDxu7
```

Warte, bis die Sitzung im Leerlauf ist, bevor du das nächste Beispiel ausführst. Das Beispiel hört auf zu lesen, wenn ein Turn endet. Wenn ein früherer Turn noch läuft, kann sein Ende das Beispiel stoppen, bevor die Antwort auf deine Nachricht eintrifft. Die Konsole und `ant beta:sessions connect` zeigen beide den Status der Sitzung an.

Das folgende Beispiel sendet eine Nachricht und gibt die Antwort des Agenten aus. Es öffnet zuerst den Event-Stream der Sitzung, weil ein Stream nur die Events liefert, die nach seinem Öffnen eintreffen:

<CodeGroup exclude="shell">
  <CodeGroupItem language="cURL">
    Dieser Workflow benötigt mehr Logik als ein einzelner Shell-Befehl. Verwende das [Anthropic SDK](https://platform.claude.com/docs/de/cli-sdks-libraries/overview), um ihn auszuführen.
  </CodeGroupItem>

  <CodeGroupItem language="CLI">
    Dieser Workflow benötigt mehr Logik als ein einzelner Shell-Befehl. Um Nachrichten zu senden und die Antworten in deinem Terminal zu lesen, verwende [`ant beta:sessions connect`](https://platform.claude.com/docs/de/cli-sdks-libraries/cli/sessions-connect).
  </CodeGroupItem>

  ```python Python
  import os

  from anthropic import Anthropic

  client = Anthropic()
  session_id = os.environ["SESSION_ID"]

  with client.beta.sessions.events.stream(session_id) as stream:
      client.beta.sessions.events.send(
          session_id,
          events=[
              {
                  "type": "user.message",
                  "content": [
                      {"type": "text", "text": "Summarize what you did in one sentence."}
                  ],
              },
          ],
      )

      for event in stream:
          match event.type:
              case "agent.message":
                  for block in event.content:
                      if block.type == "text":
                          print(block.text, end="")
              case "session.error":
                  error_message = event.error.message if event.error else "unknown"
                  print(f"\n[Error: {error_message}]")
              case "session.status_idle":
                  if event.stop_reason.type != "requires_action":
                      break
              case "session.status_terminated":
                  break
  ```

  ```typescript TypeScript
  import Anthropic from "@anthropic-ai/sdk";

  const client = new Anthropic();
  const sessionId = process.env["SESSION_ID"]!;

  const stream = await client.beta.sessions.events.stream(sessionId);
  await client.beta.sessions.events.send(sessionId, {
    events: [
      {
        type: "user.message",
        content: [{ type: "text", text: "Summarize what you did in one sentence." }]
      }
    ]
  });

  events: for await (const event of stream) {
    switch (event.type) {
      case "agent.message":
        for (const block of event.content) {
          if (block.type === "text") {
            process.stdout.write(block.text);
          }
        }
        break;
      case "session.error":
        console.log(`\n[Error: ${event.error?.message ?? "unknown"}]`);
        break;
      case "session.status_idle":
        if (event.stop_reason.type !== "requires_action") {
          break events;
        }
        break;
      case "session.status_terminated":
        break events;
    }
  }
  ```

  ```csharp C#
  using System;
  using Anthropic;
  using Anthropic.Models.Beta.Sessions.Events;

  AnthropicClient client = new();
  var sessionId = Environment.GetEnvironmentVariable("SESSION_ID")!;

  using var stream = await client.Beta.Sessions.Events.WithRawResponse.StreamStreaming(sessionId);
  await client.Beta.Sessions.Events.Send(sessionId, new()
  {
      Events =
      [
          new BetaManagedAgentsUserMessageEventParams
          {
              Content = [new BetaManagedAgentsTextBlock { Text = "Summarize what you did in one sentence." }],
          },
      ],
  });

  await foreach (var streamEvent in stream.Enumerate())
  {
      if (streamEvent.Value is BetaManagedAgentsAgentMessageEvent message)
      {
          foreach (var block in message.Content)
          {
              if (block.Value is BetaManagedAgentsTextBlock textBlock)
              {
                  Console.Write(textBlock.Text);
              }
          }
      }
      else if (streamEvent.Value is BetaManagedAgentsSessionErrorEvent error)
      {
          Console.WriteLine($"\n[Error: {error.Error?.Message ?? "unknown"}]");
      }
      else if (streamEvent.Value is BetaManagedAgentsSessionStatusIdleEvent idle
          && idle.StopReason?.Value is not BetaManagedAgentsSessionRequiresAction)
      {
          break;
      }
      else if (streamEvent.Value is BetaManagedAgentsSessionStatusTerminatedEvent)
      {
          break;
      }
  }
  ```

  ```go Go
  package main

  import (
  	"cmp"
  	"context"
  	"fmt"
  	"os"

  	"github.com/anthropics/anthropic-sdk-go/v2"
  )

  func main() {
  	client := anthropic.NewClient()
  	ctx := context.Background()
  	sessionID := os.Getenv("SESSION_ID")

  	stream := client.Beta.Sessions.Events.StreamEvents(ctx, sessionID, anthropic.BetaSessionEventStreamParams{})
  	defer stream.Close()

  	if _, err := client.Beta.Sessions.Events.Send(ctx, sessionID, anthropic.BetaSessionEventSendParams{
  		Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
  			OfUserMessage: &anthropic.BetaManagedAgentsUserMessageEventParams{
  				Content: []anthropic.BetaManagedAgentsUserMessageEventParamsContentUnion{{
  					OfText: &anthropic.BetaManagedAgentsTextBlockParam{
  						Text: "Summarize what you did in one sentence.",
  					},
  				}},
  			},
  		}},
  	}); err != nil {
  		panic(err)
  	}

  events:
  	for stream.Next() {
  		switch event := stream.Current().AsAny().(type) {
  		case anthropic.BetaManagedAgentsAgentMessageEvent:
  			for _, block := range event.Content {
  				if block.Type == "text" {
  					fmt.Print(block.Text)
  				}
  			}
  		case anthropic.BetaManagedAgentsSessionErrorEvent:
  			fmt.Printf("\n[Error: %s]\n", cmp.Or(event.Error.Message, "unknown"))
  		case anthropic.BetaManagedAgentsSessionStatusIdleEvent:
  			if _, paused := event.StopReason.AsAny().(anthropic.BetaManagedAgentsSessionRequiresAction); !paused {
  				break events
  			}
  		case anthropic.BetaManagedAgentsSessionStatusTerminatedEvent:
  			break events
  		}
  	}
  	if err := stream.Err(); err != nil {
  		panic(err)
  	}
  }
  ```

  ```java Java
  import com.anthropic.client.AnthropicClient;
  import com.anthropic.client.okhttp.AnthropicOkHttpClient;
  import com.anthropic.core.JsonObject;
  import com.anthropic.models.beta.sessions.events.BetaManagedAgentsUserMessageEventParams;
  import com.anthropic.models.beta.sessions.events.EventSendParams;

  void main() {
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();
      var sessionId = System.getenv("SESSION_ID");

      try (var stream = client.beta().sessions().events().streamStreaming(sessionId)) {
          client.beta().sessions().events().send(
              sessionId,
              EventSendParams.builder()
                  .addEvent(BetaManagedAgentsUserMessageEventParams.builder()
                      .addTextContent("Summarize what you did in one sentence.")
                      .build())
                  .build()
          );

          events:
          for (var event : stream) {
              switch (event.type().value()) {
                  case AGENT_MESSAGE -> {
                      for (var block : event.asAgentMessage().content()) {
                          block.text().ifPresent(textBlock -> IO.print(textBlock.text()));
                      }
                  }
                  case SESSION_ERROR -> {
                      var errorMessage =
                          event.asSessionError().error()._json().orElse(null) instanceof JsonObject json
                              ? json.values().get("message").asStringOrThrow()
                              : "unknown";
                      IO.println("\n[Error: " + errorMessage + "]");
                  }
                  case SESSION_STATUS_IDLE -> {
                      if (!event.asSessionStatusIdle().stopReason().isRequiresAction()) {
                          break events;
                      }
                  }
                  case SESSION_STATUS_TERMINATED -> {
                      break events;
                  }
                  default -> {}
              }
          }
      }
  }
  ```

  ```php PHP
  <?php

  use Anthropic\Beta\Sessions\Events\ManagedAgentsAgentMessageEvent;
  use Anthropic\Beta\Sessions\Events\ManagedAgentsSessionErrorEvent;
  use Anthropic\Beta\Sessions\Events\ManagedAgentsSessionRequiresAction;
  use Anthropic\Beta\Sessions\Events\ManagedAgentsSessionStatusIdleEvent;
  use Anthropic\Beta\Sessions\Events\ManagedAgentsSessionStatusTerminatedEvent;
  use Anthropic\Beta\Sessions\Events\ManagedAgentsTextBlock;
  use Anthropic\Client;

  $client = new Client();
  $sessionId = (string) getenv('SESSION_ID');

  $stream = $client->beta->sessions->events->streamStream($sessionId);
  $client->beta->sessions->events->send(
      $sessionId,
      events: [
          [
              'type' => 'user.message',
              'content' => [['type' => 'text', 'text' => 'Summarize what you did in one sentence.']],
          ],
      ],
  );

  foreach ($stream as $event) {
      switch (true) {
          case $event instanceof ManagedAgentsAgentMessageEvent:
              foreach ($event->content as $block) {
                  if ($block instanceof ManagedAgentsTextBlock) {
                      echo $block->text;
                  }
              }
              break;
          case $event instanceof ManagedAgentsSessionErrorEvent:
              printf("\n[Error: %s]\n", $event->error->message);
              break;
          case $event instanceof ManagedAgentsSessionStatusIdleEvent:
              if (!($event->stopReason instanceof ManagedAgentsSessionRequiresAction)) {
                  break 2; // Break foreach loop
              }
              break;
          case $event instanceof ManagedAgentsSessionStatusTerminatedEvent:
              break 2; // Break foreach loop
      }
  }
  $stream->close();
  ```

  ```ruby Ruby
  require "anthropic"

  client = Anthropic::Client.new
  session_id = ENV.fetch("SESSION_ID")

  stream = client.beta.sessions.events.stream_events(session_id)

  client.beta.sessions.events.send_(
    session_id,
    events: [{
      type: "user.message",
      content: [{type: "text", text: "Summarize what you did in one sentence."}]
    }]
  )

  stream.each do |event|
    case event
    when Anthropic::Beta::Sessions::BetaManagedAgentsAgentMessageEvent
      event.content.each do |block|
        print block.text if block.is_a?(Anthropic::Beta::Sessions::BetaManagedAgentsTextBlock)
      end
    when Anthropic::Beta::Sessions::BetaManagedAgentsSessionErrorEvent
      puts "\n[Error: #{event.error&.message || "unknown"}]"
    when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusIdleEvent
      break unless event.stop_reason.is_a?(Anthropic::Beta::Sessions::BetaManagedAgentsSessionRequiresAction)
    when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusTerminatedEvent
      break
    else
      # ignoriere andere Event-Typen
    end
  end
  ```
</CodeGroup>

Neben der Ausgabe von `agent.message`-Text verarbeitet die Schleife drei Events:

* **`session.status_idle`:** Die Schleife endet, es sei denn, der `stop_reason.type` des Events ist `requires_action`.
* **`session.status_terminated`:** Die Schleife endet.
* **`session.error`:** Die Schleife gibt die Meldung des Fehlers aus und liest weiter, weil der Server einen fehlgeschlagenen Modellaufruf wiederholen und den Turn abschließen kann.

`requires_action` bedeutet, dass die Sitzung für einen Tool-Aufruf pausiert hat. Was die Pause beendet, hängt vom Aufruf ab:

* **Ein Aufruf eines benutzerdefinierten Tools oder eine Anfrage zur Bestätigung eines Tool-Aufrufs:** Nur dein Code kann darauf antworten. Wenn dein Agent eines davon verwendet, siehe [Tool-Aufrufe beantworten, die die Session pausieren](https://platform.claude.com/docs/de/managed-agents/events-and-streaming#answer-tool-calls-that-pause-the-session).
* **Ein Aufruf eines Tools, das ein Worker ausführt, etwa `bash`:** Dieser Aufruf pausiert die Sitzung normalerweise nicht. Wenn etwa 3 Minuten lang kein Worker den Aufruf übernimmt, pausiert die Sitzung, bis ein Worker das Ergebnis zurückgibt. Dein Code muss dann nichts beantworten. Halte den Stream offen, und der Turn wird fortgesetzt, wenn ein Worker den Aufruf ausführt.

Um die anderen Events zu sehen, die eine Sitzung sendet, und zu erfahren, wie du dich erneut verbindest, ohne eines zu verpassen, siehe [Session-Event-Stream](https://platform.claude.com/docs/de/managed-agents/events-and-streaming).

## Daten in eine Sitzung hinein- und aus ihr herausbringen

Daten gelangen über das Arbeitsverzeichnis des Workers in eine Sitzung und aus ihr heraus.

Auf dem Schnellstart-Stack startet der Container jeder Sitzung mit einem leeren `/workspace`-Verzeichnis, abgesehen von den Klonen der Repositories der Sitzung. Standardmäßig wird der Container etwa eine Minute nach dem Ende eines Turns beendet, und Docker löscht ihn zusammen mit diesem Verzeichnis. Alles, was eine Sitzung behalten muss, muss vorher über einen Tool-Aufruf, etwa einen Upload oder einen `git push`, nach außen gelangen.

Ein Container wird außerdem etwa eine Stunde nach seinem Start beendet, selbst mitten in einem Turn. Keine Einstellung ändert das. Der Turn wird in einem neuen Container fortgesetzt, normalerweise nach ein oder zwei Minuten, und dein Client erhält kein Event für den Wechsel. Der Wechsel hat zwei Kosten:

* **Befehle:** Alles, was im alten Container läuft, stoppt. Der neue Container führt den unterbrochenen Tool-Aufruf erneut von Anfang an aus, aber nichts startet einen Befehl neu, den der Agent im Hintergrund laufen gelassen hat.
* **Dateien:** Das `/workspace` des neuen Containers ist wieder leer, abgesehen von frischen Klonen der Repositories der Sitzung.

Lass den Agenten in einem langen Turn seine Arbeit fortlaufend hochladen oder pushen, und vermeide Befehle, die Schaden anrichten, wenn sie zweimal ausgeführt werden.

Unter Kubernetes behält eine Sitzung einen Pod höchstens etwa eine Stunde lang, und der Turn wird auf dieselbe Weise fortgesetzt. Zwei Dinge unterscheiden sich: Der neue Pod findet die Dateien der Sitzung in `/workspace`, und er startet etwa 6 Minuten, nachdem der alte Pod stoppt.

Lege bei Workern, die du selbst startest, Eingabedateien im Arbeitsverzeichnis ab, bevor du die Nachricht sendest, die sie benötigt. Lies Ausgabedateien anschließend von dort.

Wenn du selbst für jede Sitzung einen Container startest, binde ein Verzeichnis, das die Eingabedateien der Sitzung enthält, als Arbeitsverzeichnis des Containers ein. Hole die Ausgabedateien von dort ab, nachdem der Container beendet wurde. Siehe [Dateien für eine Sitzung bereitstellen](https://platform.claude.com/docs/de/managed-agents/self-hosted-sandboxes-workers#stage-files-for-a-session).

## Weitere Beispiele in den Leitfäden des gehosteten Dienstes finden

Die Leitfäden des gehosteten Dienstes erklären die [Kernkonzepte](https://platform.claude.com/docs/de/managed-agents/overview#core-concepts) der API und enthalten Beispiele für jede Funktion. Ihre SDK- und CLI-Beispiele rufen deinen Server auf, wenn du sie in dem Terminal ausführst, in dem `ANTHROPIC_BASE_URL` und `ANTHROPIC_API_KEY` gesetzt sind. Ihre cURL-Beispiele nennen `https://api.anthropic.com`, ersetze diese Adresse also durch `$ANTHROPIC_BASE_URL`, bevor du eines ausführst.

Für manche Funktionen benötigt dein Server zuerst eine Einstellung, oder ein Beispiel benötigt eine Änderung:

| Aufgabe                                                              | Leitfaden des gehosteten Dienstes                                                                                                                                              | Auf deinem Server                                                                                                                                                                                                                                                                                                                                                     |
| -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Modell, System-Prompt und Versionen eines Agenten festlegen          | [Definiere deinen Agenten](https://platform.claude.com/docs/de/managed-agents/agent-setup)                                                                                     | Manche Felder [hängen von deinem Inferenzanbieter ab](https://platform.claude.com/docs/de/managed-agents/self-hosted/differences#differences-that-depend-on-your-inference-provider).                                                                                                                                                                                 |
| Integrierte Tools auswählen oder benutzerdefinierte Tools hinzufügen | [Tools](https://platform.claude.com/docs/de/managed-agents/tools)                                                                                                              | Um die Web-Tools zu verwenden, schalte sie zuerst ein, wie [Web-Tools benötigen eine Servereinstellung](https://platform.claude.com/docs/de/managed-agents/self-hosted/differences#web-tools-need-a-server-setting) beschreibt. Welche es gibt, hängt von deinem Inferenzanbieter ab.                                                                                 |
| Einen MCP-Server verbinden und sein Token speichern                  | [MCP-Connector](https://platform.claude.com/docs/de/managed-agents/mcp-connector) und [Mit Vaults authentifizieren](https://platform.claude.com/docs/de/managed-agents/vaults) | Füge den Host des MCP-Servers zur [Allowlist für MCP-Server](https://platform.claude.com/docs/de/managed-agents/self-hosted/differences#mcp-servers-need-an-allowlist-entry) hinzu. Speichere das Token als `static_bearer`-Anmeldedaten.                                                                                                                             |
| Einem Agenten Skills geben                                           | [Skills](https://platform.claude.com/docs/de/managed-agents/skills)                                                                                                            | Lade jeden Skill als einzelne Dateien hoch, da dein Server ein Zip-Archiv ablehnt. Die [vorgefertigten Skills](https://platform.claude.com/docs/de/managed-agents/self-hosted/differences#features-that-arent-available) in den Beispielen jenes Leitfadens sind nicht verfügbar.                                                                                     |
| Speicher über Sitzungen hinweg behalten                              | [Agentenspeicher verwenden](https://platform.claude.com/docs/de/managed-agents/memory)                                                                                         | Wenn du deine eigenen Worker betreibst, gib ihnen ein beschreibbares `/mnt/memory`-Verzeichnis, wie in [Speicher in selbst gehosteten Sandboxes](https://platform.claude.com/docs/de/managed-agents/self-hosted-sandboxes-memory).                                                                                                                                    |
| Arbeit an andere Agenten übergeben                                   | [Multiagenten-Orchestrierung](https://platform.claude.com/docs/de/managed-agents/multiagent-orchestration)                                                                     | Ersetze den `multiagent_20261001`-Block in den Beispielen jenes Leitfadens durch einen [`coordinator`-Block](https://platform.claude.com/docs/de/managed-agents/self-hosted/differences#features-that-behave-differently).                                                                                                                                            |
| In einem Git-Repository arbeiten                                     | [Auf GitHub zugreifen](https://platform.claude.com/docs/de/managed-agents/github)                                                                                              | Trage den Git-Host in den Einstellungen deines Servers ein, wie [Git-Repositories benötigen einen Allowlist-Eintrag](https://platform.claude.com/docs/de/managed-agents/self-hosted/differences#git-repositories-need-an-allowlist-entry) beschreibt. Der Beispiel-Agent jenes Leitfadens benötigt außerdem `api.githubcopilot.com` auf der Allowlist für MCP-Server. |
| Die Arbeit von einem Bewerter anhand einer Rubrik prüfen lassen      | [Ergebnisse definieren](https://platform.claude.com/docs/de/managed-agents/define-outcomes)                                                                                    | Sende die Rubrik als Text. Die Files API ist nicht verfügbar, also [hole Ausgabedateien](https://platform.claude.com/docs/de/managed-agents/self-hosted/call-the-api#move-data-in-and-out-of-a-session) aus dem Arbeitsverzeichnis ab.                                                                                                                                |
| Eine Sitzung verfolgen und ihre Tool-Aufrufe beantworten             | [Session-Event-Stream](https://platform.claude.com/docs/de/managed-agents/events-and-streaming)                                                                                | Das erste Beispiel jenes Leitfadens schließt den Stream bei jeder Pause, beginne also stattdessen mit der Schleife in [Eine Nachricht senden und die Antwort lesen](https://platform.claude.com/docs/de/managed-agents/self-hosted/call-the-api#send-a-message-and-read-the-reply).                                                                                   |

[Unterschiede zum gehosteten Dienst](https://platform.claude.com/docs/de/managed-agents/self-hosted/differences) enthält die vollständige Liste. Prüfe sie, bevor du eine bestehende Anwendung umziehst.

## Eigene Worker betreiben

Der [Schnellstart-Stack](https://platform.claude.com/docs/de/managed-agents/self-hosted/quickstart) erstellt eine Umgebung und betreibt die Worker dieser Umgebung. Das tun auch die Helm-Charts in [Auf Kubernetes bereitstellen](https://platform.claude.com/docs/de/managed-agents/self-hosted/kubernetes). Wenn diese Worker alles sind, was du brauchst, überspringe diesen Abschnitt.

Du betreibst Worker wie bei [selbst gehosteten Sandboxes](https://platform.claude.com/docs/de/managed-agents/self-hosted-sandboxes): mit denselben `ant beta:worker`-Befehlen und SDK-Workern, auf die Weisen, die [Selbst gehostete Worker bereitstellen](https://platform.claude.com/docs/de/managed-agents/self-hosted-sandboxes-workers) zeigt. Die Ausnahme sind durch Webhooks ausgelöste Worker, da dein Server keine sendet.

### Eine Umgebung und ihren Schlüssel erstellen

Erstelle mit der Admin-CLI, nicht in der Claude Console, eine Umgebung und einen „environment key“ (Umgebungsschlüssel). Die CLI, `cma-server-admin`, liegt in der obersten Ebene des Release-Archivs, führe den Befehl also von dort aus. Übergib für `-base-url` die Adresse, unter der deine Worker den Server erreichen:

* **Worker auf dem Rechner, auf dem der Schnellstart-Stack läuft:** `http://127.0.0.1:8400`
* **Worker auf einem anderen Rechner:** die `https`-Adresse des [TLS-Proxys, den du vor den Server schaltest](https://platform.claude.com/docs/de/managed-agents/self-hosted/kubernetes#put-tls-in-front-of-the-server)

Die Admin-CLI ruft den Server unter derselben Adresse auf, führe sie also auf einem Rechner aus, der diese Adresse erreichen kann.

```bash
echo "$ANTHROPIC_API_KEY" | ./cma-server-admin bootstrap \
  -base-url http://127.0.0.1:8400 -name my-env -key-file -
```

Der Befehl gibt die Einstellungen des Workers, den Befehl zum Starten eines Workers sowie die ID und das Ablaufdatum des Schlüssels aus:

```text wrap
export ANTHROPIC_BASE_URL='http://127.0.0.1:8400'
export ANTHROPIC_ENVIRONMENT_ID='env_...'
export ANTHROPIC_ENVIRONMENT_KEY='sk-ant-oat01-...'
# then: histchars= HISTFILE=/dev/null ant beta:worker poll --workdir /workspace
# key id: 'etok_...'  expires: '...'
```

Der Befehl zeigt den Schlüssel nur einmal an, speichere also den Schlüssel, seine ID und sein Ablaufdatum in deinem Secret-Manager. Der Schlüssel funktioniert nach 365 Tagen nicht mehr. Befolge vorher [Einen Umgebungsschlüssel für deine eigenen Worker ersetzen](https://platform.claude.com/docs/de/managed-agents/self-hosted/kubernetes#replace-an-environment-key-for-your-own-workers).

Halte den Server-API-Key von den Rechnern fern, auf denen Worker laufen. Führe Worker in einem Container oder einer VM aus, die nichts enthalten, was du schützen musst. Deine weiteren Sicherheitspflichten findest du unter [Deine Verantwortlichkeiten für die Sicherheit](https://platform.claude.com/docs/de/managed-agents/self-hosted#your-security-responsibilities).

### Ein lokales Experiment ausführen

Führe die drei `export`-Zeilen in der Shell aus, in der du den Worker startest. Starte den Worker dann mit diesen Befehlen, nicht mit dem ausgegebenen. Der erste Befehl erstellt das Arbeitsverzeichnis des Workers, da der Worker es nicht erstellt:

```bash
mkdir -p "$HOME/cma-workspace" "$HOME/.config/cma"
cat > "$HOME/.config/cma/worker.inputrc" <<'EOF'
$include /etc/inputrc
set disable-completion on
EOF
histchars= HISTFILE=/dev/null INPUTRC="$HOME/.config/cma/worker.inputrc" \
  ant beta:worker poll --workdir "$HOME/cma-workspace"
```

`histchars`, `INPUTRC` und `HISTFILE` richten die Shell hinter dem `bash`-Tool des Workers so ein, dass sie jeden Befehl so ausführt, wie der Agent ihn geschrieben hat:

* **`histchars=`:** Die Shell behandelt `!` nicht als Verweis auf ihren Befehlsverlauf.
* **`INPUTRC`:** Die Datei schaltet die Vervollständigung aus, die sonst jedes Tabulatorzeichen in einem Befehl verbrauchen würde. Halte die Datei aus dem Arbeitsverzeichnis heraus, wo die Datei-Tools des Agenten sie überschreiben könnten.
* **`HISTFILE=/dev/null`:** Die Shell liest und schreibt keine Verlaufsdatei.

Verwende diesen Worker für nichts anderes. Er hält den Umgebungsschlüssel und führt die Tools jeder Sitzung in einem einzigen Prozess aus. Er klont auch nicht die Repositories einer Sitzung. Die Sitzung läuft ohne sie, und dein Client erhält keinen Fehler.

### Worker in der Produktion betreiben

Für alles außer einem lokalen Experiment starte für jede Sitzung einen Container und führe darin `ant beta:worker run` aus, wie [Eine Sandbox pro Sitzung ausführen](https://platform.claude.com/docs/de/managed-agents/self-hosted-sandboxes-workers#run-one-sandbox-per-session) zeigt. Gib seinem Image, was [Ein eigenes Sandbox-Image erstellen](https://platform.claude.com/docs/de/managed-agents/self-hosted/call-the-api#build-your-own-sandbox-image) auflistet, und ändere drei Dinge in diesem Setup:

* **Umgebungsschlüssel:** Übergib `ANTHROPIC_ENVIRONMENT_KEY` nicht an den Container einer Sitzung. Der Server akzeptiert diesen Schlüssel für jede Sitzung in der Umgebung, und der Container benötigt nur Zugriff auf eine Sitzung.
* **Secret des Work-Items:** Übergib dieses Secret anstelle des Schlüssels, weil der Server es nur für diese eine Sitzung akzeptiert. [Das Secret des Arbeitselements weiterleiten](https://platform.claude.com/docs/de/managed-agents/self-hosted-sandboxes-workers#forward-the-work-items-secret) zeigt, wo dein Code es empfängt. Wo jener Abschnitt `ANTHROPIC_WORK_SECRET` setzt, lege das Secret in einer Datei ab, die nur der Benutzer des Containers lesen kann. Leite das Secret zum Beispiel per Pipe an die Standardeingabe des Containers weiter und lass den Container die Datei schreiben, bevor er den Worker startet. Setze dann `ANTHROPIC_WORK_SECRET_FILE` auf den Pfad der Datei.
* **Serveradresse:** Setze `ANTHROPIC_BASE_URL` auf eine Adresse, die der Container erreichen kann. `http://127.0.0.1:8400` ist keine solche Adresse.

Für einen SDK-Worker gelten zwei weitere Punkte:

* **Version:** Baue den Worker auf der neuesten Version des SDK auf, wie [SDKs, CLI und Bibliotheken](https://platform.claude.com/docs/de/cli-sdks-libraries/overview) beschreibt. Der Worker dieser Version wartet auf eine Bestätigung, bevor er einen Tool-Aufruf ausführt, der sie benötigt, und führt nie einen Aufruf aus, den eine Richtlinie ablehnt. Ein Worker, der auf einer früheren Version aufbaut, führt jeden Tool-Aufruf aus, sobald er eintrifft.
* **Beispiele:** Die Beispiele in [Den SDK-Worker innerhalb der Sandbox ausführen](https://platform.claude.com/docs/de/managed-agents/self-hosted-sandboxes-workers#run-the-sdk-worker-inside-the-sandbox) lesen den Umgebungsschlüssel, daher funktionieren sie hier nicht unverändert.

### Ein eigenes Sandbox-Image erstellen

Ein eigenes Image benötigt diese Pakete und Einstellungen:

* **Pakete:** Git 2.38 oder höher, `curl`, `jq` und ripgrep, mit dem das `grep`-Tool des Workers sucht.

* **Shell-Einstellungen:** `histchars`, `HISTFILE` und `INPUTRC`, wie im lokalen Experiment, sowie `TERMINFO`. Füge diese Zeilen in das Dockerfile ein, vor jeder `USER`-Zeile:

  ```dockerfile
  ENV histchars=
  RUN printf '\nset disable-completion on\n' >> /etc/inputrc
  ENV INPUTRC=/etc/inputrc TERMINFO=/etc/terminfo HISTFILE=/dev/null
  RUN test -r /etc/terminfo/d/dumb
  ```

  `TERMINFO` muss das Verzeichnis angeben, das `d/dumb` enthält, die Terminalbeschreibung, die das `bash` des Workers liest. Unter Alpine mit installiertem `bash` ist das `/etc/terminfo`, wie gezeigt. Auf einer anderen Basis, etwa Debian oder Ubuntu, ist es `/lib/terminfo` oder `/usr/share/terminfo`, je nachdem, welches `d/dumb` enthält. Trage dieses Verzeichnis in der `TERMINFO`-Einstellung und in der `RUN test`-Zeile ein, die den Build stoppt, wenn die Datei fehlt.

Das Image benötigt außerdem zwei Skripte aus dem Archiv, die ausgeführt werden, bevor der Worker startet:

1. Kopiere `image-build/with-repositories.sh` nach `/usr/local/bin/cma-with-repositories`. Es klont die Repositories einer Sitzung.
2. Kopiere `image-build/with-egress.sh` nach `/usr/local/bin/cma-with-egress`. Es richtet die Tools der Sitzung auf das [Egress-Gateway](https://platform.claude.com/docs/de/managed-agents/self-hosted/agent-identity#environment-variable-credentials) aus, falls dein Server eines betreibt.
3. Mache beide Dateien ausführbar.
4. Stelle beide dem Befehl des Workers voran, wie in `cma-with-egress cma-with-repositories ant beta:worker run ...`. Überspringe diesen Schritt, wenn dein Image das `kubernetes/sandbox/worker.sh` des Archivs ausführt, weil dieses Skript den Worker auf diese Weise startet.

Ein Worker, der ohne `cma-with-repositories` startet, führt die Sitzung ohne Repository aus. Dein Client erhält keinen Fehler.

### Worker vom gehosteten Dienst umziehen

Wenn du bereits Worker für den gehosteten Dienst von Anthropic betreibst, können dieselben Worker stattdessen deinen Server bedienen. Tu drei Dinge:

* Übergib dem Prozess, der nach Arbeit pollt, die drei `export`-Werte, die die Admin-CLI ausgegeben hat.
* Starte diesen Prozess mit gesetzten `histchars`, `HISTFILE` und `INPUTRC`, wie im lokalen Experiment.
* Nimm die Änderungen vor, die [Worker in der Produktion betreiben](https://platform.claude.com/docs/de/managed-agents/self-hosted/call-the-api#run-workers-in-production) beschreibt, und prüfe das Image jeder Sitzung anhand von [Ein eigenes Sandbox-Image erstellen](https://platform.claude.com/docs/de/managed-agents/self-hosted/call-the-api#build-your-own-sandbox-image).

## Nächste Schritte

* [Entwicklern die Anmeldung über ein Terminal ermöglichen](https://platform.claude.com/docs/de/managed-agents/self-hosted/configure#let-developers-log-in-from-a-terminal): Richte Single Sign-on ein, damit Entwickler die `ant` CLI unter ihrer eigenen Identität verwenden, in einem Terminal ohne `ANTHROPIC_API_KEY`.
* [Agent-Identität und Anmeldeinformationen](https://platform.claude.com/docs/de/managed-agents/self-hosted/agent-identity): Lass externe Systeme deinen Agents vertrauen, und bewahre Vault-Anmeldedaten in deinem Secret-Manager auf.
* [Inferenzanbieter](https://platform.claude.com/docs/de/managed-agents/self-hosted/inference-provider): Sende Modellaufrufe an einen Cloud-Anbieter oder dein eigenes Modell-Gateway.
