---
title: Llamar a la API en un servidor autoalojado
url: https://platform.claude.com/docs/es/managed-agents/self-hosted/call-the-api
description: Apunta el SDK oficial, cURL o la CLI de ant a tu servidor autoalojado de Claude Managed Agents, inicia una sesión y lee la respuesta del agente. Después, conecta tus propios workers, si los necesitas.
---

<Note>
  Para solicitar acceso a Claude Managed Agents autoalojado, ponte en contacto con el equipo de tu cuenta de Anthropic.
</Note>

Un servidor autoalojado de Claude Managed Agents tiene la misma API que el servicio alojado de [Managed Agents](https://platform.claude.com/docs/es/managed-agents/overview) de Anthropic. Tu código lo llama con el SDK oficial, cURL o la CLI `ant`. Cambian dos cosas: la URL base es la dirección de tu servidor, y la clave de API es tu [clave de API del servidor](https://platform.claude.com/docs/es/managed-agents/self-hosted#the-three-credentials) en lugar de una clave de API de Claude.

Para crear agentes y ejecutar sesiones en un navegador, consulta [Usar la consola en tu servidor](https://platform.claude.com/docs/es/managed-agents/self-hosted/console).

## Requisitos previos

* **Un servidor en ejecución:** Inicia uno con [Comenzar con Claude Managed Agents autoalojado](https://platform.claude.com/docs/es/managed-agents/self-hosted/quickstart) o [Implementar en Kubernetes](https://platform.claude.com/docs/es/managed-agents/self-hosted/kubernetes).
* **Acceso al servidor:** Si otra persona ejecuta el servidor, pídele su dirección y cómo autenticarte. Si usa el inicio de sesión único, consulta [Permitir que los desarrolladores inicien sesión desde una terminal](https://platform.claude.com/docs/es/managed-agents/self-hosted/configure#let-developers-log-in-from-a-terminal).
* **La CLI `ant`:** Instala la versión más reciente, como se muestra en el [inicio rápido de la CLI](https://platform.claude.com/docs/es/cli-sdks-libraries/cli/quickstart#installation).

## Apuntar tu cliente a tu servidor

El SDK y la CLI `ant` leen la dirección del servidor desde `ANTHROPIC_BASE_URL` y la clave de API desde `ANTHROPIC_API_KEY`. Define ambas variables en una terminal que reserves para este servidor.

Para el [stack del inicio rápido](https://platform.claude.com/docs/es/managed-agents/self-hosted/quickstart), ejecuta estos comandos desde el directorio que contiene tu archivo `.env`:

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

En Kubernetes, define las dos variables como se muestra en [Ejecutar una sesión](https://platform.claude.com/docs/es/managed-agents/self-hosted/kubernetes#run-a-session) y mantén en ejecución su port-forward.

En esa terminal, cada comando `ant`, como `ant beta:agents list`, llega a tu servidor. No ejecutes Claude Code ni `docker compose` en esa terminal, porque leen las mismas variables.

## Iniciar una sesión

Una sesión necesita el ID de un agente y el ID de un entorno:

* **Agente:** Crea uno como se muestra en [Crear un agente](https://platform.claude.com/docs/es/managed-agents/agent-setup#create-an-agent), con tu cliente apuntando a tu servidor. Si envías solicitudes HTTP directas, reemplaza `https://api.anthropic.com` en la URL por `$ANTHROPIC_BASE_URL`.
* **Entorno:** El stack del inicio rápido crea uno llamado `compose-sandbox`, y los charts de Helm crean uno llamado `default`. `ant beta:environments list` imprime el nombre y el ID de cada entorno. Para tus propios workers, es el ID que la CLI de administración imprimió en [Ejecutar tus propios workers](https://platform.claude.com/docs/es/managed-agents/self-hosted/call-the-api#point-a-worker-at-your-server).

Coloca tus dos ID en tu shell, en lugar de estos ID de ejemplo:

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

El siguiente ejemplo crea una sesión y envía su primer mensaje en la misma solicitud:

<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>

La respuesta contiene el ID de la sesión, que comienza con `sesn_`. El agente empieza a trabajar de inmediato. Sus herramientas integradas, como `bash`, se ejecutan en un worker que sirve el entorno.

Para observar la sesión, abre la [consola de tu servidor](https://platform.claude.com/docs/es/managed-agents/self-hosted/console) en un navegador, selecciona **Sessions** y, a continuación, selecciona la sesión. Una sesión que iniciaste con la clave de API del servidor, como en esta página, solo es visible para los administradores.

Para seguir la sesión en tu terminal, pasa su ID a [`ant beta:sessions connect`](https://platform.claude.com/docs/es/cli-sdks-libraries/cli/sessions-connect):

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

Para saber qué más puede hacer una sesión, como fijar una versión del agente, consulta [Iniciar una sesión](https://platform.claude.com/docs/es/managed-agents/sessions).

## Enviar un mensaje y leer la respuesta

Coloca el ID de tu sesión en tu shell, en lugar de este ID de ejemplo:

```bash
export SESSION_ID=sesn_011CZkZAtmR3yMPDzynEDxu7
```

Espera hasta que la sesión esté inactiva antes de ejecutar el siguiente ejemplo. El ejemplo deja de leer cuando termina un turno. Si un turno anterior sigue en curso, su final puede detener el ejemplo antes de que llegue la respuesta a tu mensaje. Tanto la consola como `ant beta:sessions connect` muestran el estado de la sesión.

El siguiente ejemplo envía un mensaje e imprime la respuesta del agente. Primero abre el flujo de eventos de la sesión, porque un flujo entrega solo los eventos que llegan después de abrirse:

<CodeGroup exclude="shell">
  <CodeGroupItem language="cURL">
    Este flujo de trabajo necesita más lógica que un solo comando de shell. Usa el [SDK de Anthropic](https://platform.claude.com/docs/es/cli-sdks-libraries/overview) para ejecutarlo.
  </CodeGroupItem>

  <CodeGroupItem language="CLI">
    Este flujo de trabajo necesita más lógica que un solo comando de shell. Para enviar mensajes y leer las respuestas en tu terminal, usa [`ant beta:sessions connect`](https://platform.claude.com/docs/es/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
      # ignora otros tipos de eventos
    end
  end
  ```
</CodeGroup>

Además de imprimir el texto de `agent.message`, el bucle gestiona tres eventos:

* **`session.status_idle`:** El bucle termina, a menos que el `stop_reason.type` del evento sea `requires_action`.
* **`session.status_terminated`:** El bucle termina.
* **`session.error`:** El bucle imprime el mensaje del error y sigue leyendo, porque el servidor puede reintentar una llamada al modelo que falló y terminar el turno.

`requires_action` significa que la sesión se ha pausado para una llamada a herramienta. Lo que termina la pausa depende de la llamada:

* **Una llamada a una herramienta personalizada o una solicitud para confirmar una llamada a herramienta:** Solo tu código puede responderla. Si tu agente usa cualquiera de las dos, consulta [Responder a llamadas a herramientas que pausan la sesión](https://platform.claude.com/docs/es/managed-agents/events-and-streaming#answer-tool-calls-that-pause-the-session).
* **Una llamada a una herramienta que ejecuta un worker, como `bash`:** Esta llamada normalmente no pausa la sesión. Si ningún worker toma la llamada durante unos 3 minutos, la sesión se pausa hasta que un worker devuelve el resultado. En ese caso, tu código no tiene nada que responder. Mantén el flujo abierto, y el turno se reanuda cuando un worker ejecuta la llamada.

Para conocer los demás eventos que envía una sesión y cómo reconectarte sin perder ninguno, consulta [Flujo de eventos de la sesión](https://platform.claude.com/docs/es/managed-agents/events-and-streaming).

## Mover datos hacia dentro y fuera de una sesión

Los datos llegan a una sesión y salen de ella a través del directorio de trabajo del worker.

En el stack del inicio rápido, el contenedor de cada sesión comienza con un directorio `/workspace` vacío, salvo por los clones de los repositorios de la sesión. De forma predeterminada, aproximadamente un minuto después de que termina un turno, el contenedor finaliza y Docker lo elimina junto con ese directorio. Todo lo que una sesión deba conservar tiene que salir mediante una llamada a herramienta, como una subida o un `git push`, antes de ese momento.

Un contenedor también finaliza aproximadamente una hora después de iniciarse, incluso a mitad de un turno. Ninguna configuración cambia eso. El turno continúa en un contenedor nuevo, normalmente después de uno o dos minutos, y tu cliente no recibe ningún evento por el cambio. El cambio tiene dos costos:

* **Comandos:** Todo lo que se ejecuta en el contenedor anterior se detiene. El contenedor nuevo vuelve a ejecutar desde el principio la llamada a herramienta interrumpida, pero nada reinicia un comando que el agente dejó en ejecución en segundo plano.
* **Archivos:** El `/workspace` del contenedor nuevo vuelve a estar vacío, salvo por clones nuevos de los repositorios de la sesión.

En un turno largo, haz que el agente suba o envíe su trabajo a medida que avanza, y evita los comandos que causen daño si se ejecutan dos veces.

En Kubernetes, una sesión conserva un pod durante aproximadamente una hora como máximo, y el turno continúa de la misma manera. Hay dos diferencias: el pod nuevo encuentra los archivos de la sesión en `/workspace`, y se inicia unos 6 minutos después de que se detiene el pod anterior.

Para los workers que inicias tú mismo, coloca los archivos de entrada en el directorio de trabajo antes de enviar el mensaje que los necesita. Lee los archivos de salida de ese directorio después.

Cuando inicias tú mismo un contenedor para cada sesión, monta un directorio que contenga los archivos de entrada de la sesión como directorio de trabajo del contenedor. Recoge los archivos de salida de él después de que el contenedor termine. Consulta [Prepara archivos para una sesión](https://platform.claude.com/docs/es/managed-agents/self-hosted-sandboxes-workers#stage-files-for-a-session).

## Encontrar más ejemplos en las guías del servicio alojado

Las guías del servicio alojado explican los [conceptos principales](https://platform.claude.com/docs/es/managed-agents/overview#core-concepts) de la API e incluyen ejemplos para cada función. Sus ejemplos del SDK y de la CLI llaman a tu servidor cuando los ejecutas en la terminal donde están definidas `ANTHROPIC_BASE_URL` y `ANTHROPIC_API_KEY`. Sus ejemplos de cURL indican `https://api.anthropic.com`, así que reemplaza esa dirección por `$ANTHROPIC_BASE_URL` antes de ejecutar uno.

Para algunas funciones, tu servidor necesita primero una configuración, o un ejemplo necesita un cambio:

| Tarea                                                                        | Guía del servicio alojado                                                                                                                                               | En tu servidor                                                                                                                                                                                                                                                                                                                                                                                       |
| ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Establecer el modelo, la indicación del sistema y las versiones de un agente | [Define tu agente](https://platform.claude.com/docs/es/managed-agents/agent-setup)                                                                                      | Algunos campos [dependen de tu proveedor de inferencia](https://platform.claude.com/docs/es/managed-agents/self-hosted/differences#differences-that-depend-on-your-inference-provider).                                                                                                                                                                                                              |
| Elegir herramientas integradas o agregar herramientas personalizadas         | [Herramientas](https://platform.claude.com/docs/es/managed-agents/tools)                                                                                                | Para usar las herramientas web, primero actívalas, como se describe en [Las herramientas web necesitan una configuración del servidor](https://platform.claude.com/docs/es/managed-agents/self-hosted/differences#web-tools-need-a-server-setting). Cuáles existen depende de tu proveedor de inferencia.                                                                                            |
| Conectar un servidor MCP y almacenar su token                                | [Conector MCP](https://platform.claude.com/docs/es/managed-agents/mcp-connector) y [Autenticarse con vaults](https://platform.claude.com/docs/es/managed-agents/vaults) | Agrega el host del servidor MCP a la [lista de permitidos para servidores MCP](https://platform.claude.com/docs/es/managed-agents/self-hosted/differences#mcp-servers-need-an-allowlist-entry). Almacena el token como una credencial `static_bearer`.                                                                                                                                               |
| Dar skills a un agente                                                       | [Skills](https://platform.claude.com/docs/es/managed-agents/skills)                                                                                                     | Sube cada skill como archivos individuales, porque tu servidor rechaza un archivo zip. Las [skills prediseñadas](https://platform.claude.com/docs/es/managed-agents/self-hosted/differences#features-that-arent-available) de los ejemplos de esa guía no están disponibles.                                                                                                                         |
| Conservar memoria entre sesiones                                             | [Usar la memoria del agente](https://platform.claude.com/docs/es/managed-agents/memory)                                                                                 | Si ejecutas tus propios workers, proporciónales un directorio `/mnt/memory` con permisos de escritura, como en [Almacenes de memoria en sandboxes autoalojados](https://platform.claude.com/docs/es/managed-agents/self-hosted-sandboxes-memory).                                                                                                                                                    |
| Delegar trabajo a otros agentes                                              | [Orquestación multiagente](https://platform.claude.com/docs/es/managed-agents/multiagent-orchestration)                                                                 | Reemplaza el bloque `multiagent_20261001` de los ejemplos de esa guía por un [bloque `coordinator`](https://platform.claude.com/docs/es/managed-agents/self-hosted/differences#features-that-behave-differently).                                                                                                                                                                                    |
| Trabajar en un repositorio Git                                               | [Acceder a GitHub](https://platform.claude.com/docs/es/managed-agents/github)                                                                                           | Incluye el host de Git en la configuración de tu servidor, como se describe en [Los repositorios Git necesitan una entrada en la lista de permitidos](https://platform.claude.com/docs/es/managed-agents/self-hosted/differences#git-repositories-need-an-allowlist-entry). El agente de ejemplo de esa guía también necesita `api.githubcopilot.com` en la lista de permitidos para servidores MCP. |
| Hacer que un evaluador revise el trabajo según una rúbrica                   | [Definir resultados](https://platform.claude.com/docs/es/managed-agents/define-outcomes)                                                                                | Envía la rúbrica como texto. La Files API no está disponible, así que [recoge los archivos de salida](https://platform.claude.com/docs/es/managed-agents/self-hosted/call-the-api#move-data-in-and-out-of-a-session) del directorio de trabajo.                                                                                                                                                      |
| Seguir una sesión y responder a sus llamadas a herramientas                  | [Flujo de eventos de la sesión](https://platform.claude.com/docs/es/managed-agents/events-and-streaming)                                                                | El primer ejemplo de esa guía cierra el flujo ante cualquier pausa, así que parte en su lugar del bucle de [Enviar un mensaje y leer la respuesta](https://platform.claude.com/docs/es/managed-agents/self-hosted/call-the-api#send-a-message-and-read-the-reply).                                                                                                                                   |

[Diferencias con el servicio alojado](https://platform.claude.com/docs/es/managed-agents/self-hosted/differences) contiene la lista completa. Consúltala antes de migrar una aplicación existente.

## Ejecutar tus propios workers

El [stack del inicio rápido](https://platform.claude.com/docs/es/managed-agents/self-hosted/quickstart) crea un entorno y ejecuta sus workers. Lo mismo hacen los charts de Helm de [Implementar en Kubernetes](https://platform.claude.com/docs/es/managed-agents/self-hosted/kubernetes). Si esos workers son todo lo que necesitas, omite esta sección.

Ejecutas los workers como lo haces con los [sandboxes autoalojados](https://platform.claude.com/docs/es/managed-agents/self-hosted-sandboxes): los mismos comandos `ant beta:worker` y workers del SDK, de las formas que muestra [Implementar workers autoalojados](https://platform.claude.com/docs/es/managed-agents/self-hosted-sandboxes-workers). La excepción son los workers activados por webhooks, porque tu servidor no envía ninguno.

### Crear un entorno y su clave

Crea un entorno y una clave de entorno con la CLI de administración, no en la Claude Console. La CLI, `cma-server-admin`, está en el nivel superior del archivo de la versión, así que ejecuta el comando desde allí. Para `-base-url`, pasa la dirección en la que tus workers llegan al servidor:

* **Workers en la máquina que ejecuta el stack del inicio rápido:** `http://127.0.0.1:8400`
* **Workers en otra máquina:** la dirección `https` del [proxy TLS que colocas delante del servidor](https://platform.claude.com/docs/es/managed-agents/self-hosted/kubernetes#put-tls-in-front-of-the-server)

La CLI de administración llama al servidor en la misma dirección, así que ejecútala en una máquina que pueda alcanzar esa dirección.

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

El comando imprime la configuración del worker, el comando que inicia un worker, y el ID y la fecha de caducidad de la clave:

```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: '...'
```

El comando muestra la clave solo una vez, así que guarda la clave, su ID y su fecha de caducidad en tu gestor de secretos. La clave deja de funcionar después de 365 días. Antes de eso, sigue [Reemplazar una clave de entorno para tus propios workers](https://platform.claude.com/docs/es/managed-agents/self-hosted/kubernetes#replace-an-environment-key-for-your-own-workers).

Mantén la clave de API del servidor fuera de las máquinas que ejecutan workers. Ejecuta los workers en un contenedor o máquina virtual que no contenga nada que necesites proteger. Para tus demás responsabilidades de seguridad, consulta [Tus responsabilidades de seguridad](https://platform.claude.com/docs/es/managed-agents/self-hosted#your-security-responsibilities).

### Ejecutar un experimento local

Ejecuta las tres líneas `export` en el shell donde inicias el worker. Luego inicia el worker con estos comandos, no con el que se imprimió. El primer comando crea el directorio de trabajo del worker, porque el worker no lo crea:

```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` y `HISTFILE` configuran el shell detrás de la herramienta `bash` del worker, para que ejecute cada comando tal como lo escribió el agente:

* **`histchars=`:** El shell no interpreta `!` como una referencia a su historial de comandos.
* **`INPUTRC`:** El archivo desactiva el “completion” (autocompletado), que de otro modo consumiría cada carácter de tabulación de un comando. Mantén el archivo fuera del directorio de trabajo, donde las herramientas de archivos del agente podrían reescribirlo.
* **`HISTFILE=/dev/null`:** El shell no lee ni escribe ningún archivo de historial.

No uses este worker para nada más. Contiene la clave de entorno y ejecuta las herramientas de todas las sesiones en un solo proceso. Tampoco clona los repositorios de una sesión. La sesión se ejecuta sin ellos, y tu cliente no recibe ningún error.

### Ejecutar workers en producción

Para cualquier caso que no sea un experimento local, inicia un contenedor para cada sesión y ejecuta `ant beta:worker run` en él, como se muestra en [Ejecutar un sandbox por sesión](https://platform.claude.com/docs/es/managed-agents/self-hosted-sandboxes-workers#run-one-sandbox-per-session). Dale a su imagen lo que enumera [Crear tu propia imagen de sandbox](https://platform.claude.com/docs/es/managed-agents/self-hosted/call-the-api#build-your-own-sandbox-image) y cambia tres cosas en esa configuración:

* **Clave de entorno:** No pases `ANTHROPIC_ENVIRONMENT_KEY` al contenedor de una sesión. El servidor acepta esa clave para todas las sesiones del entorno, y el contenedor solo necesita acceso a una sesión.
* **Secreto del elemento de trabajo:** Pasa este secreto en lugar de la clave, porque el servidor lo acepta solo para esa sesión. [Reenvía el secreto del elemento de trabajo](https://platform.claude.com/docs/es/managed-agents/self-hosted-sandboxes-workers#forward-the-work-items-secret) muestra dónde lo recibe tu código. Donde esa sección establece `ANTHROPIC_WORK_SECRET`, coloca el secreto en un archivo que solo el usuario del contenedor pueda leer. Por ejemplo, canaliza el secreto a la entrada estándar del contenedor y haz que el contenedor escriba el archivo antes de iniciar el worker. Luego establece `ANTHROPIC_WORK_SECRET_FILE` en la ruta del archivo.
* **Dirección del servidor:** Establece `ANTHROPIC_BASE_URL` en una dirección que el contenedor pueda alcanzar. `http://127.0.0.1:8400` no lo es.

Para un worker del SDK, se aplican dos puntos más:

* **Versión:** Compila el worker con la versión más reciente del SDK, como se describe en [SDKs, CLI y bibliotecas](https://platform.claude.com/docs/es/cli-sdks-libraries/overview). El worker de esa versión espera la aprobación antes de ejecutar una llamada a herramienta que la necesite, y nunca ejecuta una llamada que una política deniega. Un worker compilado con una versión anterior ejecuta cada llamada a herramienta en cuanto llega.
* **Ejemplos:** Los ejemplos de [Ejecutar el worker del SDK dentro del sandbox](https://platform.claude.com/docs/es/managed-agents/self-hosted-sandboxes-workers#run-the-sdk-worker-inside-the-sandbox) leen la clave de entorno, así que no funcionan aquí tal como están.

### Crear tu propia imagen de sandbox

Una imagen propia necesita estos paquetes y ajustes:

* **Paquetes:** Git 2.38 o posterior, `curl`, `jq` y ripgrep, con el que busca la herramienta `grep` del worker.

* **Ajustes del shell:** `histchars`, `HISTFILE` e `INPUTRC`, como en el experimento local, y `TERMINFO`. Coloca estas líneas en el Dockerfile, antes de cualquier línea `USER`:

  ```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` debe indicar el directorio que contiene `d/dumb`, la descripción de terminal que lee el `bash` del worker. En Alpine con `bash` instalado, es `/etc/terminfo`, como se muestra. En otra base, como Debian o Ubuntu, es `/lib/terminfo` o `/usr/share/terminfo`, el que contenga `d/dumb`. Escribe ese directorio en el ajuste `TERMINFO` y en la línea `RUN test`, que detiene la compilación si falta el archivo.

La imagen también necesita dos scripts del archivo, que se ejecutan antes de que se inicie el worker:

1. Copia `image-build/with-repositories.sh` a `/usr/local/bin/cma-with-repositories`. Clona los repositorios de una sesión.
2. Copia `image-build/with-egress.sh` a `/usr/local/bin/cma-with-egress`. Dirige las herramientas de la sesión al [gateway de salida](https://platform.claude.com/docs/es/managed-agents/self-hosted/agent-identity#environment-variable-credentials), si tu servidor ejecuta uno.
3. Haz ejecutables ambos archivos.
4. Coloca ambos delante del comando del worker, como en `cma-with-egress cma-with-repositories ant beta:worker run ...`. Omite este paso si tu imagen ejecuta el `kubernetes/sandbox/worker.sh` del archivo, porque ese script inicia el worker de esta manera.

Un worker que se inicia sin `cma-with-repositories` ejecuta la sesión sin ningún repositorio. Tu cliente no recibe ningún error.

### Trasladar workers desde el servicio alojado

Si ya ejecutas workers para el servicio alojado de Anthropic, esos mismos workers pueden servir a tu servidor en su lugar. Haz tres cosas:

* Pasa al proceso que sondea en busca de trabajo los tres valores `export` que imprimió la CLI de administración.
* Inicia ese proceso con `histchars`, `HISTFILE` e `INPUTRC` definidas, como en el experimento local.
* Aplica los cambios que describe [Ejecutar workers en producción](https://platform.claude.com/docs/es/managed-agents/self-hosted/call-the-api#run-workers-in-production) y compara la imagen de cada sesión con [Crear tu propia imagen de sandbox](https://platform.claude.com/docs/es/managed-agents/self-hosted/call-the-api#build-your-own-sandbox-image).

## Próximos pasos

* [Permitir que los desarrolladores inicien sesión desde una terminal](https://platform.claude.com/docs/es/managed-agents/self-hosted/configure#let-developers-log-in-from-a-terminal): Configura el inicio de sesión único, para que los desarrolladores usen la CLI `ant` con su propia identidad, en una terminal sin `ANTHROPIC_API_KEY`.
* [Identidad y credenciales del agente](https://platform.claude.com/docs/es/managed-agents/self-hosted/agent-identity): Permite que los sistemas externos confíen en tus agentes y mantén las credenciales de vault en tu gestor de secretos.
* [Proveedor de inferencia](https://platform.claude.com/docs/es/managed-agents/self-hosted/inference-provider): Envía las llamadas al modelo a un proveedor de nube o a tu propio gateway de modelos.
