---
title: メモリツール
url: https://platform.claude.com/docs/ja/agents-and-tools/tool-use/memory-tool
description: アプリケーションでメモリツールのファイル操作を実装することで、Claudeが会話をまたいで情報を保存・取得できるようにします。
---

メモリツールを使用すると、Claudeはメモリファイルのディレクトリに情報を保存し、会話をまたいでその情報を取得できます。Claudeはセッション間で永続化されるファイルを作成、読み取り、更新、削除できます。これにより、すべてを「context window」（コンテキストウィンドウ）に保持しなくても、時間をかけて知識を蓄積できます。

メモリは「just-in-time context retrieval」（ジャストインタイムのコンテキスト取得）をサポートします。エージェントは関連するすべての情報を最初に読み込むのではなく、学んだことをメモリファイルに記録し、必要に応じて読み返します。これにより、アクティブなコンテキストを現在のタスクに集中させられます。この点は、放置するとコンテキストウィンドウを圧迫してしまう長時間実行セッションで重要です。このパターンの全体像については、[Effective context engineering](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents)を参照してください。

メモリツールは「client-side」（クライアントサイド）で動作します。Claudeがファイル操作をリクエストし、アプリケーションがそれを実行します。データをどこにどのように保存するかは、独自のインフラストラクチャを通じて制御できます。

