---
title: Chiamare l'API su un server self-hosted
url: https://platform.claude.com/docs/it/managed-agents/self-hosted/call-the-api
description: Punta l'SDK ufficiale, cURL o la CLI ant al tuo server self-hosted di Claude Managed Agents, avvia una sessione e leggi la risposta dell'agente. Poi collega i tuoi worker, se ti servono.
---

<Note>
  Per richiedere l’accesso a Claude Managed Agents self-hosted, contatta il tuo team di riferimento Anthropic.
</Note>

Un server self-hosted di Claude Managed Agents ha la stessa API del servizio ospitato [Managed Agents](https://platform.claude.com/docs/it/managed-agents/overview) di Anthropic. Il tuo codice lo chiama con l’SDK ufficiale, cURL o la CLI `ant`. Cambiano due cose: il “base URL” (URL di base) è l’indirizzo del tuo server, e la chiave API è la tua [chiave API del server](https://platform.claude.com/docs/it/managed-agents/self-hosted#the-three-credentials) invece di una chiave API di Claude.

Per creare agenti ed eseguire sessioni in un browser, consulta [Usa la console sul tuo server](https://platform.claude.com/docs/it/managed-agents/self-hosted/console).

## Prerequisiti

* **Un server in esecuzione:** Avviane uno con [Iniziare con Claude Managed Agents self-hosted](https://platform.claude.com/docs/it/managed-agents/self-hosted/quickstart) o [Distribuire su Kubernetes](https://platform.claude.com/docs/it/managed-agents/self-hosted/kubernetes).
* **Accesso al server:** Se il server è gestito da qualcun altro, chiedigli il suo indirizzo e come autenticarti. Se usa il single sign-on, consulta [Consentire agli sviluppatori di accedere da un terminale](https://platform.claude.com/docs/it/managed-agents/self-hosted/configure#let-developers-log-in-from-a-terminal).
* **La CLI `ant`:** Installa la versione più recente, come mostra la [guida rapida della CLI](https://platform.claude.com/docs/it/cli-sdks-libraries/cli/quickstart#installation).

## Puntare il tuo client al tuo server

L’SDK e la CLI `ant` leggono l’indirizzo del server da `ANTHROPIC_BASE_URL` e la chiave API da `ANTHROPIC_API_KEY`. Imposta entrambe le variabili in un terminale che dedichi a questo server.

Per lo [stack della guida rapida](https://platform.claude.com/docs/it/managed-agents/self-hosted/quickstart), esegui questi comandi dalla directory che contiene il tuo file `.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)
```

Su Kubernetes, imposta le due variabili come mostrato in [Eseguire una sessione](https://platform.claude.com/docs/it/managed-agents/self-hosted/kubernetes#run-a-session) e mantieni in esecuzione il suo port-forward.

In quel terminale, ogni comando `ant`, come `ant beta:agents list`, raggiunge il tuo server. Non eseguire Claude Code o `docker compose` in quel terminale, perché leggono le stesse variabili.

## Avviare una sessione

Una sessione richiede l’ID di un agente e l’ID di un ambiente:

* **Agente:** Creane uno come mostrato in [Creare un agente](https://platform.claude.com/docs/it/managed-agents/agent-setup#create-an-agent), con il tuo client puntato al tuo server. Se invii richieste HTTP dirette, sostituisci `https://api.anthropic.com` nell’URL con `$ANTHROPIC_BASE_URL`.
* **Ambiente:** Lo stack della guida rapida ne crea uno chiamato `compose-sandbox`, e i chart Helm ne creano uno chiamato `default`. `ant beta:environments list` stampa il nome e l’ID di ciascun ambiente. Per i tuoi worker, è l’ID che la CLI di amministrazione ha stampato in [Eseguire i tuoi worker](https://platform.claude.com/docs/it/managed-agents/self-hosted/call-the-api#point-a-worker-at-your-server).

Inserisci i tuoi due ID nella tua shell, al posto di questi ID di esempio:

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

L’esempio seguente crea una sessione e invia il suo primo messaggio nella stessa richiesta:

<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 risposta contiene l’ID della sessione, che inizia con `sesn_`. L’agente inizia subito a lavorare. I suoi strumenti integrati, come `bash`, vengono eseguiti su un worker che serve l’ambiente.

Per osservare la sessione, apri la [console sul tuo server](https://platform.claude.com/docs/it/managed-agents/self-hosted/console) in un browser, seleziona **Sessions**, quindi seleziona la sessione. Una sessione che hai avviato con la chiave API del server, come in questa pagina, è visibile solo agli amministratori.

Per seguire invece la sessione nel tuo terminale, passa il suo ID a [`ant beta:sessions connect`](https://platform.claude.com/docs/it/cli-sdks-libraries/cli/sessions-connect):

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

Per le altre cose che una sessione può fare, come fissare una versione dell’agente, consulta [Avviare una sessione](https://platform.claude.com/docs/it/managed-agents/sessions).

## Inviare un messaggio e leggere la risposta

Inserisci l’ID della tua sessione nella tua shell, al posto di questo ID di esempio:

```bash
export SESSION_ID=sesn_011CZkZAtmR3yMPDzynEDxu7
```

Attendi che la sessione sia inattiva prima di eseguire il prossimo esempio. L’esempio smette di leggere quando un turno termina. Se un turno precedente è ancora in esecuzione, la sua fine può fermare l’esempio prima che arrivi la risposta al tuo messaggio. Sia la console sia `ant beta:sessions connect` mostrano lo stato della sessione.

L’esempio seguente invia un messaggio e stampa la risposta dell’agente. Apre prima il flusso di eventi della sessione, perché un flusso consegna solo gli eventi che arrivano dopo la sua apertura:

<CodeGroup exclude="shell">
  <CodeGroupItem language="cURL">
    Questo flusso di lavoro richiede più logica di un singolo comando shell. Usa l’[SDK di Anthropic](https://platform.claude.com/docs/it/cli-sdks-libraries/overview) per eseguirlo.
  </CodeGroupItem>

  <CodeGroupItem language="CLI">
    Questo flusso di lavoro richiede più logica di un singolo comando shell. Per inviare messaggi e leggere le risposte nel tuo terminale, usa [`ant beta:sessions connect`](https://platform.claude.com/docs/it/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 gli altri tipi di evento
    end
  end
  ```
</CodeGroup>

Oltre a stampare il testo di `agent.message`, il ciclo gestisce tre eventi:

* **`session.status_idle`:** Il ciclo termina, a meno che il `stop_reason.type` dell’evento non sia `requires_action`.
* **`session.status_terminated`:** Il ciclo termina.
* **`session.error`:** Il ciclo stampa il messaggio dell’errore e continua a leggere, perché il server può ritentare una chiamata al modello non riuscita e completare il turno.

`requires_action` significa che la sessione è in pausa per una chiamata a uno strumento. Ciò che pone fine alla pausa dipende dalla chiamata:

* **Una chiamata a uno strumento personalizzato, o una richiesta di conferma di una chiamata a uno strumento:** Solo il tuo codice può rispondere. Se il tuo agente usa l’una o l’altra, consulta [Rispondere alle chiamate agli strumenti che mettono in pausa la sessione](https://platform.claude.com/docs/it/managed-agents/events-and-streaming#answer-tool-calls-that-pause-the-session).
* **Una chiamata a uno strumento eseguito da un worker, come `bash`:** Questa chiamata normalmente non mette in pausa la sessione. Se nessun worker prende in carico la chiamata per circa 3 minuti, la sessione va in pausa finché un worker non restituisce il risultato. In quel caso il tuo codice non ha nulla a cui rispondere. Mantieni aperto il flusso, e il turno riprende quando un worker esegue la chiamata.

Per gli altri eventi che una sessione invia, e per come riconnettersi senza perderne nessuno, consulta [Flusso di eventi della sessione](https://platform.claude.com/docs/it/managed-agents/events-and-streaming).

## Spostare dati dentro e fuori da una sessione

I dati entrano in una sessione e ne escono attraverso la directory di lavoro del worker.

Nello stack della guida rapida, il container di ogni sessione parte con una directory `/workspace` vuota, fatta eccezione per i cloni dei repository della sessione. Per impostazione predefinita, circa un minuto dopo la fine di un turno, il container termina e Docker lo elimina insieme a quella directory. Tutto ciò che una sessione deve conservare deve uscire tramite una chiamata a uno strumento, come un upload o un `git push`, prima di allora.

Un container termina anche circa un’ora dopo l’avvio, persino nel mezzo di un turno. Nessuna impostazione modifica questo comportamento. Il turno prosegue in un nuovo container, di solito dopo un minuto o due, e il tuo client non riceve alcun evento per il passaggio. Il passaggio ha due costi:

* **Comandi:** Tutto ciò che è in esecuzione nel vecchio container si interrompe. Il nuovo container esegue di nuovo dall’inizio la chiamata allo strumento interrotta, ma nulla riavvia un comando che l’agente ha lasciato in esecuzione in background.
* **File:** La `/workspace` del nuovo container è di nuovo vuota, fatta eccezione per i cloni aggiornati dei repository della sessione.

In un turno lungo, fai in modo che l’agente carichi o esegua il push del proprio lavoro man mano che procede, ed evita comandi che causano danni se vengono eseguiti due volte.

Su Kubernetes, una sessione mantiene un pod per circa un’ora al massimo, e il turno prosegue nello stesso modo. Due cose sono diverse: il nuovo pod trova i file della sessione in `/workspace`, e si avvia circa 6 minuti dopo l’arresto del vecchio pod.

Per i worker che avvii tu stesso, inserisci i file di input nella directory di lavoro prima di inviare il messaggio che li richiede. Leggi da essa i file di output in seguito.

Quando avvii tu stesso un container per ogni sessione, monta una directory che contiene i file di input della sessione come directory di lavoro del container. Raccogli da essa i file di output dopo che il container è terminato. Consulta [Prepara i file per una sessione](https://platform.claude.com/docs/it/managed-agents/self-hosted-sandboxes-workers#stage-files-for-a-session).

## Trovare altri esempi nelle guide del servizio ospitato

Le guide del servizio ospitato spiegano i [concetti fondamentali](https://platform.claude.com/docs/it/managed-agents/overview#core-concepts) dell’API e contengono esempi per ogni funzionalità. I loro esempi di SDK e CLI chiamano il tuo server quando li esegui nel terminale in cui sono impostate `ANTHROPIC_BASE_URL` e `ANTHROPIC_API_KEY`. I loro esempi cURL indicano `https://api.anthropic.com`, quindi sostituisci quell’indirizzo con `$ANTHROPIC_BASE_URL` prima di eseguirne uno.

Per alcune funzionalità, il tuo server ha prima bisogno di un’impostazione, oppure un esempio richiede una modifica:

| Attività                                                                | Guida del servizio ospitato                                                                                                                                                | Sul tuo server                                                                                                                                                                                                                                                                                                                                                 |
| ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Impostare il modello, il prompt di sistema e le versioni di un agente   | [Definisci il tuo agente](https://platform.claude.com/docs/it/managed-agents/agent-setup)                                                                                  | Alcuni campi [dipendono dal tuo provider di inferenza](https://platform.claude.com/docs/it/managed-agents/self-hosted/differences#differences-that-depend-on-your-inference-provider).                                                                                                                                                                         |
| Scegliere gli strumenti integrati o aggiungere strumenti personalizzati | [Strumenti](https://platform.claude.com/docs/it/managed-agents/tools)                                                                                                      | Per usare gli strumenti web, prima attivali, come descritto in [Gli strumenti web richiedono un’impostazione del server](https://platform.claude.com/docs/it/managed-agents/self-hosted/differences#web-tools-need-a-server-setting). Quali sono disponibili dipende dal tuo provider di inferenza.                                                            |
| Collegare un server MCP e memorizzarne il token                         | [Connettore MCP](https://platform.claude.com/docs/it/managed-agents/mcp-connector) e [Autenticarsi con i vault](https://platform.claude.com/docs/it/managed-agents/vaults) | Aggiungi l’host del server MCP all’[allowlist per i server MCP](https://platform.claude.com/docs/it/managed-agents/self-hosted/differences#mcp-servers-need-an-allowlist-entry). Memorizza il token come credenziale `static_bearer`.                                                                                                                          |
| Dare skill a un agente                                                  | [Skill](https://platform.claude.com/docs/it/managed-agents/skills)                                                                                                         | Carica ogni skill come file singoli, perché il tuo server rifiuta un archivio zip. Le [skill predefinite](https://platform.claude.com/docs/it/managed-agents/self-hosted/differences#features-that-arent-available) negli esempi di quella guida non sono disponibili.                                                                                         |
| Mantenere la memoria tra le sessioni                                    | [Usare la memoria dell’agente](https://platform.claude.com/docs/it/managed-agents/memory)                                                                                  | Se esegui i tuoi worker, fornisci loro una directory `/mnt/memory` scrivibile, come in [Archivi di memoria nelle sandbox self-hosted](https://platform.claude.com/docs/it/managed-agents/self-hosted-sandboxes-memory).                                                                                                                                        |
| Affidare lavoro ad altri agenti                                         | [Orchestrazione multiagente](https://platform.claude.com/docs/it/managed-agents/multiagent-orchestration)                                                                  | Sostituisci il blocco `multiagent_20261001` negli esempi di quella guida con un [blocco `coordinator`](https://platform.claude.com/docs/it/managed-agents/self-hosted/differences#features-that-behave-differently).                                                                                                                                           |
| Lavorare in un repository Git                                           | [Accedere a GitHub](https://platform.claude.com/docs/it/managed-agents/github)                                                                                             | Elenca l’host Git nelle impostazioni del tuo server, come descritto in [I repository Git richiedono una voce nell’allowlist](https://platform.claude.com/docs/it/managed-agents/self-hosted/differences#git-repositories-need-an-allowlist-entry). L’agente di esempio di quella guida richiede anche `api.githubcopilot.com` nell’allowlist per i server MCP. |
| Far verificare il lavoro da un valutatore rispetto a una rubrica        | [Definire i risultati](https://platform.claude.com/docs/it/managed-agents/define-outcomes)                                                                                 | Invia la rubrica come testo. La Files API non è disponibile, quindi [raccogli i file di output](https://platform.claude.com/docs/it/managed-agents/self-hosted/call-the-api#move-data-in-and-out-of-a-session) dalla directory di lavoro.                                                                                                                      |
| Seguire una sessione e rispondere alle sue chiamate agli strumenti      | [Flusso di eventi della sessione](https://platform.claude.com/docs/it/managed-agents/events-and-streaming)                                                                 | Il primo esempio di quella guida chiude il flusso a ogni pausa, quindi parti invece dal ciclo in [Inviare un messaggio e leggere la risposta](https://platform.claude.com/docs/it/managed-agents/self-hosted/call-the-api#send-a-message-and-read-the-reply).                                                                                                  |

[Differenze rispetto al servizio ospitato](https://platform.claude.com/docs/it/managed-agents/self-hosted/differences) contiene l’elenco completo. Consultalo prima di spostare un’applicazione esistente.

## Eseguire i tuoi worker

Lo [stack della guida rapida](https://platform.claude.com/docs/it/managed-agents/self-hosted/quickstart) crea un ambiente ed esegue i relativi worker. Lo stesso fanno i chart Helm in [Distribuire su Kubernetes](https://platform.claude.com/docs/it/managed-agents/self-hosted/kubernetes). Se quei worker sono tutto ciò che ti serve, salta questa sezione.

Esegui i worker come faresti per le [sandbox self-hosted](https://platform.claude.com/docs/it/managed-agents/self-hosted-sandboxes): con gli stessi comandi `ant beta:worker` e worker SDK, nei modi mostrati in [Distribuire worker self-hosted](https://platform.claude.com/docs/it/managed-agents/self-hosted-sandboxes-workers). L’eccezione sono i worker attivati da webhook, perché il tuo server non ne invia.

### Creare un ambiente e la relativa chiave

Crea un ambiente e una “environment key” (chiave di ambiente) con la CLI di amministrazione, non nella Claude Console. La CLI, `cma-server-admin`, si trova nella radice dell’archivio della release, quindi esegui il comando da lì. Per `-base-url`, passa l’indirizzo al quale i tuoi worker raggiungono il server:

* **Worker sulla macchina che esegue lo stack della guida rapida:** `http://127.0.0.1:8400`
* **Worker su un’altra macchina:** l’indirizzo `https` del [proxy TLS che hai posto davanti al server](https://platform.claude.com/docs/it/managed-agents/self-hosted/kubernetes#put-tls-in-front-of-the-server)

La CLI di amministrazione chiama il server allo stesso indirizzo, quindi eseguila su una macchina che può raggiungere quell’indirizzo.

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

Il comando stampa le impostazioni del worker, il comando che avvia un worker, e l’ID e la scadenza della chiave:

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

Il comando mostra la chiave una sola volta, quindi conserva la chiave, il suo ID e la sua scadenza nel tuo secret manager. La chiave smette di funzionare dopo 365 giorni. Prima di allora, segui [Sostituire una chiave di ambiente per i tuoi worker](https://platform.claude.com/docs/it/managed-agents/self-hosted/kubernetes#replace-an-environment-key-for-your-own-workers).

Tieni la chiave API del server lontana dalle macchine che eseguono i worker. Esegui i worker in un container o in una VM che non contenga nulla che tu debba proteggere. Per gli altri tuoi compiti di sicurezza, consulta [Le tue responsabilità di sicurezza](https://platform.claude.com/docs/it/managed-agents/self-hosted#your-security-responsibilities).

### Eseguire un esperimento locale

Esegui le tre righe `export` nella shell in cui avvii il worker. Poi avvia il worker con questi comandi, non con quello stampato. Il primo comando crea la directory di lavoro del worker, perché il worker non la 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` e `HISTFILE` configurano la shell alla base dello strumento `bash` del worker, in modo che esegua ogni comando così come l’agente lo ha scritto:

* **`histchars=`:** La shell non interpreta `!` come un riferimento alla cronologia dei comandi.
* **`INPUTRC`:** Il file disattiva il completamento, che altrimenti consumerebbe ogni carattere di tabulazione in un comando. Tieni il file fuori dalla directory di lavoro, dove gli strumenti per i file dell’agente potrebbero riscriverlo.
* **`HISTFILE=/dev/null`:** La shell non legge né scrive un file di cronologia.

Non usare questo worker per nient’altro. Contiene la chiave di ambiente ed esegue gli strumenti di ogni sessione in un unico processo. Inoltre non clona i repository di una sessione. La sessione viene eseguita senza di essi, e il tuo client non riceve alcun errore.

### Eseguire i worker in produzione

Per qualsiasi uso diverso da un esperimento locale, avvia un container per ogni sessione ed esegui `ant beta:worker run` al suo interno, come mostrato in [Eseguire una sandbox per sessione](https://platform.claude.com/docs/it/managed-agents/self-hosted-sandboxes-workers#run-one-sandbox-per-session). Fornisci alla sua immagine ciò che elenca [Creare la tua immagine sandbox](https://platform.claude.com/docs/it/managed-agents/self-hosted/call-the-api#build-your-own-sandbox-image) e modifica tre cose in quella configurazione:

* **Chiave di ambiente:** Non passare `ANTHROPIC_ENVIRONMENT_KEY` nel container di una sessione. Il server accetta quella chiave per ogni sessione dell’ambiente, e il container ha bisogno di accedere a una sola sessione.
* **Segreto dell’elemento di lavoro:** Passa questo segreto al posto della chiave, perché il server lo accetta solo per quella sessione. [Inoltra il segreto dell’elemento di lavoro](https://platform.claude.com/docs/it/managed-agents/self-hosted-sandboxes-workers#forward-the-work-items-secret) mostra il punto in cui il tuo codice lo riceve. Dove quella sezione imposta `ANTHROPIC_WORK_SECRET`, inserisci il segreto in un file che solo l’utente del container può leggere. Ad esempio, invia il segreto tramite pipe allo standard input del container e fai in modo che il container scriva il file prima di avviare il worker. Poi imposta `ANTHROPIC_WORK_SECRET_FILE` sul percorso del file.
* **Indirizzo del server:** Imposta `ANTHROPIC_BASE_URL` su un indirizzo che il container può raggiungere. `http://127.0.0.1:8400` non lo è.

Per un worker SDK, valgono altri due punti:

* **Versione:** Crea il worker sulla versione più recente dell’SDK, come descritto in [SDK, CLI e librerie](https://platform.claude.com/docs/it/cli-sdks-libraries/overview). Il worker di quella versione attende l’approvazione prima di eseguire una chiamata a uno strumento che la richiede, e non esegue mai una chiamata che una policy nega. Un worker creato su una versione precedente esegue ogni chiamata a uno strumento non appena arriva.
* **Esempi:** Gli esempi in [Eseguire il worker SDK all’interno della sandbox](https://platform.claude.com/docs/it/managed-agents/self-hosted-sandboxes-workers#run-the-sdk-worker-inside-the-sandbox) leggono la chiave di ambiente, quindi qui non funzionano così come sono.

### Creare la tua immagine sandbox

Un’immagine personalizzata richiede questi pacchetti e queste impostazioni:

* **Pacchetti:** Git 2.38 o versioni successive, `curl`, `jq` e ripgrep, che lo strumento `grep` del worker usa per le ricerche.

* **Impostazioni della shell:** `histchars`, `HISTFILE` e `INPUTRC`, come nell’esperimento locale, e `TERMINFO`. Inserisci queste righe nel Dockerfile, prima di qualsiasi riga `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` deve indicare la directory che contiene `d/dumb`, la descrizione del terminale che legge il `bash` del worker. Su Alpine con `bash` installato, è `/etc/terminfo`, come mostrato. Su un’altra base, come Debian o Ubuntu, è `/lib/terminfo` o `/usr/share/terminfo`, quella che contiene `d/dumb`. Scrivi quella directory nell’impostazione `TERMINFO` e nella riga `RUN test`, che interrompe la build se il file manca.

L’immagine richiede anche due script dall’archivio, che vengono eseguiti prima dell’avvio del worker:

1. Copia `image-build/with-repositories.sh` in `/usr/local/bin/cma-with-repositories`. Clona i repository di una sessione.
2. Copia `image-build/with-egress.sh` in `/usr/local/bin/cma-with-egress`. Punta gli strumenti della sessione all’[egress gateway](https://platform.claude.com/docs/it/managed-agents/self-hosted/agent-identity#environment-variable-credentials), se il tuo server ne esegue uno.
3. Rendi eseguibili entrambi i file.
4. Anteponi entrambi al comando del worker, come in `cma-with-egress cma-with-repositories ant beta:worker run ...`. Salta questo passaggio se la tua immagine esegue `kubernetes/sandbox/worker.sh` dell’archivio, perché quello script avvia il worker in questo modo.

Un worker avviato senza `cma-with-repositories` esegue la sessione senza alcun repository. Il tuo client non riceve alcun errore.

### Spostare i worker dal servizio ospitato

Se esegui già worker per il servizio ospitato di Anthropic, gli stessi worker possono invece servire il tuo server. Fai tre cose:

* Passa al processo che esegue il polling del lavoro i tre valori `export` stampati dalla CLI di amministrazione.
* Avvia quel processo con `histchars`, `HISTFILE` e `INPUTRC` impostati, come nell’esperimento locale.
* Applica le modifiche descritte in [Eseguire i worker in produzione](https://platform.claude.com/docs/it/managed-agents/self-hosted/call-the-api#run-workers-in-production) e verifica l’immagine di ogni sessione rispetto a [Creare la tua immagine sandbox](https://platform.claude.com/docs/it/managed-agents/self-hosted/call-the-api#build-your-own-sandbox-image).

## Passaggi successivi

* [Consentire agli sviluppatori di accedere da un terminale](https://platform.claude.com/docs/it/managed-agents/self-hosted/configure#let-developers-log-in-from-a-terminal): configura il single sign-on, in modo che gli sviluppatori usino la CLI `ant` con la propria identità, in un terminale senza `ANTHROPIC_API_KEY`.
* [Identità e credenziali dell’agente](https://platform.claude.com/docs/it/managed-agents/self-hosted/agent-identity): consenti ai sistemi esterni di fidarsi dei tuoi agenti e conserva le credenziali dei vault nel tuo gestore di segreti.
* [Provider di inferenza](https://platform.claude.com/docs/it/managed-agents/self-hosted/inference-provider): invia le chiamate al modello a un provider cloud o al tuo gateway di modelli.
