---
title: Memory-Tool
url: https://platform.claude.com/docs/de/agents-and-tools/tool-use/memory-tool
description: Lass Claude Informationen über Gespräche hinweg speichern und abrufen, indem du die Dateioperationen des Memory-Tools in deiner Anwendung implementierst.
---

Das Memory-Tool lässt Claude Informationen über Gespräche hinweg in einem Verzeichnis von Memory-Dateien speichern und abrufen. Claude kann Dateien erstellen, lesen, aktualisieren und löschen, die zwischen Sitzungen bestehen bleiben, und so im Laufe der Zeit Wissen aufbauen, ohne alles im Kontextfenster zu behalten.

Memory unterstützt Just-in-Time-Kontextabruf. Anstatt alle relevanten Informationen im Voraus zu laden, zeichnet ein Agent das, was er lernt, in Memory-Dateien auf und liest sie bei Bedarf zurück. Dadurch bleibt der aktive Kontext auf die aktuelle Aufgabe fokussiert, was für langlaufende Sitzungen wichtig ist, die andernfalls das Kontextfenster überlasten würden. Siehe [Effektives Kontext-Engineering](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents) für das umfassendere Muster.

Das Memory-Tool arbeitet clientseitig: Claude fordert Dateioperationen an, und deine Anwendung führt sie aus. Du kontrollierst über deine eigene Infrastruktur, wo und wie die Daten gespeichert werden.

