---
title: Herramienta de memoria
url: https://platform.claude.com/docs/es/agents-and-tools/tool-use/memory-tool
description: Permite que Claude almacene y recupere información entre conversaciones implementando las operaciones de archivos de la herramienta de memoria en tu aplicación.
---

La herramienta de memoria permite que Claude almacene y recupere información entre conversaciones en un directorio de archivos de memoria. Claude puede crear, leer, actualizar y eliminar archivos que persisten entre sesiones, acumulando conocimiento con el tiempo sin mantener todo en la "context window" (ventana de contexto).

La memoria admite la recuperación de contexto justo a tiempo. En lugar de cargar toda la información relevante desde el principio, un agente registra lo que aprende en archivos de memoria y los vuelve a leer cuando los necesita. Esto mantiene el contexto activo enfocado en la tarea actual, lo cual es importante para sesiones de larga duración que de otro modo saturarían la ventana de contexto. Consulta [Ingeniería de contexto efectiva](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents) para conocer el patrón más amplio.

La herramienta de memoria opera del lado del cliente: Claude solicita operaciones de archivos y tu aplicación las ejecuta. Tú controlas dónde y cómo se almacenan los datos a través de tu propia infraestructura.

<Note>
  Comunícate a través del [formulario de comentarios](https://forms.gle/YXC2EKGMhjN1c4L88) para compartir tu opinión sobre esta función.
</Note>

<Note>
  Para saber cómo se aplica la "zero data retention" (retención cero de datos), o ZDR, a esta función, consulta [API y retención de datos](https://platform.claude.com/docs/es/manage-claude/api-and-data-retention).
</Note>

## Casos de uso

* Mantener el contexto del proyecto a lo largo de múltiples sesiones de agente
* Aplicar lecciones de interacciones, decisiones y comentarios anteriores a nuevas tareas
* Construir una base de conocimiento con el tiempo

## Cómo funciona

Cuando la herramienta de memoria está habilitada, Claude revisa automáticamente su directorio de memoria antes de comenzar una tarea. Mientras trabaja, Claude almacena lo que aprende en archivos bajo `/memories` y los vuelve a leer en conversaciones posteriores para continuar el trabajo anterior.

Como la herramienta de memoria es del lado del cliente, Claude solo solicita operaciones de memoria. Tu aplicación ejecuta cada solicitud contra el almacenamiento que tú controlas y devuelve el resultado en un bloque `tool_result` (consulta [Manejar llamadas a herramientas](https://platform.claude.com/docs/es/agents-and-tools/tool-use/handle-tool-calls)). La ruta `/memories` es un prefijo que tu manejador asigna a un almacenamiento real, como un directorio por usuario o claves en una base de datos. La memoria vive completamente en tu aplicación. Una conversación posterior continúa desde la misma memoria cuando envía la misma entrada `tools` y tu manejador sirve el mismo almacén. Por seguridad, restringe todas las operaciones de memoria al directorio `/memories` (consulta [Protección contra recorrido de rutas](https://platform.claude.com/docs/es/agents-and-tools/tool-use/memory-tool#path-traversal-protection)).

### Ejemplo: Cómo funcionan las llamadas a la herramienta de memoria

Una interacción típica se ve así:

**1. Solicitud del usuario:**

```text wrap
"Help me respond to this customer service ticket."
```

**2. Claude revisa el directorio de memoria:**

```text wrap
"I'll help you respond to the customer service ticket. Let me check my memory for any previous context."
```

Claude llama a la herramienta de memoria:

```json
{
  "type": "tool_use",
  "id": "toolu_01C4D5E6F7G8H9I0J1K2L3M4",
  "name": "memory",
  "input": {
    "command": "view",
    "path": "/memories"
  }
}
```

**3. Tu aplicación devuelve el contenido del directorio:**

```json
{
  "type": "tool_result",
  "tool_use_id": "toolu_01C4D5E6F7G8H9I0J1K2L3M4",
  "content": "Here're the files and directories up to 2 levels deep in /memories, excluding hidden items and node_modules:\n4.0K\t/memories\n1.5K\t/memories/customer_service_guidelines.xml\n2.0K\t/memories/refund_policies.xml"
}
```

**4. Claude lee los archivos relevantes:**

```json
{
  "type": "tool_use",
  "id": "toolu_01D5E6F7G8H9I0J1K2L3M4N5",
  "name": "memory",
  "input": {
    "command": "view",
    "path": "/memories/customer_service_guidelines.xml"
  }
}
```

**5. Tu aplicación devuelve el contenido del archivo:**

```json
{
  "type": "tool_result",
  "tool_use_id": "toolu_01D5E6F7G8H9I0J1K2L3M4N5",
  "content": "Here's the content of /memories/customer_service_guidelines.xml with line numbers:\n     1\t<guidelines>\n     2\t<addressing_customers>\n     3\t- Always address customers by their first name\n     4\t- Use empathetic language\n..."
}
```

**6. Claude usa la memoria para ayudar:**

```text wrap
"Based on your customer service guidelines, I can help you craft a response. Please share the ticket details..."
```

La herramienta de memoria está disponible en todos los modelos Claude 4 y posteriores. Para ver la lista completa de herramientas proporcionadas por Anthropic, consulta la [Referencia de herramientas](https://platform.claude.com/docs/es/agents-and-tools/tool-use/tool-reference).

## Primeros pasos

Usar la herramienta de memoria requiere dos pasos:

1. Agrega la herramienta de memoria a tu solicitud. La entrada `tools` `{"type": "memory_20250818", "name": "memory"}` es toda la configuración: el `name` debe ser `memory`, y no defines un esquema de entrada para una herramienta proporcionada por Anthropic.
2. Implementa un manejador del lado del cliente para cada comando de memoria. Tu manejador debe rechazar rutas fuera de `/memories`, así que lee [Protección contra recorrido de rutas](https://platform.claude.com/docs/es/agents-and-tools/tool-use/memory-tool#path-traversal-protection) antes de escribirlo.

## Uso básico

<CodeGroup>
  ```bash cURL
  curl https://api.anthropic.com/v1/messages \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "content-type: application/json" \
    -d '{
      "model": "claude-opus-5-5",
      "max_tokens": 2048,
      "messages": [
        {
          "role": "user",
          "content": "Help me respond to this customer service ticket."
        }
      ],
      "tools": [{
        "type": "memory_20250818",
        "name": "memory"
      }]
    }'
  ```

  ```bash CLI
  ant messages create <<'YAML'
  model: claude-opus-5-5
  max_tokens: 2048
  tools:
    - type: memory_20250818
      name: memory
  messages:
    - role: user
      content: Help me respond to this customer service ticket.
  YAML
  ```

  ```python Python
  client = anthropic.Anthropic()

  message = client.messages.create(
      model="claude-opus-5-5",
      max_tokens=2048,
      messages=[
          {
              "role": "user",
              "content": "Help me respond to this customer service ticket.",
          }
      ],
      tools=[{"type": "memory_20250818", "name": "memory"}],
  )

  print(message)
  ```

  ```typescript TypeScript
  const anthropic = new Anthropic();

  const message = await anthropic.messages.create({
    model: "claude-opus-5-5",
    max_tokens: 2048,
    messages: [
      {
        role: "user",
        content: "Help me respond to this customer service ticket."
      }
    ],
    tools: [{ type: "memory_20250818", name: "memory" }]
  });

  console.log(message);
  ```

  ```csharp C#
  var client = new AnthropicClient();

  var message = await client.Messages.Create(
      new()
      {
          Model = Model.ClaudeOpus5_5,
          MaxTokens = 2048,
          Messages =
          [
              new()
              {
                  Role = Role.User,
                  Content = "Help me respond to this customer service ticket.",
              },
          ],
          Tools = [new MemoryTool20250818()],
      }
  );

  Console.WriteLine(message);
  ```

  ```go Go
  client := anthropic.NewClient()

  message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
  	Model:     anthropic.ModelClaudeOpus5_5,
  	MaxTokens: 2048,
  	Messages: []anthropic.MessageParam{
  		anthropic.NewUserMessage(anthropic.NewTextBlock("Help me respond to this customer service ticket.")),
  	},
  	Tools: []anthropic.ToolUnionParam{
  		{OfMemoryTool20250818: &anthropic.MemoryTool20250818Param{}},
  	},
  })
  if err != nil {
  	log.Fatal(err)
  }
  fmt.Println(message)
  ```

  ```java Java
  import com.anthropic.models.messages.MemoryTool20250818;
  // ...
    AnthropicClient client = AnthropicOkHttpClient.fromEnv();

    MessageCreateParams params = MessageCreateParams.builder()
      .model(Model.CLAUDE_OPUS_5_5)
      .maxTokens(2048L)
      .addTool(MemoryTool20250818.builder().build())
      .addUserMessage("Help me respond to this customer service ticket.")
      .build();

    Message message = client.messages().create(params);
    IO.println(message);
  ```

  ```php PHP
  $client = new Client();

  $message = $client->messages->create(
      model: Model::CLAUDE_OPUS_5_5,
      maxTokens: 2048,
      messages: [
          [
              'role' => 'user',
              'content' => 'Help me respond to this customer service ticket.',
          ],
      ],
      tools: [new MemoryTool20250818],
  );

  echo $message;
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  message = client.messages.create(
    model: Anthropic::Model::CLAUDE_OPUS_5_5,
    max_tokens: 2048,
    messages: [
      {
        role: "user",
        content: "Help me respond to this customer service ticket."
      }
    ],
    tools: [
      {
        type: "memory_20250818",
        name: "memory"
      }
    ]
  )
  puts message
  ```
</CodeGroup>

## Implementar el manejador de memoria

La respuesta de Claude a una solicitud como la anterior termina con un bloque `tool_use` que solicita una operación de memoria, como `view /memories`. Tu aplicación ejecuta la operación y devuelve el resultado en un bloque `tool_result`, luego envía la conversación de vuelta para que Claude pueda continuar: el [bucle de uso de herramientas](https://platform.claude.com/docs/es/agents-and-tools/tool-use/handle-tool-calls) estándar.

Cuatro SDK proporcionan ayudantes para la herramienta de memoria que manejan la interfaz de la herramienta y el bucle. Crea una subclase de `BetaAbstractMemoryTool` (Python y C#), usa `betaMemoryTool` (TypeScript) o implementa `BetaMemoryToolHandler` (Java) para respaldar la memoria con tu propio almacenamiento, como archivos en disco, una base de datos, almacenamiento en la nube o archivos cifrados. Python y TypeScript también incluyen una implementación lista para usar basada en el sistema de archivos local, `BetaLocalFilesystemMemoryTool`. Las interfaces del ayudante y del ejecutor de herramientas se encuentran en el espacio de nombres beta de tu SDK, aunque la herramienta de memoria en sí no requiere un encabezado beta. Los SDK de Go y Ruby no tienen un ayudante de memoria, por lo que esos ejemplos ejecutan el bucle de uso de herramientas por sí mismos, y PHP envuelve el closure de tu manejador en su `BetaRunnableTool` genérico. Los tres usan un almacén en memoria que reemplazas con tu propio almacenamiento.

<CodeGroup exclude="shell">
  ```python Python
  import anthropic
  from anthropic.tools import BetaLocalFilesystemMemoryTool

  client = anthropic.Anthropic()
  memory = BetaLocalFilesystemMemoryTool(base_path="./memory")

  runner = client.beta.messages.tool_runner(
      model="claude-opus-5-5",
      max_tokens=1024,
      messages=[
          {
              "role": "user",
              "content": "Remember that customer Acme Corp prefers email follow-ups.",
          }
      ],
      tools=[memory],
  )

  final_message = runner.until_done()
  print(final_message.content)
  ```

  ```typescript TypeScript
  import Anthropic from "@anthropic-ai/sdk";
  import { betaMemoryTool } from "@anthropic-ai/sdk/helpers/beta/memory";
  import { BetaLocalFilesystemMemoryTool } from "@anthropic-ai/sdk/tools/memory/node";

  const client = new Anthropic();

  const backend = await BetaLocalFilesystemMemoryTool.init("./memory");
  const memory = betaMemoryTool(backend); // or pass your own handlers object

  const runner = client.beta.messages.toolRunner({
    model: "claude-opus-5-5",
    max_tokens: 1024,
    messages: [
      {
        role: "user",
        content: "Remember that customer Acme Corp prefers email follow-ups."
      }
    ],
    tools: [memory],
    max_iterations: 10
  });

  const finalMessage = await runner;
  console.log(finalMessage.content);
  ```

  ```csharp C#
  using Anthropic;
  using Anthropic.Helpers.Beta;
  using Anthropic.Models.Beta.Messages;

  var client = new AnthropicClient();

  // Tu subclase de BetaAbstractMemoryTool
  var memory = new FilesystemMemoryTool("./memories");

  var runner = client.Beta.Messages.ToolRunner(
      new MessageCreateParams
      {
          Model = Anthropic.Models.Messages.Model.ClaudeOpus5_5,
          MaxTokens = 1024,
          Messages =
          [
              new()
              {
                  Role = Role.User,
                  Content = "Remember that customer Acme Corp prefers email follow-ups.",
              },
          ],
      },
      [memory],
      maxIterations: 10
  );

  var finalMessage = await runner.RunUntilDoneAsync();
  Console.WriteLine(finalMessage);
  ```

  ```go Go
  package main

  import (
  	"context"
  	"encoding/json"
  	"fmt"
  	"log"
  	"slices"
  	"sort"
  	"strings"

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

  // Un almacén en memoria que asigna las rutas de los archivos de memoria a su contenido.
  // Usa tu propio almacenamiento en producción.
  var store = map[string]string{}

  type memoryCommand struct {
  	Command    string `json:"command"`
  	Path       string `json:"path"`
  	FileText   string `json:"file_text"`
  	OldStr     string `json:"old_str"`
  	NewStr     string `json:"new_str"`
  	InsertLine int    `json:"insert_line"`
  	InsertText string `json:"insert_text"`
  	OldPath    string `json:"old_path"`
  	NewPath    string `json:"new_path"`
  }

  func executeMemory(raw json.RawMessage) string {
  	var cmd memoryCommand
  	if err := json.Unmarshal(raw, &cmd); err != nil {
  		return "Error: invalid memory command"
  	}
  	switch cmd.Command {
  	case "view":
  		if content, ok := store[cmd.Path]; ok {
  			lines := strings.Split(strings.TrimSuffix(content, "\n"), "\n")
  			for i, line := range lines {
  				lines[i] = fmt.Sprintf("%6d\t%s", i+1, line)
  			}
  			return fmt.Sprintf("Here's the content of %s with line numbers:\n%s", cmd.Path, strings.Join(lines, "\n"))
  		}
  		if cmd.Path == "/memories" {
  			listing := []string{"1.0K\t/memories"}
  			for path := range store {
  				listing = append(listing, "1.0K\t"+path)
  			}
  			sort.Strings(listing[1:])
  			return fmt.Sprintf("Here're the files and directories up to 2 levels deep in %s, excluding hidden items and node_modules:\n%s", cmd.Path, strings.Join(listing, "\n"))
  		}
  		return fmt.Sprintf("The path %s does not exist. Please provide a valid path.", cmd.Path)
  	case "create":
  		store[cmd.Path] = cmd.FileText
  		return "File created successfully at: " + cmd.Path
  	case "str_replace":
  		content, ok := store[cmd.Path]
  		if !ok || !strings.Contains(content, cmd.OldStr) {
  			return fmt.Sprintf("No replacement was performed, old_str `%s` did not appear verbatim in %s.", cmd.OldStr, cmd.Path)
  		}
  		store[cmd.Path] = strings.Replace(content, cmd.OldStr, cmd.NewStr, 1)
  		return "The memory file has been edited."
  	case "insert":
  		content, ok := store[cmd.Path]
  		if !ok {
  			return fmt.Sprintf("Error: The path %s does not exist", cmd.Path)
  		}
  		lines := strings.Split(content, "\n")
  		if cmd.InsertLine < 0 || cmd.InsertLine > len(lines) {
  			return fmt.Sprintf("Error: Invalid `insert_line` parameter: %d. It should be within the range of lines of the file: [0, %d]", cmd.InsertLine, len(lines))
  		}
  		lines = slices.Insert(lines, cmd.InsertLine, strings.TrimSuffix(cmd.InsertText, "\n"))
  		store[cmd.Path] = strings.Join(lines, "\n")
  		return fmt.Sprintf("The file %s has been edited.", cmd.Path)
  	case "delete":
  		if _, ok := store[cmd.Path]; !ok {
  			return fmt.Sprintf("Error: The path %s does not exist", cmd.Path)
  		}
  		delete(store, cmd.Path)
  		return "Successfully deleted " + cmd.Path
  	case "rename":
  		if _, ok := store[cmd.OldPath]; !ok {
  			return fmt.Sprintf("Error: The path %s does not exist", cmd.OldPath)
  		}
  		if _, ok := store[cmd.NewPath]; ok {
  			return fmt.Sprintf("Error: The destination %s already exists", cmd.NewPath)
  		}
  		store[cmd.NewPath] = store[cmd.OldPath]
  		delete(store, cmd.OldPath)
  		return fmt.Sprintf("Successfully renamed %s to %s", cmd.OldPath, cmd.NewPath)
  	default:
  		return "Error: unknown command " + cmd.Command
  	}
  }

  func main() {
  	client := anthropic.NewClient()
  	tools := []anthropic.ToolUnionParam{{OfMemoryTool20250818: &anthropic.MemoryTool20250818Param{}}}
  	messages := []anthropic.MessageParam{
  		anthropic.NewUserMessage(anthropic.NewTextBlock("Remember that customer Acme Corp prefers email follow-ups.")),
  	}

  	for {
  		message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
  			Model:     anthropic.ModelClaudeOpus5_5,
  			MaxTokens: 1024,
  			Messages:  messages,
  			Tools:     tools,
  		})
  		if err != nil {
  			log.Fatal(err)
  		}
  		if message.StopReason != anthropic.StopReasonToolUse {
  			for _, block := range message.Content {
  				if block.Type == "text" {
  					fmt.Println(block.Text)
  				}
  			}
  			break
  		}
  		results := []anthropic.ContentBlockParamUnion{}
  		for _, block := range message.Content {
  			if block.Type == "tool_use" {
  				results = append(results, anthropic.NewToolResultBlock(block.ID, executeMemory(block.Input), false))
  			}
  		}
  		messages = append(messages, message.ToParam(), anthropic.NewUserMessage(results...))
  	}
  }
  ```

  ```java Java
  import com.anthropic.client.AnthropicClient;
  import com.anthropic.client.okhttp.AnthropicOkHttpClient;
  import com.anthropic.helpers.BetaMemoryToolHandler;
  import com.anthropic.helpers.BetaToolRunner;
  import com.anthropic.models.beta.messages.BetaMemoryTool20250818;
  import com.anthropic.models.beta.messages.BetaMessage;
  import com.anthropic.models.beta.messages.MessageCreateParams; // beta package, not models.messages
  import com.anthropic.models.beta.messages.ToolRunnerCreateParams;
  import com.anthropic.models.messages.Model;
  import java.nio.file.Path;

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

    // Tu implementación de BetaMemoryToolHandler de los seis comandos de memoria
    BetaMemoryToolHandler handler = new FileSystemMemoryToolHandler(Path.of("memories"));

    MessageCreateParams createParams = MessageCreateParams.builder()
      .model(Model.CLAUDE_OPUS_5_5)
      .maxTokens(1024L)
      .addTool(BetaMemoryTool20250818.builder().build())
      .addUserMessage("Remember that customer Acme Corp prefers email follow-ups.")
      .build();

    ToolRunnerCreateParams runnerParams = ToolRunnerCreateParams.builder()
      .betaMemoryToolHandler(handler)
      .initialMessageParams(createParams)
      .maxIterations(10)
      .build();

    BetaToolRunner runner = client.beta().messages().toolRunner(runnerParams);
    for (BetaMessage message : runner) {
      IO.println(message);
    }
  }
  ```

  ```php PHP
  <?php

  use Anthropic\Beta\Messages\BetaMemoryTool20250818;
  use Anthropic\Client;
  use Anthropic\Lib\Tools\BetaRunnableTool;
  use Anthropic\Messages\Model;

  $client = new Client();

  // Un almacén en memoria que asigna las rutas de los archivos de memoria a su contenido.
  // Usa tu propio almacenamiento en producción.
  $store = [];

  $memory = new BetaRunnableTool(
      definition: new BetaMemoryTool20250818,
      run: function (array $input) use (&$store): string {
          $path = $input['path'] ?? '';
          switch ($input['command']) {
              case 'view':
                  if (isset($store[$path])) {
                      $numbered = [];
                      foreach (explode("\n", preg_replace('/\n\z/', '', $store[$path])) as $i => $line) {
                          $numbered[] = sprintf("%6d\t%s", $i + 1, $line);
                      }
                      return "Here's the content of {$path} with line numbers:\n" . implode("\n", $numbered);
                  }
                  if ($path === '/memories') {
                      $listing = ["1.0K\t/memories"];
                      foreach (array_keys($store) as $stored) {
                          $listing[] = "1.0K\t{$stored}";
                      }
                      return "Here're the files and directories up to 2 levels deep in {$path}, excluding hidden items and node_modules:\n" . implode("\n", $listing);
                  }
                  return "The path {$path} does not exist. Please provide a valid path.";
              case 'create':
                  $store[$path] = $input['file_text'];
                  return "File created successfully at: {$path}";
              case 'str_replace':
                  $position = strpos($store[$path] ?? '', $input['old_str']);
                  if ($position === false) {
                      return "No replacement was performed, old_str `{$input['old_str']}` did not appear verbatim in {$path}.";
                  }
                  $store[$path] = substr_replace($store[$path], $input['new_str'] ?? '', $position, strlen($input['old_str']));
                  return 'The memory file has been edited.';
              case 'insert':
                  if (!isset($store[$path])) {
                      return "Error: The path {$path} does not exist";
                  }
                  $lines = explode("\n", $store[$path]);
                  if ($input['insert_line'] < 0 || $input['insert_line'] > count($lines)) {
                      return "Error: Invalid `insert_line` parameter: {$input['insert_line']}. It should be within the range of lines of the file: [0, " . count($lines) . "]";
                  }
                  array_splice($lines, $input['insert_line'], 0, [preg_replace('/\n\z/', '', $input['insert_text'])]);
                  $store[$path] = implode("\n", $lines);
                  return "The file {$path} has been edited.";
              case 'delete':
                  if (!isset($store[$path])) {
                      return "Error: The path {$path} does not exist";
                  }
                  unset($store[$path]);
                  return "Successfully deleted {$path}";
              case 'rename':
                  if (!isset($store[$input['old_path']])) {
                      return "Error: The path {$input['old_path']} does not exist";
                  }
                  if (isset($store[$input['new_path']])) {
                      return "Error: The destination {$input['new_path']} already exists";
                  }
                  $store[$input['new_path']] = $store[$input['old_path']];
                  unset($store[$input['old_path']]);
                  return "Successfully renamed {$input['old_path']} to {$input['new_path']}";
              default:
                  return "Error: unknown command {$input['command']}";
          }
      },
  );

  $runner = $client->beta->messages->toolRunner(
      maxTokens: 1024,
      messages: [['role' => 'user', 'content' => 'Remember that customer Acme Corp prefers email follow-ups.']],
      model: Model::CLAUDE_OPUS_5_5,
      tools: [$memory],
      maxIterations: 10,
  );

  $finalMessage = $runner->runUntilDone();
  print_r($finalMessage->content);
  ```

  ```ruby Ruby
  require "anthropic"

  client = Anthropic::Client.new
  TOOLS = [{type: "memory_20250818", name: "memory"}].freeze

  # Un almacén en memoria que asigna las rutas de archivos de memoria a su contenido.
  # Usa tu propio almacenamiento en producción.
  STORE = {}

  def execute_memory(input)
    path = input[:path]
    case input[:command]
    when "view"
      if STORE.key?(path)
        lines = STORE[path].chomp.split("\n", -1)
        lines = [""] if lines.empty?
        numbered = lines.each_with_index.map { |line, i| format("%6d\t%s", i + 1, line) }
        "Here's the content of #{path} with line numbers:\n#{numbered.join("\n")}"
      elsif path == "/memories"
        listing = ["1.0K\t/memories"] + STORE.keys.map { |stored| "1.0K\t#{stored}" }
        "Here're the files and directories up to 2 levels deep in #{path}, excluding hidden items and node_modules:\n#{listing.join("\n")}"
      else
        "The path #{path} does not exist. Please provide a valid path."
      end
    when "create"
      STORE[path] = input[:file_text]
      "File created successfully at: #{path}"
    when "str_replace"
      unless STORE.key?(path) && STORE[path].include?(input[:old_str])
        return "No replacement was performed, old_str `#{input[:old_str]}` did not appear verbatim in #{path}."
      end
      STORE[path] = STORE[path].sub(input[:old_str]) { input[:new_str].to_s }
      "The memory file has been edited."
    when "insert"
      return "Error: The path #{path} does not exist" unless STORE.key?(path)
      lines = STORE[path].split("\n", -1)
      lines = [""] if lines.empty?
      if input[:insert_line] < 0 || input[:insert_line] > lines.length
        return "Error: Invalid `insert_line` parameter: #{input[:insert_line]}. It should be within the range of lines of the file: [0, #{lines.length}]"
      end
      lines.insert(input[:insert_line], input[:insert_text].chomp)
      STORE[path] = lines.join("\n")
      "The file #{path} has been edited."
    when "delete"
      return "Error: The path #{path} does not exist" unless STORE.key?(path)
      STORE.delete(path)
      "Successfully deleted #{path}"
    when "rename"
      return "Error: The path #{input[:old_path]} does not exist" unless STORE.key?(input[:old_path])
      return "Error: The destination #{input[:new_path]} already exists" if STORE.key?(input[:new_path])
      STORE[input[:new_path]] = STORE.delete(input[:old_path])
      "Successfully renamed #{input[:old_path]} to #{input[:new_path]}"
    else
      "Error: unknown command #{input[:command]}"
    end
  end

  messages = [{role: "user", content: "Remember that customer Acme Corp prefers email follow-ups."}]
  loop do
    message = client.messages.create(
      model: Anthropic::Model::CLAUDE_OPUS_5_5,
      max_tokens: 1024,
      messages: messages,
      tools: TOOLS
    )
    unless message.stop_reason == :tool_use
      puts message.content
      break
    end
    tool_results = message.content.filter_map do |block|
      next unless block.type == :tool_use
      {type: "tool_result", tool_use_id: block.id, content: execute_memory(block.input)}
    end
    messages << {role: "assistant", content: message.content} << {role: "user", content: tool_results}
  end
  ```
</CodeGroup>

Los almacenes en memoria de los ejemplos de Go, PHP y Ruby los mantienen autocontenidos: cada uno despacha según el campo `command` en el `input` del bloque `tool_use` y devuelve las cadenas descritas en [Comandos de la herramienta](https://platform.claude.com/docs/es/agents-and-tools/tool-use/memory-tool#tool-commands). Un manejador de producción también necesita la [validación de rutas](https://platform.claude.com/docs/es/agents-and-tools/tool-use/memory-tool#path-traversal-protection) que estos almacenes de demostración omiten. Para ver los ejemplos completos propios de los SDK, consulta:

* Python: [examples/memory/basic.py](https://github.com/anthropics/anthropic-sdk-python/blob/main/examples/memory/basic.py)
* TypeScript: [examples/tools-helpers-memory.ts](https://github.com/anthropics/anthropic-sdk-typescript/blob/main/examples/tools-helpers-memory.ts)
* C#: [MemoryToolExample](https://github.com/anthropics/anthropic-sdk-csharp/tree/main/examples/MemoryToolExample)
* Java: [BetaMemoryToolExample.java](https://github.com/anthropics/anthropic-sdk-java/blob/main/anthropic-java-example/src/main/java/com/anthropic/example/BetaMemoryToolExample.java)

## Comandos de la herramienta

Tu implementación del lado del cliente debe manejar los siguientes comandos. Estas especificaciones describen los comportamientos y cadenas de retorno recomendados: Claude lee cualquier texto que contenga el resultado de tu herramienta, por lo que puedes devolver cadenas diferentes si tu aplicación lo necesita.

### view

Muestra el contenido de un directorio o de un archivo con rangos de líneas opcionales:

```json
{
  "command": "view",
  "path": "/memories/notes.txt",
  "view_range": [1, 10]
}
```

`view_range` es opcional y se aplica a las vistas de archivos de texto: `[start_line, end_line]` devuelve esas líneas, y `[start_line, -1]` devuelve todo desde `start_line` hasta el final del archivo.

#### Valores de retorno

**Para directorios:** Devuelve un listado que muestra archivos y directorios con sus tamaños:

```text
Here're the files and directories up to 2 levels deep in {path}, excluding hidden items and node_modules:
{size}\t{path}
{size}\t{path}/{filename1}
{size}\t{path}/{filename2}
```

* Lista archivos hasta 2 niveles de profundidad
* Muestra tamaños legibles para humanos (por ejemplo, `5.5K`, `1.2M`)
* Excluye elementos ocultos (archivos que comienzan con `.`) y `node_modules`
* Usa un carácter de tabulación entre el tamaño y la ruta

El primer `view` de `/memories` en un almacén vacío no es un error. Cuando tu SDK incluye una herramienta de memoria basada en el sistema de archivos local, `BetaLocalFilesystemMemoryTool`, esta crea la raíz de memoria antes de la primera llamada de Claude y devuelve el encabezado del listado seguido de una única línea de tamaño y ruta para el propio directorio vacío.

**Para archivos:** Devuelve el contenido del archivo con un encabezado y números de línea:

```text wrap
Here's the content of {path} with line numbers:
{line_numbers}{tab}{content}
```

Formato de los números de línea:

* **Ancho:** 6 caracteres, alineados a la derecha con relleno de espacios
* **Separador:** Carácter de tabulación entre el número de línea y el contenido
* **Indexación:** Basada en 1 (la primera línea es la línea 1)
* **Límite de líneas:** Los archivos con más de 999,999 líneas deben devolver un error: `"File {path} exceeds maximum line limit of 999,999 lines."`

**Ejemplo de salida:**

```text
Here's the content of /memories/notes.txt with line numbers:
     1	Hello World
     2	This is line two
    10	Line ten
   100	Line one hundred
```

La descripción de la herramienta de Claude también indica que `view` muestra archivos de imagen (`.jpg`, `.jpeg` y `.png`) y trunca la vista de texto de archivos de más de 16,000 caracteres. Espera llamadas `view` sobre rutas de imágenes y vistas posteriores por rangos de archivos largos.

#### Manejo de errores

* **El archivo o directorio no existe:** `"The path {path} does not exist. Please provide a valid path."`

### create

Crea un archivo nuevo:

```json
{
  "command": "create",
  "path": "/memories/notes.txt",
  "file_text": "Meeting notes:\n- Discussed project timeline\n- Next steps defined\n"
}
```

#### Valores de retorno

* **Éxito:** `"File created successfully at: {path}"`

#### Manejo de errores

* **El archivo ya existe:** `"Error: File {path} already exists"`

La descripción de la herramienta de Claude dice que `create` "crea o sobrescribe" un archivo, así que espera llamadas `create` sobre rutas que ya existen. Devolver el error es el comportamiento de referencia, y sobrescribir en su lugar es una opción de implementación válida.

### str\_replace

Reemplaza texto en un archivo:

```json
{
  "command": "str_replace",
  "path": "/memories/preferences.txt",
  "old_str": "Favorite color: blue",
  "new_str": "Favorite color: green"
}
```

`new_str` es opcional para `str_replace`: cuando se omite, `old_str` se elimina sin reemplazo.

#### Valores de retorno

* **Éxito:** `"The memory file has been edited."` seguido de un fragmento del archivo editado con números de línea

#### Manejo de errores

* **El archivo no existe:** `"Error: The path {path} does not exist. Please provide a valid path."`
* **Texto no encontrado:** ``"No replacement was performed, old_str `\{old_str}` did not appear verbatim in {path}."``
* **Texto duplicado:** Cuando `old_str` aparece varias veces, devuelve: ``"No replacement was performed. Multiple occurrences of old_str `\{old_str}` in lines: {line_numbers}. Please ensure it is unique"``

#### Manejo de directorios

Si la ruta es un directorio, devuelve un error de "el archivo no existe".

### insert

Inserta texto en una línea específica:

```json
{
  "command": "insert",
  "path": "/memories/todo.txt",
  "insert_line": 2,
  "insert_text": "- Review memory tool documentation\n"
}
```

`insert_text` se inserta después de la línea `insert_line`, y `0` inserta al principio del archivo.

#### Valores de retorno

* **Éxito:** `"The file {path} has been edited."`

#### Manejo de errores

* **El archivo no existe:** `"Error: The path {path} does not exist"`
* **Número de línea inválido:** ``"Error: Invalid `insert_line` parameter: {insert_line}. It should be within the range of lines of the file: [0, {n_lines}]"``

#### Manejo de directorios

Si la ruta es un directorio, devuelve un error de "el archivo no existe".

### delete

Elimina un archivo o directorio:

```json
{
  "command": "delete",
  "path": "/memories/old_file.txt"
}
```

#### Valores de retorno

* **Éxito:** `"Successfully deleted {path}"`

#### Manejo de errores

* **El archivo o directorio no existe:** `"Error: The path {path} does not exist"`

#### Manejo de directorios

Elimina el directorio y todo su contenido de forma recursiva. La descripción de la herramienta le indica a Claude que no puede eliminar el directorio `/memories` en sí, así que rechaza un `delete` cuya ruta sea la raíz de memoria.

### rename

Renombra o mueve un archivo o directorio:

```json
{
  "command": "rename",
  "old_path": "/memories/draft.txt",
  "new_path": "/memories/final.txt"
}
```

#### Valores de retorno

* **Éxito:** `"Successfully renamed {old_path} to {new_path}"`

#### Manejo de errores

* **El origen no existe:** `"Error: The path {old_path} does not exist"`
* **El destino ya existe:** Devuelve un error (no sobrescribas): `"Error: The destination {new_path} already exists"`

#### Manejo de directorios

Renombra el directorio. La descripción de la herramienta le indica a Claude que no puede renombrar el directorio `/memories` en sí, así que rechaza un `rename` cuyo `old_path` sea la raíz de memoria.

## Guía de prompts

Cuando la herramienta de memoria está presente en los `tools` de tu solicitud, la API agrega automáticamente esta instrucción a la indicación del sistema. No necesitas enviarla tú mismo:

```text wrap
IMPORTANT: ALWAYS VIEW YOUR MEMORY DIRECTORY BEFORE DOING ANYTHING ELSE.
MEMORY PROTOCOL:
1. Use the `view` command of your `memory` tool to check for earlier progress.
2. ... (work on the task) ...
   - As you make progress, record status / progress / thoughts etc in your memory.
ASSUME INTERRUPTION: Your context window might be reset at any moment, so you risk losing any progress that is not recorded in your memory directory.
```

La descripción de la herramienta de Claude ya le indica que mantenga organizado el directorio de memoria, por lo que no necesitas repetir esa instrucción. Si Claude aún crea archivos de memoria desordenados, puedes reforzarlo en tu prompt:

```text wrap
Note: when editing your memory folder, always try to keep its content up-to-date, coherent and organized. You can rename or delete files that are no longer relevant. Do not create new files unless necessary.
```

También puedes guiar lo que Claude escribe en la memoria. Por ejemplo: "Only write down information relevant to \<topic> in your memory system."

## Consideraciones de seguridad

Tu aplicación ejecuta cada operación de archivos que Claude solicita, por lo que estas protecciones son tu responsabilidad:

### Información sensible

Claude normalmente se niega a escribir información sensible en archivos de memoria. Para obtener garantías más sólidas, agrega una validación que elimine los datos sensibles antes de que tu manejador escriba el archivo.

### Tamaño del almacenamiento de archivos

Haz seguimiento del tamaño de los archivos de memoria y limita cuánto puede crecer un archivo. Considera limitar cuántos caracteres devuelve el comando `view` y deja que Claude recorra el resto con `view_range`.

### Expiración de la memoria

Elimina periódicamente los archivos de memoria a los que no se haya accedido en mucho tiempo.

### Protección contra recorrido de rutas

<Warning>
  Una ruta maliciosa como `/memories/../../secrets.env` puede alcanzar archivos fuera del directorio `/memories`. Tu implementación debe validar cada ruta en cada comando para prevenir ataques de recorrido de directorios.
</Warning>

Considera estas protecciones:

* Valida que todas las rutas comiencen con `/memories`
* Resuelve las rutas a su forma canónica y verifica que permanezcan dentro del directorio de memoria
* Rechaza rutas que contengan secuencias como `../`, `..\\` u otros patrones de recorrido
* Vigila las secuencias de recorrido codificadas en URL (`%2e%2e%2f`)
* Usa las utilidades de seguridad de rutas integradas en tu lenguaje (por ejemplo, `pathlib.Path.resolve()` y `relative_to()` de Python)

## Manejo de errores

La herramienta de memoria usa patrones de manejo de errores similares a los de la [herramienta de editor de texto](https://platform.claude.com/docs/es/agents-and-tools/tool-use/text-editor-tool#handle-errors). Los mensajes de error de cada comando se enumeran en [Comandos de la herramienta](https://platform.claude.com/docs/es/agents-and-tools/tool-use/memory-tool#tool-commands). Para devolver un error a Claude, establece `is_error` en `true` en el resultado de la herramienta y coloca el mensaje en `content`:

```json
{
  "type": "tool_result",
  "tool_use_id": "toolu_01C4D5E6F7G8H9I0J1K2L3M4",
  "content": "Error: The path /memories/notes.txt does not exist",
  "is_error": true
}
```

## Integración con la edición de contexto

La herramienta de memoria se combina con la edición de contexto para gestionar conversaciones de larga duración. Para más detalles, consulta [Edición de contexto](https://platform.claude.com/docs/es/build-with-claude/context-editing).

## Uso con compactación

La herramienta de memoria también puede combinarse con la [compactación](https://platform.claude.com/docs/es/build-with-claude/compaction), que resume el contexto más antiguo de la conversación del lado del servidor. La edición de contexto borra resultados de herramientas específicos en el cliente. La compactación resume automáticamente toda la conversación en el servidor cuando la conversación se acerca al límite de la ventana de contexto.

Para agentes de larga duración, considera usar ambas: la compactación mantiene pequeño el contexto activo sin contabilidad del lado del cliente, y la memoria preserva la información que debe sobrevivir al resumen.

## Patrón de desarrollo de software multisesión

Para proyectos de software que abarcan múltiples sesiones de agente, configura los archivos de memoria deliberadamente en lugar de escribirlos de forma improvisada a medida que avanza el trabajo. El siguiente patrón convierte la memoria en un mecanismo de recuperación: cada nueva sesión se reanuda desde el estado que registró la anterior.

### Cómo funciona el patrón

1. **Sesión inicializadora:** La primera sesión configura los archivos de memoria antes de que comience cualquier trabajo sustancial. Esto incluye un registro de progreso (que rastrea lo que se ha hecho y lo que sigue), una lista de verificación de funcionalidades (que define el alcance del trabajo) y una referencia a cualquier script de arranque o inicialización que necesite el proyecto.

2. **Sesiones posteriores:** Cada nueva sesión comienza leyendo esos archivos de memoria. Esto restaura el estado del proyecto sin volver a explorar la base de código ni repasar decisiones anteriores.

3. **Actualización al final de la sesión:** Antes de que termine una sesión, actualiza el registro de progreso con lo que se completó y lo que queda pendiente. Esto garantiza que la siguiente sesión tenga un punto de partida preciso.

### Principio clave

Trabaja en una funcionalidad a la vez. Marca una funcionalidad como completa solo después de que una verificación de extremo a extremo confirme que funciona, no cuando el código esté escrito. Esto mantiene el registro de progreso preciso de una sesión a otra.

<Tip>
  Para ver un estudio de caso detallado de este patrón en la práctica, incluido el script inicializador, la estructura del archivo de progreso y la recuperación basada en git, consulta [Arneses efectivos para agentes de larga duración](https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents).
</Tip>

## Próximos pasos

<CardGroup cols={2}>
  <Card title="Herramienta Bash" icon="terminal" href="https://platform.claude.com/docs/es/agents-and-tools/tool-use/bash-tool">
    Ejecuta comandos de shell en una sesión bash persistente.
  </Card>

  <Card title="Edición de contexto" icon="edit" href="https://platform.claude.com/docs/es/build-with-claude/context-editing">
    Gestiona automáticamente el contexto de la conversación a medida que crece con la edición de contexto.
  </Card>

  <Card title="Compactación" icon="stack" href="https://platform.claude.com/docs/es/build-with-claude/compaction">
    Compactación de contexto del lado del servidor para gestionar conversaciones largas que se acercan a los límites de la ventana de contexto.
  </Card>

  <Card title="Referencia de herramientas" icon="book" href="https://platform.claude.com/docs/es/agents-and-tools/tool-use/tool-reference">
    Directorio de herramientas proporcionadas por Anthropic y referencia de las propiedades opcionales de definición de herramientas.
  </Card>
</CardGroup>