<Note>
  この機能に関するフィードバックは、[フィードバックフォーム](https://forms.gle/YXC2EKGMhjN1c4L88)からお寄せください。
</Note>

<Note>
  「zero data retention」（ゼロデータ保持）、すなわちZDRがこの機能にどのように適用されるかについては、[APIとデータ保持](https://platform.claude.com/docs/ja/manage-claude/api-and-data-retention)を参照してください。
</Note>

## ユースケース

* 複数のエージェントセッションにわたってプロジェクトのコンテキストを維持する
* 過去のやり取り、決定、フィードバックから得た教訓を新しいタスクに適用する
* 時間をかけてナレッジベースを構築する

## 仕組み

メモリツールが有効になっている場合、Claudeはタスクを開始する前に自動的にメモリディレクトリを確認します。作業中、Claudeは学んだことを`/memories`配下のファイルに保存し、後の会話でそれらを読み返して以前の作業を継続します。

メモリツールはクライアントサイドで動作するため、Claudeはメモリ操作をリクエストするだけです。アプリケーションは、自身が管理するストレージに対して各リクエストを実行し、その結果を`tool_result`ブロックで返します（[ツール呼び出しの処理](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/handle-tool-calls)を参照）。`/memories`パスはプレフィックスであり、ハンドラーがこれをユーザーごとのディレクトリやデータベースのキーなどの実際のストレージにマッピングします。メモリは完全にアプリケーション内に存在します。後の会話が同じ`tools`エントリを送信し、ハンドラーが同じストアを提供すれば、その会話は同じメモリから継続されます。セキュリティのため、すべてのメモリ操作を`/memories`ディレクトリに制限してください（[パストラバーサル対策](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/memory-tool#path-traversal-protection)を参照）。

### 例：メモリツール呼び出しの仕組み

典型的なやり取りは次のようになります。

**1. ユーザーのリクエスト：**

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

**2. Claudeがメモリディレクトリを確認します：**

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

Claudeがメモリツールを呼び出します：

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

**3. アプリケーションがディレクトリの内容を返します：**

```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が関連するファイルを読み取ります：**

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

**5. アプリケーションがファイルの内容を返します：**

```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がメモリを活用して支援します：**

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

メモリツールは、すべてのClaude 4以降のモデルで利用できます。Anthropicが提供するツールの完全な一覧については、[ツールリファレンス](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/tool-reference)を参照してください。

## はじめに

メモリツールの使用は2つのステップで行います。

1. リクエストにメモリツールを追加します。`tools`エントリ`{"type": "memory_20250818", "name": "memory"}`が設定のすべてです。`name`は`memory`である必要があり、Anthropicが提供するツールについては入力スキーマを定義する必要はありません。
2. 各メモリコマンドに対するクライアントサイドのハンドラーを実装します。ハンドラーは`/memories`外のパスを拒否する必要があるため、実装する前に[パストラバーサル対策](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/memory-tool#path-traversal-protection)をお読みください。

## 基本的な使い方

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

## メモリハンドラーの実装

前述のようなリクエストに対するClaudeの応答は、`view /memories`などのメモリ操作をリクエストする`tool_use`ブロックで終わります。アプリケーションはその操作を実行して結果を`tool_result`ブロックで返し、Claudeが処理を続行できるように会話を送り返します。これが標準的な[ツール使用ループ](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/handle-tool-calls)です。

4つのSDKが、ツールインターフェースとループを処理するメモリツールヘルパーを提供しています。`BetaAbstractMemoryTool`をサブクラス化する（PythonおよびC#）、`betaMemoryTool`を使用する（TypeScript）、または`BetaMemoryToolHandler`を実装する（Java）ことで、ディスク上のファイル、データベース、クラウドストレージ、暗号化ファイルなど、独自のストレージでメモリを実装できます。PythonとTypeScriptには、すぐに使えるローカルファイルシステム実装である`BetaLocalFilesystemMemoryTool`も同梱されています。メモリツール自体はベータヘッダーを必要としませんが、ヘルパーとツールランナーのインターフェースはSDKのベータ名前空間に存在します。GoおよびRuby SDKにはメモリヘルパーがないため、それらの例ではツール使用ループを自前で実行します。PHPはハンドラーのクロージャを汎用の`BetaRunnableTool`でラップします。これら3つはいずれもインメモリストアを使用しており、独自のストレージに置き換えて使用します。

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

  // 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"
  )

  // メモリファイルのパスをその内容に対応付けるインメモリストアです。
  // 本番環境では独自のストレージを使用してください。
  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();

    // 6つのメモリコマンドを実装した BetaMemoryToolHandler の実装です
    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();

  // メモリファイルのパスをその内容に対応付けるインメモリストアです。
  // 本番環境では独自のストレージを使用してください。
  $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

  # メモリファイルのパスをその内容に対応付けるインメモリストアです。
  # 本番環境では独自のストレージを使用してください。
  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>

Go、PHP、Rubyの例では、インメモリストアを使用することで例を自己完結させています。各ストアは`tool_use`ブロックの`input`内の`command`フィールドに基づいて処理を振り分け、[ツールコマンド](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/memory-tool#tool-commands)で説明されている文字列を返します。本番環境のハンドラーには、これらのデモ用ストアでは省略されている[パス検証](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/memory-tool#path-traversal-protection)も必要です。各SDK独自の完全な例については、以下を参照してください。

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

## ツールコマンド

クライアントサイドの実装では、以下のコマンドを処理する必要があります。これらの仕様は推奨される動作と戻り値の文字列を示しています。Claudeはツール結果に含まれるテキストをそのまま読み取るため、アプリケーションで必要であれば異なる文字列を返すこともできます。

### view

ディレクトリの内容、またはファイルの内容（オプションで行範囲を指定可能）を表示します：

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

`view_range`はオプションで、テキストファイルの表示に適用されます。`[start_line, end_line]`はその範囲の行を返し、`[start_line, -1]`は`start_line`からファイルの末尾までのすべてを返します。

#### 戻り値

**ディレクトリの場合：** ファイルとディレクトリをそのサイズとともに示す一覧を返します：

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

* 最大2階層までのファイルを一覧表示します
* 人間が読みやすい形式でサイズを表示します（例：`5.5K`、`1.2M`）
* 隠しアイテム（`.`で始まるファイル）と`node_modules`を除外します
* サイズとパスの間にタブ文字を使用します

空のストアに対する`/memories`の最初の`view`はエラーではありません。SDKにローカルファイルシステムのメモリツールである`BetaLocalFilesystemMemoryTool`が同梱されている場合、このツールはClaudeの最初の呼び出しの前にメモリルートを作成し、一覧のヘッダーに続けて、空のディレクトリ自体を示すサイズとパスの1行を返します。

**ファイルの場合：** ヘッダーと行番号付きでファイルの内容を返します：

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

行番号の書式：

* **幅：** 6文字、スペースで埋めて右揃え
* **区切り文字：** 行番号と内容の間にタブ文字
* **インデックス：** 1始まり（最初の行は1行目）
* **行数の上限：** 999,999行を超えるファイルはエラーを返す必要があります：`"File {path} exceeds maximum line limit of 999,999 lines."`

**出力例：**

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

Claudeのツール説明には、`view`が画像ファイル（`.jpg`、`.jpeg`、`.png`）を表示すること、および16,000文字を超えるファイルのテキスト表示を切り詰めることも記載されています。画像パスに対する`view`呼び出しや、長いファイルに対する範囲指定付きの追加の表示が行われることを想定してください。

#### エラー処理

* **ファイルまたはディレクトリが存在しない場合：** `"The path {path} does not exist. Please provide a valid path."`

### create

新しいファイルを作成します：

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

#### 戻り値

* **成功時：** `"File created successfully at: {path}"`

#### エラー処理

* **ファイルがすでに存在する場合：** `"Error: File {path} already exists"`

Claudeのツール説明では`create`がファイルを「作成または上書きする」とされているため、すでに存在するパスに対する`create`呼び出しが行われることを想定してください。エラーを返すのがリファレンスの動作ですが、代わりに上書きすることも有効な実装上の選択です。

### str\_replace

ファイル内のテキストを置換します：

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

`str_replace`では`new_str`はオプションです。省略した場合、`old_str`は置換されずに削除されます。

#### 戻り値

* **成功時：** `"The memory file has been edited."`に続けて、編集されたファイルの行番号付きスニペット

#### エラー処理

* **ファイルが存在しない場合：** `"Error: The path {path} does not exist. Please provide a valid path."`
* **テキストが見つからない場合：** ``"No replacement was performed, old_str `\{old_str}` did not appear verbatim in {path}."``
* **テキストが重複している場合：** `old_str`が複数回出現する場合は、次を返します：``"No replacement was performed. Multiple occurrences of old_str `\{old_str}` in lines: {line_numbers}. Please ensure it is unique"``

#### ディレクトリの扱い

パスがディレクトリの場合は、「ファイルが存在しない」エラーを返します。

### insert

特定の行にテキストを挿入します：

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

`insert_text`は`insert_line`行目の後に挿入され、`0`を指定するとファイルの先頭に挿入されます。

#### 戻り値

* **成功時：** `"The file {path} has been edited."`

#### エラー処理

* **ファイルが存在しない場合：** `"Error: The path {path} does not exist"`
* **無効な行番号の場合：** ``"Error: Invalid `insert_line` parameter: {insert_line}. It should be within the range of lines of the file: [0, {n_lines}]"``

#### ディレクトリの扱い

パスがディレクトリの場合は、「ファイルが存在しない」エラーを返します。

### delete

ファイルまたはディレクトリを削除します：

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

#### 戻り値

* **成功時：** `"Successfully deleted {path}"`

#### エラー処理

* **ファイルまたはディレクトリが存在しない場合：** `"Error: The path {path} does not exist"`

#### ディレクトリの扱い

ディレクトリとそのすべての内容を再帰的に削除します。ツール説明ではClaudeに対して`/memories`ディレクトリ自体は削除できないと伝えているため、パスがメモリルートである`delete`は拒否してください。

### rename

ファイルまたはディレクトリの名前を変更、または移動します：

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

#### 戻り値

* **成功時：** `"Successfully renamed {old_path} to {new_path}"`

#### エラー処理

* **移動元が存在しない場合：** `"Error: The path {old_path} does not exist"`
* **移動先がすでに存在する場合：** エラーを返します（上書きしないでください）：`"Error: The destination {new_path} already exists"`

#### ディレクトリの扱い

ディレクトリの名前を変更します。ツール説明ではClaudeに対して`/memories`ディレクトリ自体の名前は変更できないと伝えているため、`old_path`がメモリルートである`rename`は拒否してください。

## プロンプトのガイダンス

リクエストの`tools`にメモリツールが含まれている場合、APIは次の指示を自動的にシステムプロンプトに追加します。自分で送信する必要はありません：

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

Claudeのツール説明ではすでにメモリディレクトリを整理された状態に保つよう指示しているため、その指示を繰り返す必要はありません。それでもClaudeが雑然としたメモリファイルを作成する場合は、プロンプトで指示を補強できます：

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

Claudeがメモリに書き込む内容を誘導することもできます。例：「メモリシステムには \<topic> に関連する情報のみを書き留めてください。」

## セキュリティに関する考慮事項

Claudeがリクエストするすべてのファイル操作はアプリケーションが実行するため、以下の安全対策はアプリケーション側の責任となります。

### 機密情報

Claudeは通常、機密情報をメモリファイルに書き込むことを拒否します。より強力な保証が必要な場合は、ハンドラーがファイルを書き込む前に機密データを除去する検証処理を追加してください。

### ファイルストレージのサイズ

メモリファイルのサイズを追跡し、ファイルが大きくなりすぎないよう上限を設けてください。`view`コマンドが返す文字数に上限を設け、残りの部分はClaudeが`view_range`でページングして読めるようにすることも検討してください。

### メモリの有効期限

長期間アクセスされていないメモリファイルは定期的に削除してください。

### パストラバーサル対策

<Warning>
  `/memories/../../secrets.env`のような悪意のあるパスは、`/memories`ディレクトリ外のファイルに到達する可能性があります。「directory traversal attack」（ディレクトリトラバーサル攻撃）を防ぐため、実装ではすべてのコマンドのすべてのパスを検証する必要があります。
</Warning>

以下の安全対策を検討してください：

* すべてのパスが`/memories`で始まることを検証する
* パスを正規形に解決し、メモリディレクトリ内に収まっていることを確認する
* `../`、`..\\`などのシーケンスやその他のトラバーサルパターンを含むパスを拒否する
* URLエンコードされたトラバーサルシーケンス（`%2e%2e%2f`）に注意する
* 使用する言語に組み込まれたパスセキュリティユーティリティを使用する（例：Pythonの`pathlib.Path.resolve()`と`relative_to()`）

## エラー処理

メモリツールは、[テキストエディタツール](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/text-editor-tool#handle-errors)と同様のエラー処理パターンを使用します。各コマンドのエラーメッセージは[ツールコマンド](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/memory-tool#tool-commands)に記載されています。Claudeにエラーを返すには、ツール結果の`is_error`を`true`に設定し、メッセージを`content`に入れます：

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

## コンテキスト編集との統合

メモリツールは「context editing」（コンテキスト編集）と組み合わせて、長時間実行される会話を管理できます。詳細については、[コンテキスト編集](https://platform.claude.com/docs/ja/build-with-claude/context-editing)を参照してください。

## コンパクションとの併用

メモリツールは、古い会話コンテキストをサーバーサイドで要約する[「compaction」（コンパクション）](https://platform.claude.com/docs/ja/build-with-claude/compaction)と組み合わせることもできます。コンテキスト編集は、クライアント上で特定のツール結果をクリアします。コンパクションは、会話がコンテキストウィンドウの上限に近づくと、サーバー上で会話全体を自動的に要約します。

長時間実行されるエージェントでは、両方の使用を検討してください。コンパクションはクライアントサイドでの管理作業なしにアクティブなコンテキストを小さく保ち、メモリは要約後も残す必要がある情報を保持します。

## マルチセッションのソフトウェア開発パターン

複数のエージェントセッションにまたがるソフトウェアプロジェクトでは、作業の進行に合わせて場当たり的にメモリファイルを書き込むのではなく、意図的にメモリファイルを設計してください。次のパターンでは、メモリを復旧メカニズムとして活用します。新しいセッションはそれぞれ、前回のセッションが記録した状態から再開します。

### パターンの仕組み

1. **初期化セッション：** 最初のセッションでは、実質的な作業を始める前にメモリファイルをセットアップします。これには、進捗ログ（完了した作業と次に行う作業を追跡）、機能チェックリスト（作業範囲を定義）、およびプロジェクトに必要な起動スクリプトや初期化スクリプトへの参照が含まれます。

2. **後続のセッション：** 新しいセッションはそれぞれ、まずこれらのメモリファイルを読み込みます。これにより、コードベースを再調査したり以前の決定をたどり直したりすることなく、プロジェクトの状態を復元できます。

3. **セッション終了時の更新：** セッションを終了する前に、完了した作業と残っている作業で進捗ログを更新します。これにより、次のセッションが正確な出発点を持てるようになります。

### 重要な原則

一度に1つの機能に取り組んでください。機能を完了としてマークするのは、コードを書いた時点ではなく、エンドツーエンドの検証で動作が確認された後にしてください。これにより、セッションをまたいで進捗ログの正確さが保たれます。

<Tip>
  初期化スクリプト、進捗ファイルの構造、gitベースの復旧など、このパターンを実践した詳細なケーススタディについては、[Effective harnesses for long-running agents](https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents)を参照してください。
</Tip>

## 次のステップ

<CardGroup cols={2}>
  <Card title="Bashツール" icon="terminal" href="https://platform.claude.com/docs/ja/agents-and-tools/tool-use/bash-tool">
    永続的なbashセッションでシェルコマンドを実行します。
  </Card>

  <Card title="コンテキスト編集" icon="edit" href="https://platform.claude.com/docs/ja/build-with-claude/context-editing">
    コンテキスト編集により、増大する会話コンテキストを自動的に管理します。
  </Card>

  <Card title="コンパクション" icon="stack" href="https://platform.claude.com/docs/ja/build-with-claude/compaction">
    コンテキストウィンドウの上限に近づく長い会話を管理するための、サーバーサイドのコンテキストコンパクションです。
  </Card>

  <Card title="ツールリファレンス" icon="book" href="https://platform.claude.com/docs/ja/agents-and-tools/tool-use/tool-reference">
    Anthropicが提供するツールの一覧と、オプションのツール定義プロパティのリファレンスです。
  </Card>
</CardGroup>