<Note>
  Melde dich über das [Feedback-Formular](https://forms.gle/YXC2EKGMhjN1c4L88), um dein Feedback zu dieser Funktion zu teilen.
</Note>

<Note>
  Um zu erfahren, wie „zero data retention“ (Null-Datenspeicherung), oder ZDR, auf diese Funktion angewendet wird, siehe [API und Datenspeicherung](https://platform.claude.com/docs/de/manage-claude/api-and-data-retention).
</Note>

## Anwendungsfälle

* Projektkontext über mehrere Agent-Sitzungen hinweg beibehalten
* Lektionen aus vergangenen Interaktionen, Entscheidungen und Feedback auf neue Aufgaben anwenden
* Im Laufe der Zeit eine Wissensbasis aufbauen

## Funktionsweise

Wenn das Memory-Tool aktiviert ist, überprüft Claude automatisch sein Memory-Verzeichnis, bevor es eine Aufgabe beginnt. Während es arbeitet, speichert Claude das, was es lernt, in Dateien unter `/memories` und liest sie in späteren Gesprächen zurück, um frühere Arbeit fortzusetzen.

Da das Memory-Tool clientseitig ist, fordert Claude nur Memory-Operationen an. Deine Anwendung führt jede Anfrage gegen von dir kontrollierten Speicher aus und gibt das Ergebnis in einem `tool_result`-Block zurück (siehe [Tool-Aufrufe verarbeiten](https://platform.claude.com/docs/de/agents-and-tools/tool-use/handle-tool-calls)). Der Pfad `/memories` ist ein Präfix, das dein Handler auf echten Speicher abbildet, etwa ein Verzeichnis pro Benutzer oder Schlüssel in einer Datenbank. Memory lebt vollständig in deiner Anwendung. Ein späteres Gespräch setzt vom selben Memory fort, wenn es denselben `tools`-Eintrag sendet und dein Handler denselben Speicher bedient. Aus Sicherheitsgründen beschränke alle Memory-Operationen auf das Verzeichnis `/memories` (siehe [Schutz vor Path Traversal](https://platform.claude.com/docs/de/agents-and-tools/tool-use/memory-tool#path-traversal-protection)).

### Beispiel: Wie Memory-Tool-Aufrufe funktionieren

Eine typische Interaktion sieht so aus:

**1. Benutzeranfrage:**

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

**2. Claude überprüft das Memory-Verzeichnis:**

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

Claude ruft das Memory-Tool auf:

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

**3. Deine Anwendung gibt den Verzeichnisinhalt zurück:**

```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 liest relevante Dateien:**

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

**5. Deine Anwendung gibt den Dateiinhalt zurück:**

```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 nutzt das Memory, um zu helfen:**

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

Das Memory-Tool ist auf allen Claude 4- und späteren Modellen verfügbar. Die vollständige Liste der von Anthropic bereitgestellten Tools findest du in der [Tool-Referenz](https://platform.claude.com/docs/de/agents-and-tools/tool-use/tool-reference).

## Erste Schritte

Die Verwendung des Memory-Tools erfolgt in zwei Schritten:

1. Füge das Memory-Tool zu deiner Anfrage hinzu. Der `tools`-Eintrag `{"type": "memory_20250818", "name": "memory"}` ist die gesamte Konfiguration: Der `name` muss `memory` sein, und du definierst kein Eingabeschema für ein von Anthropic bereitgestelltes Tool.
2. Implementiere einen clientseitigen Handler für jeden Memory-Befehl. Dein Handler muss Pfade außerhalb von `/memories` ablehnen, lies also [Schutz vor Path Traversal](https://platform.claude.com/docs/de/agents-and-tools/tool-use/memory-tool#path-traversal-protection), bevor du ihn schreibst.

## Grundlegende Verwendung

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

## Den Memory-Handler implementieren

Claudes Antwort auf eine Anfrage wie die vorherige endet mit einem `tool_use`-Block, der eine Memory-Operation anfordert, etwa `view /memories`. Deine Anwendung führt die Operation aus und gibt das Ergebnis in einem `tool_result`-Block zurück, sendet dann das Gespräch zurück, damit Claude fortfahren kann: die standardmäßige [Tool-Nutzungs-Schleife](https://platform.claude.com/docs/de/agents-and-tools/tool-use/handle-tool-calls).

Vier SDKs bieten Memory-Tool-Helfer, die die Tool-Schnittstelle und die Schleife übernehmen. Leite von `BetaAbstractMemoryTool` ab (Python und C#), verwende `betaMemoryTool` (TypeScript) oder implementiere `BetaMemoryToolHandler` (Java), um Memory mit deinem eigenen Speicher zu hinterlegen, etwa Dateien auf der Festplatte, einer Datenbank, Cloud-Speicher oder verschlüsselten Dateien. Python und TypeScript liefern außerdem eine fertige Implementierung für das lokale Dateisystem mit, `BetaLocalFilesystemMemoryTool`. Die Helfer- und Tool-Runner-Schnittstellen befinden sich im Beta-Namespace deines SDKs, obwohl das Memory-Tool selbst keinen Beta-Header erfordert. Die Go- und Ruby-SDKs haben keinen Memory-Helfer, daher führen diese Beispiele die Tool-Nutzungs-Schleife selbst aus, und PHP verpackt deine Handler-Closure in sein generisches `BetaRunnableTool`. Alle drei verwenden einen In-Memory-Speicher, den du durch deinen eigenen Speicher ersetzt.

<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();

  // Deine Unterklasse von 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"
  )

  // Ein In-Memory-Speicher, der Pfade von Memory-Dateien ihren Inhalten zuordnet.
  // Verwende in der Produktion deinen eigenen Speicher.
  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();

    // Deine BetaMemoryToolHandler-Implementierung der sechs Memory-Befehle
    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();

  // Ein In-Memory-Speicher, der Pfade von Memory-Dateien ihren Inhalten zuordnet.
  // Verwende in der Produktion deinen eigenen Speicher.
  $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

  # Ein In-Memory-Speicher, der Pfade von Memory-Dateien ihren Inhalten zuordnet.
  # Verwende in der Produktion deinen eigenen Speicher.
  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>

Die In-Memory-Speicher in den Go-, PHP- und Ruby-Beispielen halten sie eigenständig: Jeder verteilt anhand des `command`-Felds im `input` des `tool_use`-Blocks und gibt die unter [Tool-Befehle](https://platform.claude.com/docs/de/agents-and-tools/tool-use/memory-tool#tool-commands) beschriebenen Strings zurück. Ein Produktions-Handler benötigt außerdem die [Pfadvalidierung](https://platform.claude.com/docs/de/agents-and-tools/tool-use/memory-tool#path-traversal-protection), die diese Demonstrationsspeicher überspringen. Die vollständigen eigenen Beispiele der SDKs findest du hier:

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

## Tool-Befehle

Deine clientseitige Implementierung muss die folgenden Befehle verarbeiten. Diese Spezifikationen beschreiben die empfohlenen Verhaltensweisen und Rückgabe-Strings: Claude liest, welchen Text auch immer dein Tool-Ergebnis enthält, sodass du andere Strings zurückgeben kannst, wenn deine Anwendung dies benötigt.

### view

Zeigt Verzeichnisinhalte oder Dateiinhalte mit optionalen Zeilenbereichen an:

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

`view_range` ist optional und gilt für Textdatei-Ansichten: `[start_line, end_line]` gibt diese Zeilen zurück, und `[start_line, -1]` gibt alles von `start_line` bis zum Ende der Datei zurück.

#### Rückgabewerte

**Für Verzeichnisse:** Gib eine Auflistung zurück, die Dateien und Verzeichnisse mit ihren Größen zeigt:

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

* Listet Dateien bis zu 2 Ebenen tief auf
* Zeigt menschenlesbare Größen (zum Beispiel `5.5K`, `1.2M`)
* Schließt versteckte Elemente (Dateien, die mit `.` beginnen) und `node_modules` aus
* Verwendet ein Tabulatorzeichen zwischen der Größe und dem Pfad

Das erste `view` von `/memories` auf einem leeren Speicher ist kein Fehler. Wo dein SDK ein Memory-Tool für das lokale Dateisystem mitliefert, `BetaLocalFilesystemMemoryTool`, erstellt es das Memory-Root vor Claudes erstem Aufruf und gibt den Auflistungs-Header gefolgt von einer einzelnen Zeile mit Größe und Pfad für das leere Verzeichnis selbst zurück.

**Für Dateien:** Gib Dateiinhalte mit einem Header und Zeilennummern zurück:

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

Formatierung der Zeilennummern:

* **Breite:** 6 Zeichen, rechtsbündig mit Leerzeichen-Auffüllung
* **Trennzeichen:** Tabulatorzeichen zwischen Zeilennummer und Inhalt
* **Indizierung:** 1-indiziert (die erste Zeile ist Zeile 1)
* **Zeilenlimit:** Dateien mit mehr als 999.999 Zeilen sollten einen Fehler zurückgeben: `"File {path} exceeds maximum line limit of 999,999 lines."`

**Beispielausgabe:**

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

Claudes Tool-Beschreibung besagt außerdem, dass `view` Bilddateien (`.jpg`, `.jpeg` und `.png`) anzeigt und die Textansicht von Dateien, die länger als 16.000 Zeichen sind, abschneidet. Erwarte `view`-Aufrufe auf Bildpfaden und nachfolgende bereichsbasierte Ansichten langer Dateien.

#### Fehlerbehandlung

* **Datei oder Verzeichnis existiert nicht:** `"The path {path} does not exist. Please provide a valid path."`

### create

Erstellt eine neue Datei:

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

#### Rückgabewerte

* **Erfolg:** `"File created successfully at: {path}"`

#### Fehlerbehandlung

* **Datei existiert bereits:** `"Error: File {path} already exists"`

Claudes Tool-Beschreibung besagt, dass `create` eine Datei „erstellt oder überschreibt“, erwarte also `create`-Aufrufe auf Pfaden, die bereits existieren. Die Rückgabe des Fehlers ist das Referenzverhalten, und stattdessen zu überschreiben ist eine gültige Implementierungsentscheidung.

### str\_replace

Ersetzt Text in einer Datei:

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

`new_str` ist für `str_replace` optional: Wenn es weggelassen wird, wird `old_str` ohne Ersetzung gelöscht.

#### Rückgabewerte

* **Erfolg:** `"The memory file has been edited."` gefolgt von einem Ausschnitt der bearbeiteten Datei mit Zeilennummern

#### Fehlerbehandlung

* **Datei existiert nicht:** `"Error: The path {path} does not exist. Please provide a valid path."`
* **Text nicht gefunden:** ``"No replacement was performed, old_str `\{old_str}` did not appear verbatim in {path}."``
* **Doppelter Text:** Wenn `old_str` mehrmals vorkommt, gib zurück: ``"No replacement was performed. Multiple occurrences of old_str `\{old_str}` in lines: {line_numbers}. Please ensure it is unique"``

#### Verzeichnisbehandlung

Wenn der Pfad ein Verzeichnis ist, gib einen „Datei existiert nicht“-Fehler zurück.

### insert

Fügt Text an einer bestimmten Zeile ein:

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

`insert_text` wird nach Zeile `insert_line` eingefügt, und `0` fügt am Anfang der Datei ein.

#### Rückgabewerte

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

#### Fehlerbehandlung

* **Datei existiert nicht:** `"Error: The path {path} does not exist"`
* **Ungültige Zeilennummer:** ``"Error: Invalid `insert_line` parameter: {insert_line}. It should be within the range of lines of the file: [0, {n_lines}]"``

#### Verzeichnisbehandlung

Wenn der Pfad ein Verzeichnis ist, gib einen „Datei existiert nicht“-Fehler zurück.

### delete

Löscht eine Datei oder ein Verzeichnis:

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

#### Rückgabewerte

* **Erfolg:** `"Successfully deleted {path}"`

#### Fehlerbehandlung

* **Datei oder Verzeichnis existiert nicht:** `"Error: The path {path} does not exist"`

#### Verzeichnisbehandlung

Löscht das Verzeichnis und seinen gesamten Inhalt rekursiv. Die Tool-Beschreibung teilt Claude mit, dass es das Verzeichnis `/memories` selbst nicht löschen kann, lehne also ein `delete` ab, dessen Pfad das Memory-Root ist.

### rename

Benennt eine Datei oder ein Verzeichnis um oder verschiebt sie:

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

#### Rückgabewerte

* **Erfolg:** `"Successfully renamed {old_path} to {new_path}"`

#### Fehlerbehandlung

* **Quelle existiert nicht:** `"Error: The path {old_path} does not exist"`
* **Ziel existiert bereits:** Gib einen Fehler zurück (nicht überschreiben): `"Error: The destination {new_path} already exists"`

#### Verzeichnisbehandlung

Benennt das Verzeichnis um. Die Tool-Beschreibung teilt Claude mit, dass es das Verzeichnis `/memories` selbst nicht umbenennen kann, lehne also ein `rename` ab, dessen `old_path` das Memory-Root ist.

## Prompting-Anleitung

Wenn das Memory-Tool in den `tools` deiner Anfrage vorhanden ist, fügt die API diese Anweisung automatisch zum System-Prompt hinzu. Du musst sie nicht selbst senden:

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

Claudes Tool-Beschreibung weist es bereits an, das Memory-Verzeichnis organisiert zu halten, sodass du diese Anweisung nicht wiederholen musst. Wenn Claude dennoch unübersichtliche Memory-Dateien erstellt, kannst du es in deinem Prompt verstärken:

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

Du kannst auch steuern, was Claude in das Memory schreibt. Zum Beispiel: „Only write down information relevant to \<topic> in your memory system.“

## Sicherheitsüberlegungen

Deine Anwendung führt jede Dateioperation aus, die Claude anfordert, daher liegen diese Schutzmaßnahmen in deiner Verantwortung:

### Sensible Informationen

Claude weigert sich normalerweise, sensible Informationen in Memory-Dateien zu schreiben. Für stärkere Garantien füge eine Validierung hinzu, die sensible Daten entfernt, bevor dein Handler die Datei schreibt.

### Dateispeichergröße

Verfolge die Größen der Memory-Dateien und begrenze, wie groß eine Datei werden kann. Erwäge, zu begrenzen, wie viele Zeichen der `view`-Befehl zurückgibt, und lass Claude den Rest mit `view_range` durchblättern.

### Memory-Ablauf

Lösche regelmäßig Memory-Dateien, auf die lange nicht zugegriffen wurde.

### Schutz vor Path Traversal

<Warning>
  Ein bösartiger Pfad wie `/memories/../../secrets.env` kann Dateien außerhalb des Verzeichnisses `/memories` erreichen. Deine Implementierung muss jeden Pfad in jedem Befehl validieren, um Directory-Traversal-Angriffe zu verhindern.
</Warning>

Erwäge diese Schutzmaßnahmen:

* Validiere, dass alle Pfade mit `/memories` beginnen
* Löse Pfade in ihre kanonische Form auf und überprüfe, dass sie innerhalb des Memory-Verzeichnisses bleiben
* Lehne Pfade ab, die Sequenzen wie `../`, `..\\` oder andere Traversal-Muster enthalten
* Achte auf URL-codierte Traversal-Sequenzen (`%2e%2e%2f`)
* Verwende die integrierten Pfad-Sicherheitsdienstprogramme deiner Sprache (zum Beispiel Pythons `pathlib.Path.resolve()` und `relative_to()`)

## Fehlerbehandlung

Das Memory-Tool verwendet ähnliche Fehlerbehandlungsmuster wie das [Texteditor-Tool](https://platform.claude.com/docs/de/agents-and-tools/tool-use/text-editor-tool#handle-errors). Die Fehlermeldungen jedes Befehls sind unter [Tool-Befehle](https://platform.claude.com/docs/de/agents-and-tools/tool-use/memory-tool#tool-commands) aufgeführt. Um einen Fehler an Claude zurückzugeben, setze `is_error` im Tool-Ergebnis auf `true` und platziere die Meldung in `content`:

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

## Integration der Kontextbearbeitung

Das Memory-Tool lässt sich mit der Kontextbearbeitung kombinieren, um langlaufende Gespräche zu verwalten. Details findest du unter [Kontextbearbeitung](https://platform.claude.com/docs/de/build-with-claude/context-editing).

## Verwendung mit Kompaktierung

Das Memory-Tool kann auch mit [Kompaktierung](https://platform.claude.com/docs/de/build-with-claude/compaction) kombiniert werden, die älteren Gesprächskontext serverseitig zusammenfasst. Die Kontextbearbeitung löscht bestimmte Tool-Ergebnisse auf dem Client. Die Kompaktierung fasst das gesamte Gespräch automatisch auf dem Server zusammen, wenn sich das Gespräch dem Limit des Kontextfensters nähert.

Für langlaufende Agenten erwäge, beides zu verwenden: Die Kompaktierung hält den aktiven Kontext klein ohne clientseitige Buchführung, und Memory bewahrt die Informationen, die die Zusammenfassung überleben müssen.

## Muster für Softwareentwicklung über mehrere Sitzungen

Für Softwareprojekte, die sich über mehrere Agent-Sitzungen erstrecken, richte Memory-Dateien bewusst ein, anstatt sie ad hoc zu schreiben, während die Arbeit voranschreitet. Das folgende Muster verwandelt Memory in einen Wiederherstellungsmechanismus: Jede neue Sitzung setzt von dem Zustand fort, den die letzte aufgezeichnet hat.

### Wie das Muster funktioniert

1. **Initialisierungssitzung:** Die erste Sitzung richtet die Memory-Dateien ein, bevor substanzielle Arbeit beginnt. Dazu gehören ein Fortschrittsprotokoll (das verfolgt, was getan wurde und was als Nächstes kommt), eine Feature-Checkliste (die den Arbeitsumfang definiert) und ein Verweis auf jedes Startup- oder Initialisierungsskript, das das Projekt benötigt.

2. **Nachfolgende Sitzungen:** Jede neue Sitzung beginnt mit dem Lesen dieser Memory-Dateien. Dies stellt den Projektzustand wieder her, ohne die Codebasis erneut zu erkunden oder frühere Entscheidungen nachzuvollziehen.

3. **Aktualisierung am Sitzungsende:** Bevor eine Sitzung endet, aktualisiert sie das Fortschrittsprotokoll mit dem, was abgeschlossen wurde und was verbleibt. Dies stellt sicher, dass die nächste Sitzung einen genauen Ausgangspunkt hat.

### Schlüsselprinzip

Arbeite an einem Feature nach dem anderen. Markiere ein Feature erst dann als abgeschlossen, wenn eine End-to-End-Verifizierung bestätigt, dass es funktioniert, nicht wenn der Code geschrieben ist. Dies hält das Fortschrittsprotokoll von Sitzung zu Sitzung genau.

<Tip>
  Für eine detaillierte Fallstudie dieses Musters in der Praxis, einschließlich des Initialisierungsskripts, der Struktur der Fortschrittsdatei und der git-basierten Wiederherstellung, siehe [Effektive Harnesses für langlaufende Agenten](https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents).
</Tip>

## Nächste Schritte

<CardGroup cols={2}>
  <Card title="Bash-Tool" icon="terminal" href="https://platform.claude.com/docs/de/agents-and-tools/tool-use/bash-tool">
    Führe Shell-Befehle in einer persistenten Bash-Sitzung aus.
  </Card>

  <Card title="Kontextbearbeitung" icon="edit" href="https://platform.claude.com/docs/de/build-with-claude/context-editing">
    Verwalte den Gesprächskontext automatisch, während er mit der Kontextbearbeitung wächst.
  </Card>

  <Card title="Kompaktierung" icon="stack" href="https://platform.claude.com/docs/de/build-with-claude/compaction">
    Serverseitige Kontextkompaktierung zur Verwaltung langer Gespräche, die sich den Limits des Kontextfensters nähern.
  </Card>

  <Card title="Tool-Referenz" icon="book" href="https://platform.claude.com/docs/de/agents-and-tools/tool-use/tool-reference">
    Verzeichnis der von Anthropic bereitgestellten Tools und Referenz für optionale Tool-Definitionseigenschaften.
  </Card>
</CardGroup>
