Repository Public
1---2title: Memory tool3url: https://platform.claude.com/docs/en/agents-and-tools/tool-use/memory-tool4description: Let Claude store and retrieve information across conversations by implementing the memory tool's file operations in your application.5---67The memory tool lets Claude store and retrieve information across conversations in a directory of memory files. Claude can create, read, update, and delete files that persist between sessions, building up knowledge over time without keeping everything in the context window.89Memory supports just-in-time context retrieval. Rather than loading all relevant information up front, an agent records what it learns in memory files and reads them back on demand. This keeps the active context focused on the current task, which matters for long-running sessions that would otherwise overwhelm the context window. See [Effective context engineering](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents) for the broader pattern.1011The memory tool operates client-side: Claude requests file operations, and your application executes them. You control where and how the data is stored through your own infrastructure.1213<Note>14 Reach out through the [feedback form](https://forms.gle/YXC2EKGMhjN1c4L88) to share your feedback on this feature.15</Note>1617<Note>18 To learn how zero data retention (ZDR) applies to this feature, see [API and data retention](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention).19</Note>2021## Use cases2223* Maintain project context across multiple agent sessions24* Apply lessons from past interactions, decisions, and feedback to new tasks25* Build up a knowledge base over time2627## How it works2829When the memory tool is enabled, Claude automatically checks its memory directory before starting a task. As it works, Claude stores what it learns in files under `/memories` and reads them back in later conversations to continue earlier work.3031Because the memory tool is client-side, Claude only requests memory operations. Your application executes each request against storage you control and returns the result in a `tool_result` block (see [Handle tool calls](https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls)). The `/memories` path is a prefix that your handler maps onto real storage, such as a per-user directory or keys in a database. Memory lives entirely in your application. A later conversation continues from the same memory when it sends the same `tools` entry and your handler serves the same store. For security, restrict all memory operations to the `/memories` directory (see [Path traversal protection](https://platform.claude.com/docs/en/agents-and-tools/tool-use/memory-tool#path-traversal-protection)).3233### Example: How memory tool calls work3435A typical interaction looks like this:3637**1. User request:**3839```text wrap40"Help me respond to this customer service ticket."41```4243**2. Claude checks the memory directory:**4445```text wrap46"I'll help you respond to the customer service ticket. Let me check my memory for any previous context."47```4849Claude calls the memory tool:5051```json52{53 "type": "tool_use",54 "id": "toolu_01C4D5E6F7G8H9I0J1K2L3M4",55 "name": "memory",56 "input": {57 "command": "view",58 "path": "/memories"59 }60}61```6263**3. Your application returns the directory contents:**6465```json66{67 "type": "tool_result",68 "tool_use_id": "toolu_01C4D5E6F7G8H9I0J1K2L3M4",69 "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"70}71```7273**4. Claude reads relevant files:**7475```json76{77 "type": "tool_use",78 "id": "toolu_01D5E6F7G8H9I0J1K2L3M4N5",79 "name": "memory",80 "input": {81 "command": "view",82 "path": "/memories/customer_service_guidelines.xml"83 }84}85```8687**5. Your application returns the file contents:**8889```json90{91 "type": "tool_result",92 "tool_use_id": "toolu_01D5E6F7G8H9I0J1K2L3M4N5",93 "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..."94}95```9697**6. Claude uses the memory to help:**9899```text wrap100"Based on your customer service guidelines, I can help you craft a response. Please share the ticket details..."101```102103The memory tool is available on all Claude 4 and later models. For the full list of Anthropic-provided tools, see the [Tool reference](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-reference).104105## Getting started106107Using the memory tool takes two steps:1081091. Add the memory tool to your request. The `tools` entry `{"type": "memory_20250818", "name": "memory"}` is the entire configuration: the `name` must be `memory`, and you don't define an input schema for an Anthropic-provided tool.1102. Implement a client-side handler for each memory command. Your handler must reject paths outside `/memories`, so read [Path traversal protection](https://platform.claude.com/docs/en/agents-and-tools/tool-use/memory-tool#path-traversal-protection) before you write it.111112## Basic usage113114<CodeGroup>115 ```bash cURL116 curl https://api.anthropic.com/v1/messages \117 -H "x-api-key: $ANTHROPIC_API_KEY" \118 -H "anthropic-version: 2023-06-01" \119 -H "content-type: application/json" \120 -d '{121 "model": "claude-opus-5",122 "max_tokens": 2048,123 "messages": [124 {125 "role": "user",126 "content": "Help me respond to this customer service ticket."127 }128 ],129 "tools": [{130 "type": "memory_20250818",131 "name": "memory"132 }]133 }'134 ```135136 ```bash CLI137 ant messages create <<'YAML'138 model: claude-opus-5139 max_tokens: 2048140 tools:141 - type: memory_20250818142 name: memory143 messages:144 - role: user145 content: Help me respond to this customer service ticket.146 YAML147 ```148149 ```python Python150 client = anthropic.Anthropic()151152 message = client.messages.create(153 model="claude-opus-5",154 max_tokens=2048,155 messages=[156 {157 "role": "user",158 "content": "Help me respond to this customer service ticket.",159 }160 ],161 tools=[{"type": "memory_20250818", "name": "memory"}],162 )163164 print(message)165 ```166167 ```typescript TypeScript168 const anthropic = new Anthropic();169170 const message = await anthropic.messages.create({171 model: "claude-opus-5",172 max_tokens: 2048,173 messages: [174 {175 role: "user",176 content: "Help me respond to this customer service ticket."177 }178 ],179 tools: [{ type: "memory_20250818", name: "memory" }]180 });181182 console.log(message);183 ```184185 ```csharp C#186 var client = new AnthropicClient();187188 var message = await client.Messages.Create(189 new()190 {191 Model = Model.ClaudeOpus5,192 MaxTokens = 2048,193 Messages =194 [195 new()196 {197 Role = Role.User,198 Content = "Help me respond to this customer service ticket.",199 },200 ],201 Tools = [new MemoryTool20250818()],202 }203 );204205 Console.WriteLine(message);206 ```207208 ```go Go209 client := anthropic.NewClient()210211 message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{212 Model: anthropic.ModelClaudeOpus5,213 MaxTokens: 2048,214 Messages: []anthropic.MessageParam{215 anthropic.NewUserMessage(anthropic.NewTextBlock("Help me respond to this customer service ticket.")),216 },217 Tools: []anthropic.ToolUnionParam{218 {OfMemoryTool20250818: &anthropic.MemoryTool20250818Param{}},219 },220 })221 if err != nil {222 log.Fatal(err)223 }224 fmt.Println(message)225 ```226227 ```java Java228 import com.anthropic.models.messages.MemoryTool20250818;229 // ...230 AnthropicClient client = AnthropicOkHttpClient.fromEnv();231232 MessageCreateParams params = MessageCreateParams.builder()233 .model(Model.CLAUDE_OPUS_5)234 .maxTokens(2048L)235 .addTool(MemoryTool20250818.builder().build())236 .addUserMessage("Help me respond to this customer service ticket.")237 .build();238239 Message message = client.messages().create(params);240 IO.println(message);241 ```242243 ```php PHP244 $client = new Client();245246 $message = $client->messages->create(247 model: Model::CLAUDE_OPUS_5,248 maxTokens: 2048,249 messages: [250 [251 'role' => 'user',252 'content' => 'Help me respond to this customer service ticket.',253 ],254 ],255 tools: [new MemoryTool20250818],256 );257258 echo $message;259 ```260261 ```ruby Ruby262 client = Anthropic::Client.new263264 message = client.messages.create(265 model: Anthropic::Model::CLAUDE_OPUS_5,266 max_tokens: 2048,267 messages: [268 {269 role: "user",270 content: "Help me respond to this customer service ticket."271 }272 ],273 tools: [274 {275 type: "memory_20250818",276 name: "memory"277 }278 ]279 )280 puts message281 ```282</CodeGroup>283284## Implement the memory handler285286Claude's reply to a request like the previous one ends with a `tool_use` block that requests a memory operation, such as `view /memories`. Your application executes the operation and returns the result in a `tool_result` block, then sends the conversation back so Claude can continue: the standard [tool-use loop](https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls).287288Four SDKs provide memory tool helpers that handle the tool interface and the loop. Subclass `BetaAbstractMemoryTool` (Python and C#), use `betaMemoryTool` (TypeScript), or implement `BetaMemoryToolHandler` (Java) to back memory with your own storage, such as files on disk, a database, cloud storage, or encrypted files. Python and TypeScript also ship a ready-made local-filesystem implementation, `BetaLocalFilesystemMemoryTool`. The helper and tool-runner surfaces live in each SDK's beta namespace even though the memory tool itself doesn't require a beta header. The Go and Ruby SDKs have no memory helper, so those examples run the tool-use loop themselves, and PHP wraps your handler closure in its generic `BetaRunnableTool`. All three use an in-memory store that you replace with your own storage.289290<CodeGroup exclude="shell">291 ```python Python292 import anthropic293 from anthropic.tools import BetaLocalFilesystemMemoryTool294295 client = anthropic.Anthropic()296 memory = BetaLocalFilesystemMemoryTool(base_path="./memory")297298 runner = client.beta.messages.tool_runner(299 model="claude-opus-5",300 max_tokens=1024,301 messages=[302 {303 "role": "user",304 "content": "Remember that customer Acme Corp prefers email follow-ups.",305 }306 ],307 tools=[memory],308 )309310 final_message = runner.until_done()311 print(final_message.content)312 ```313314 ```typescript TypeScript315 import Anthropic from "@anthropic-ai/sdk";316 import { betaMemoryTool } from "@anthropic-ai/sdk/helpers/beta/memory";317 import { BetaLocalFilesystemMemoryTool } from "@anthropic-ai/sdk/tools/memory/node";318319 const client = new Anthropic();320321 const backend = await BetaLocalFilesystemMemoryTool.init("./memory");322 const memory = betaMemoryTool(backend); // or pass your own handlers object323324 const runner = client.beta.messages.toolRunner({325 model: "claude-opus-5",326 max_tokens: 1024,327 messages: [328 {329 role: "user",330 content: "Remember that customer Acme Corp prefers email follow-ups."331 }332 ],333 tools: [memory],334 max_iterations: 10335 });336337 const finalMessage = await runner;338 console.log(finalMessage.content);339 ```340341 ```csharp C#342 using Anthropic;343 using Anthropic.Helpers.Beta;344 using Anthropic.Models.Beta.Messages;345346 var client = new AnthropicClient();347348 // Your subclass of BetaAbstractMemoryTool349 var memory = new FilesystemMemoryTool("./memories");350351 var runner = client.Beta.Messages.ToolRunner(352 new MessageCreateParams353 {354 Model = Anthropic.Models.Messages.Model.ClaudeOpus5,355 MaxTokens = 1024,356 Messages =357 [358 new()359 {360 Role = Role.User,361 Content = "Remember that customer Acme Corp prefers email follow-ups.",362 },363 ],364 },365 [memory],366 maxIterations: 10367 );368369 var finalMessage = await runner.RunUntilDoneAsync();370 Console.WriteLine(finalMessage);371 ```372373 ```go Go374 package main375376 import (377 "context"378 "encoding/json"379 "fmt"380 "log"381 "slices"382 "sort"383 "strings"384385 "github.com/anthropics/anthropic-sdk-go"386 )387388 // An in-memory store that maps memory file paths to their contents.389 // Use your own storage in production.390 var store = map[string]string{}391392 type memoryCommand struct {393 Command string `json:"command"`394 Path string `json:"path"`395 FileText string `json:"file_text"`396 OldStr string `json:"old_str"`397 NewStr string `json:"new_str"`398 InsertLine int `json:"insert_line"`399 InsertText string `json:"insert_text"`400 OldPath string `json:"old_path"`401 NewPath string `json:"new_path"`402 }403404 func executeMemory(raw json.RawMessage) string {405 var cmd memoryCommand406 if err := json.Unmarshal(raw, &cmd); err != nil {407 return "Error: invalid memory command"408 }409 switch cmd.Command {410 case "view":411 if content, ok := store[cmd.Path]; ok {412 lines := strings.Split(strings.TrimSuffix(content, "\n"), "\n")413 for i, line := range lines {414 lines[i] = fmt.Sprintf("%6d\t%s", i+1, line)415 }416 return fmt.Sprintf("Here's the content of %s with line numbers:\n%s", cmd.Path, strings.Join(lines, "\n"))417 }418 if cmd.Path == "/memories" {419 listing := []string{"1.0K\t/memories"}420 for path := range store {421 listing = append(listing, "1.0K\t"+path)422 }423 sort.Strings(listing[1:])424 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"))425 }426 return fmt.Sprintf("The path %s does not exist. Please provide a valid path.", cmd.Path)427 case "create":428 store[cmd.Path] = cmd.FileText429 return "File created successfully at: " + cmd.Path430 case "str_replace":431 content, ok := store[cmd.Path]432 if !ok || !strings.Contains(content, cmd.OldStr) {433 return fmt.Sprintf("No replacement was performed, old_str `%s` did not appear verbatim in %s.", cmd.OldStr, cmd.Path)434 }435 store[cmd.Path] = strings.Replace(content, cmd.OldStr, cmd.NewStr, 1)436 return "The memory file has been edited."437 case "insert":438 content, ok := store[cmd.Path]439 if !ok {440 return fmt.Sprintf("Error: The path %s does not exist", cmd.Path)441 }442 lines := strings.Split(content, "\n")443 if cmd.InsertLine < 0 || cmd.InsertLine > len(lines) {444 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))445 }446 lines = slices.Insert(lines, cmd.InsertLine, strings.TrimSuffix(cmd.InsertText, "\n"))447 store[cmd.Path] = strings.Join(lines, "\n")448 return fmt.Sprintf("The file %s has been edited.", cmd.Path)449 case "delete":450 if _, ok := store[cmd.Path]; !ok {451 return fmt.Sprintf("Error: The path %s does not exist", cmd.Path)452 }453 delete(store, cmd.Path)454 return "Successfully deleted " + cmd.Path455 case "rename":456 if _, ok := store[cmd.OldPath]; !ok {457 return fmt.Sprintf("Error: The path %s does not exist", cmd.OldPath)458 }459 if _, ok := store[cmd.NewPath]; ok {460 return fmt.Sprintf("Error: The destination %s already exists", cmd.NewPath)461 }462 store[cmd.NewPath] = store[cmd.OldPath]463 delete(store, cmd.OldPath)464 return fmt.Sprintf("Successfully renamed %s to %s", cmd.OldPath, cmd.NewPath)465 default:466 return "Error: unknown command " + cmd.Command467 }468 }469470 func main() {471 client := anthropic.NewClient()472 tools := []anthropic.ToolUnionParam{{OfMemoryTool20250818: &anthropic.MemoryTool20250818Param{}}}473 messages := []anthropic.MessageParam{474 anthropic.NewUserMessage(anthropic.NewTextBlock("Remember that customer Acme Corp prefers email follow-ups.")),475 }476477 for {478 message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{479 Model: anthropic.ModelClaudeOpus5,480 MaxTokens: 1024,481 Messages: messages,482 Tools: tools,483 })484 if err != nil {485 log.Fatal(err)486 }487 if message.StopReason != anthropic.StopReasonToolUse {488 for _, block := range message.Content {489 if block.Type == "text" {490 fmt.Println(block.Text)491 }492 }493 break494 }495 results := []anthropic.ContentBlockParamUnion{}496 for _, block := range message.Content {497 if block.Type == "tool_use" {498 results = append(results, anthropic.NewToolResultBlock(block.ID, executeMemory(block.Input), false))499 }500 }501 messages = append(messages, message.ToParam(), anthropic.NewUserMessage(results...))502 }503 }504 ```505506 ```java Java507 import com.anthropic.client.AnthropicClient;508 import com.anthropic.client.okhttp.AnthropicOkHttpClient;509 import com.anthropic.helpers.BetaMemoryToolHandler;510 import com.anthropic.helpers.BetaToolRunner;511 import com.anthropic.models.beta.messages.BetaMemoryTool20250818;512 import com.anthropic.models.beta.messages.BetaMessage;513 import com.anthropic.models.beta.messages.MessageCreateParams; // beta package, not models.messages514 import com.anthropic.models.beta.messages.ToolRunnerCreateParams;515 import com.anthropic.models.messages.Model;516 import java.nio.file.Path;517518 void main() {519 AnthropicClient client = AnthropicOkHttpClient.fromEnv();520521 // Your BetaMemoryToolHandler implementation of the six memory commands522 BetaMemoryToolHandler handler = new FileSystemMemoryToolHandler(Path.of("memories"));523524 MessageCreateParams createParams = MessageCreateParams.builder()525 .model(Model.CLAUDE_OPUS_5)526 .maxTokens(1024L)527 .addTool(BetaMemoryTool20250818.builder().build())528 .addUserMessage("Remember that customer Acme Corp prefers email follow-ups.")529 .build();530531 ToolRunnerCreateParams runnerParams = ToolRunnerCreateParams.builder()532 .betaMemoryToolHandler(handler)533 .initialMessageParams(createParams)534 .maxIterations(10)535 .build();536537 BetaToolRunner runner = client.beta().messages().toolRunner(runnerParams);538 for (BetaMessage message : runner) {539 IO.println(message);540 }541 }542 ```543544 ```php PHP545 <?php546547 use Anthropic\Beta\Messages\BetaMemoryTool20250818;548 use Anthropic\Client;549 use Anthropic\Lib\Tools\BetaRunnableTool;550 use Anthropic\Messages\Model;551552 $client = new Client();553554 // An in-memory store that maps memory file paths to their contents.555 // Use your own storage in production.556 $store = [];557558 $memory = new BetaRunnableTool(559 definition: new BetaMemoryTool20250818,560 run: function (array $input) use (&$store): string {561 $path = $input['path'] ?? '';562 switch ($input['command']) {563 case 'view':564 if (isset($store[$path])) {565 $numbered = [];566 foreach (explode("\n", preg_replace('/\n\z/', '', $store[$path])) as $i => $line) {567 $numbered[] = sprintf("%6d\t%s", $i + 1, $line);568 }569 return "Here's the content of {$path} with line numbers:\n" . implode("\n", $numbered);570 }571 if ($path === '/memories') {572 $listing = ["1.0K\t/memories"];573 foreach (array_keys($store) as $stored) {574 $listing[] = "1.0K\t{$stored}";575 }576 return "Here're the files and directories up to 2 levels deep in {$path}, excluding hidden items and node_modules:\n" . implode("\n", $listing);577 }578 return "The path {$path} does not exist. Please provide a valid path.";579 case 'create':580 $store[$path] = $input['file_text'];581 return "File created successfully at: {$path}";582 case 'str_replace':583 $position = strpos($store[$path] ?? '', $input['old_str']);584 if ($position === false) {585 return "No replacement was performed, old_str `{$input['old_str']}` did not appear verbatim in {$path}.";586 }587 $store[$path] = substr_replace($store[$path], $input['new_str'] ?? '', $position, strlen($input['old_str']));588 return 'The memory file has been edited.';589 case 'insert':590 if (!isset($store[$path])) {591 return "Error: The path {$path} does not exist";592 }593 $lines = explode("\n", $store[$path]);594 if ($input['insert_line'] < 0 || $input['insert_line'] > count($lines)) {595 return "Error: Invalid `insert_line` parameter: {$input['insert_line']}. It should be within the range of lines of the file: [0, " . count($lines) . "]";596 }597 array_splice($lines, $input['insert_line'], 0, [preg_replace('/\n\z/', '', $input['insert_text'])]);598 $store[$path] = implode("\n", $lines);599 return "The file {$path} has been edited.";600 case 'delete':601 if (!isset($store[$path])) {602 return "Error: The path {$path} does not exist";603 }604 unset($store[$path]);605 return "Successfully deleted {$path}";606 case 'rename':607 if (!isset($store[$input['old_path']])) {608 return "Error: The path {$input['old_path']} does not exist";609 }610 if (isset($store[$input['new_path']])) {611 return "Error: The destination {$input['new_path']} already exists";612 }613 $store[$input['new_path']] = $store[$input['old_path']];614 unset($store[$input['old_path']]);615 return "Successfully renamed {$input['old_path']} to {$input['new_path']}";616 default:617 return "Error: unknown command {$input['command']}";618 }619 },620 );621622 $runner = $client->beta->messages->toolRunner(623 maxTokens: 1024,624 messages: [['role' => 'user', 'content' => 'Remember that customer Acme Corp prefers email follow-ups.']],625 model: Model::CLAUDE_OPUS_5,626 tools: [$memory],627 maxIterations: 10,628 );629630 $finalMessage = $runner->runUntilDone();631 print_r($finalMessage->content);632 ```633634 ```ruby Ruby635 require "anthropic"636637 client = Anthropic::Client.new638 TOOLS = [{type: "memory_20250818", name: "memory"}].freeze639640 # An in-memory store that maps memory file paths to their contents.641 # Use your own storage in production.642 STORE = {}643644 def execute_memory(input)645 path = input[:path]646 case input[:command]647 when "view"648 if STORE.key?(path)649 lines = STORE[path].chomp.split("\n", -1)650 lines = [""] if lines.empty?651 numbered = lines.each_with_index.map { |line, i| format("%6d\t%s", i + 1, line) }652 "Here's the content of #{path} with line numbers:\n#{numbered.join("\n")}"653 elsif path == "/memories"654 listing = ["1.0K\t/memories"] + STORE.keys.map { |stored| "1.0K\t#{stored}" }655 "Here're the files and directories up to 2 levels deep in #{path}, excluding hidden items and node_modules:\n#{listing.join("\n")}"656 else657 "The path #{path} does not exist. Please provide a valid path."658 end659 when "create"660 STORE[path] = input[:file_text]661 "File created successfully at: #{path}"662 when "str_replace"663 unless STORE.key?(path) && STORE[path].include?(input[:old_str])664 return "No replacement was performed, old_str `#{input[:old_str]}` did not appear verbatim in #{path}."665 end666 STORE[path] = STORE[path].sub(input[:old_str]) { input[:new_str].to_s }667 "The memory file has been edited."668 when "insert"669 return "Error: The path #{path} does not exist" unless STORE.key?(path)670 lines = STORE[path].split("\n", -1)671 lines = [""] if lines.empty?672 if input[:insert_line] < 0 || input[:insert_line] > lines.length673 return "Error: Invalid `insert_line` parameter: #{input[:insert_line]}. It should be within the range of lines of the file: [0, #{lines.length}]"674 end675 lines.insert(input[:insert_line], input[:insert_text].chomp)676 STORE[path] = lines.join("\n")677 "The file #{path} has been edited."678 when "delete"679 return "Error: The path #{path} does not exist" unless STORE.key?(path)680 STORE.delete(path)681 "Successfully deleted #{path}"682 when "rename"683 return "Error: The path #{input[:old_path]} does not exist" unless STORE.key?(input[:old_path])684 return "Error: The destination #{input[:new_path]} already exists" if STORE.key?(input[:new_path])685 STORE[input[:new_path]] = STORE.delete(input[:old_path])686 "Successfully renamed #{input[:old_path]} to #{input[:new_path]}"687 else688 "Error: unknown command #{input[:command]}"689 end690 end691692 messages = [{role: "user", content: "Remember that customer Acme Corp prefers email follow-ups."}]693 loop do694 message = client.messages.create(695 model: Anthropic::Model::CLAUDE_OPUS_5,696 max_tokens: 1024,697 messages: messages,698 tools: TOOLS699 )700 unless message.stop_reason == :tool_use701 puts message.content702 break703 end704 tool_results = message.content.filter_map do |block|705 next unless block.type == :tool_use706 {type: "tool_result", tool_use_id: block.id, content: execute_memory(block.input)}707 end708 messages << {role: "assistant", content: message.content} << {role: "user", content: tool_results}709 end710 ```711</CodeGroup>712713The in-memory stores in the Go, PHP, and Ruby examples keep them self-contained: each one dispatches on the `command` field in the `tool_use` block's `input` and returns the strings described under [Tool commands](https://platform.claude.com/docs/en/agents-and-tools/tool-use/memory-tool#tool-commands). A production handler also needs the [path validation](https://platform.claude.com/docs/en/agents-and-tools/tool-use/memory-tool#path-traversal-protection) these demonstration stores skip. For the SDKs' own complete examples, see:714715* Python: [examples/memory/basic.py](https://github.com/anthropics/anthropic-sdk-python/blob/main/examples/memory/basic.py)716* TypeScript: [examples/tools-helpers-memory.ts](https://github.com/anthropics/anthropic-sdk-typescript/blob/main/examples/tools-helpers-memory.ts)717* C#: [MemoryToolExample](https://github.com/anthropics/anthropic-sdk-csharp/tree/main/examples/MemoryToolExample)718* Java: [BetaMemoryToolExample.java](https://github.com/anthropics/anthropic-sdk-java/blob/main/anthropic-java-example/src/main/java/com/anthropic/example/BetaMemoryToolExample.java)719720## Tool commands721722Your client-side implementation must handle the following commands. These specifications describe the recommended behaviors and return strings: Claude reads whatever text your tool result contains, so you can return different strings if your application needs to.723724### view725726Shows directory contents or file contents with optional line ranges:727728```json729{730 "command": "view",731 "path": "/memories/notes.txt",732 "view_range": [1, 10]733}734```735736`view_range` is optional and applies to text-file views: `[start_line, end_line]` returns those lines, and `[start_line, -1]` returns everything from `start_line` to the end of the file.737738#### Return values739740**For directories:** Return a listing that shows files and directories with their sizes:741742```text743Here're the files and directories up to 2 levels deep in {path}, excluding hidden items and node_modules:744{size}\t{path}745{size}\t{path}/{filename1}746{size}\t{path}/{filename2}747```748749* Lists files up to 2 levels deep750* Shows human-readable sizes (for example, `5.5K`, `1.2M`)751* Excludes hidden items (files starting with `.`) and `node_modules`752* Uses a tab character between the size and the path753754The first `view` of `/memories` on an empty store is not an error. The SDKs' local-filesystem memory tools (`BetaLocalFilesystemMemoryTool`) create the memory root before Claude's first call and return the listing header followed by a single size-and-path line for the empty directory itself.755756**For files:** Return file contents with a header and line numbers:757758```text wrap759Here's the content of {path} with line numbers:760{line_numbers}{tab}{content}761```762763Line number formatting:764765* **Width:** 6 characters, right-aligned with space padding766* **Separator:** Tab character between line number and content767* **Indexing:** 1-indexed (first line is line 1)768* **Line limit:** Files with more than 999,999 lines should return an error: `"File {path} exceeds maximum line limit of 999,999 lines."`769770**Example output:**771772```text773Here's the content of /memories/notes.txt with line numbers:774 1 Hello World775 2 This is line two776 10 Line ten777 100 Line one hundred778```779780Claude's tool description also says that `view` displays image files (`.jpg`, `.jpeg`, and `.png`) and truncates the text view of files longer than 16,000 characters. Expect `view` calls on image paths and follow-up ranged views of long files.781782#### Error handling783784* **File or directory does not exist:** `"The path {path} does not exist. Please provide a valid path."`785786### create787788Creates a new file:789790```json791{792 "command": "create",793 "path": "/memories/notes.txt",794 "file_text": "Meeting notes:\n- Discussed project timeline\n- Next steps defined\n"795}796```797798#### Return values799800* **Success:** `"File created successfully at: {path}"`801802#### Error handling803804* **File already exists:** `"Error: File {path} already exists"`805806Claude's tool description says `create` "creates or overwrites" a file, so expect `create` calls on paths that already exist. Returning the error is the reference behavior, and overwriting instead is a valid implementation choice.807808### str\_replace809810Replaces text in a file:811812```json813{814 "command": "str_replace",815 "path": "/memories/preferences.txt",816 "old_str": "Favorite color: blue",817 "new_str": "Favorite color: green"818}819```820821`new_str` is optional for `str_replace`: when it's omitted, `old_str` is deleted without a replacement.822823#### Return values824825* **Success:** `"The memory file has been edited."` followed by a snippet of the edited file with line numbers826827#### Error handling828829* **File does not exist:** `"Error: The path {path} does not exist. Please provide a valid path."`830* **Text not found:** ``"No replacement was performed, old_str `\{old_str}` did not appear verbatim in {path}."``831* **Duplicate text:** When `old_str` appears multiple times, return: ``"No replacement was performed. Multiple occurrences of old_str `\{old_str}` in lines: {line_numbers}. Please ensure it is unique"``832833#### Directory handling834835If the path is a directory, return a "file does not exist" error.836837### insert838839Inserts text at a specific line:840841```json842{843 "command": "insert",844 "path": "/memories/todo.txt",845 "insert_line": 2,846 "insert_text": "- Review memory tool documentation\n"847}848```849850`insert_text` is inserted after line `insert_line`, and `0` inserts at the beginning of the file.851852#### Return values853854* **Success:** `"The file {path} has been edited."`855856#### Error handling857858* **File does not exist:** `"Error: The path {path} does not exist"`859* **Invalid line number:** ``"Error: Invalid `insert_line` parameter: {insert_line}. It should be within the range of lines of the file: [0, {n_lines}]"``860861#### Directory handling862863If the path is a directory, return a "file does not exist" error.864865### delete866867Deletes a file or directory:868869```json870{871 "command": "delete",872 "path": "/memories/old_file.txt"873}874```875876#### Return values877878* **Success:** `"Successfully deleted {path}"`879880#### Error handling881882* **File or directory does not exist:** `"Error: The path {path} does not exist"`883884#### Directory handling885886Deletes the directory and all its contents recursively. The tool description tells Claude it cannot delete the `/memories` directory itself, so reject a `delete` whose path is the memory root.887888### rename889890Renames or moves a file or directory:891892```json893{894 "command": "rename",895 "old_path": "/memories/draft.txt",896 "new_path": "/memories/final.txt"897}898```899900#### Return values901902* **Success:** `"Successfully renamed {old_path} to {new_path}"`903904#### Error handling905906* **Source does not exist:** `"Error: The path {old_path} does not exist"`907* **Destination already exists:** Return an error (do not overwrite): `"Error: The destination {new_path} already exists"`908909#### Directory handling910911Renames the directory. The tool description tells Claude it cannot rename the `/memories` directory itself, so reject a `rename` whose `old_path` is the memory root.912913## Prompting guidance914915When the memory tool is present in your request's `tools`, the API automatically adds this instruction to the system prompt. You don't need to send it yourself:916917```text wrap918IMPORTANT: ALWAYS VIEW YOUR MEMORY DIRECTORY BEFORE DOING ANYTHING ELSE.919MEMORY PROTOCOL:9201. Use the `view` command of your `memory` tool to check for earlier progress.9212. ... (work on the task) ...922 - As you make progress, record status / progress / thoughts etc in your memory.923ASSUME INTERRUPTION: Your context window might be reset at any moment, so you risk losing any progress that is not recorded in your memory directory.924```925926Claude's tool description already tells it to keep the memory directory organized, so you don't need to repeat that instruction. If Claude still creates cluttered memory files, you can reinforce it in your prompt:927928```text wrap929Note: 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.930```931932You can also guide what Claude writes to memory. For example: "Only write down information relevant to \<topic> in your memory system."933934## Security considerations935936Your application executes every file operation Claude requests, so these safeguards are your responsibility:937938### Sensitive information939940Claude usually refuses to write sensitive information to memory files. For stronger guarantees, add validation that strips sensitive data before your handler writes the file.941942### File storage size943944Track memory file sizes and cap how large a file can grow. Consider capping how many characters the `view` command returns, and let Claude page through the rest with `view_range`.945946### Memory expiration947948Periodically delete memory files that haven't been accessed in a long time.949950### Path traversal protection951952<Warning>953 A malicious path such as `/memories/../../secrets.env` can reach files outside the `/memories` directory. Your implementation must validate every path in every command to prevent directory traversal attacks.954</Warning>955956Consider these safeguards:957958* Validate that all paths start with `/memories`959* Resolve paths to their canonical form and verify they remain within the memory directory960* Reject paths containing sequences such as `../`, `..\\`, or other traversal patterns961* Watch for URL-encoded traversal sequences (`%2e%2e%2f`)962* Use your language's built-in path security utilities (for example, Python's `pathlib.Path.resolve()` and `relative_to()`)963964## Error handling965966The memory tool uses similar error-handling patterns to the [text editor tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/text-editor-tool#handle-errors). Each command's error messages are listed under [Tool commands](https://platform.claude.com/docs/en/agents-and-tools/tool-use/memory-tool#tool-commands). To return an error to Claude, set `is_error` to `true` on the tool result and put the message in `content`:967968```json969{970 "type": "tool_result",971 "tool_use_id": "toolu_01C4D5E6F7G8H9I0J1K2L3M4",972 "content": "Error: The path /memories/notes.txt does not exist",973 "is_error": true974}975```976977## Context editing integration978979The memory tool pairs with context editing to manage long-running conversations. For details, see [Context editing](https://platform.claude.com/docs/en/build-with-claude/context-editing).980981## Using with compaction982983The memory tool can also be paired with [compaction](https://platform.claude.com/docs/en/build-with-claude/compaction), which summarizes older conversation context server-side. Context editing clears specific tool results on the client. Compaction automatically summarizes the whole conversation on the server when the conversation approaches the context window limit.984985For long-running agents, consider using both: compaction keeps the active context small without client-side bookkeeping, and memory preserves the information that must survive summarization.986987## Multisession software development pattern988989For software projects that span multiple agent sessions, set up memory files deliberately instead of writing them ad hoc as work progresses. The following pattern turns memory into a recovery mechanism: each new session resumes from the state the last one recorded.990991### How the pattern works9929931. **Initializer session:** The first session sets up the memory files before any substantive work begins. This includes a progress log (tracking what has been done and what comes next), a feature checklist (defining the scope of work), and a reference to any startup or initialization script the project needs.9949952. **Subsequent sessions:** Each new session opens by reading those memory files. This restores the project state without re-exploring the code base or retracing earlier decisions.9969973. **End-of-session update:** Before a session ends, it updates the progress log with what was completed and what remains. This ensures the next session has an accurate starting point.998999### Key principle10001001Work on one feature at a time. Mark a feature complete only after end-to-end verification confirms it works, not when the code is written. This keeps the progress log accurate from session to session.10021003<Tip>1004 For a detailed case study of this pattern in practice, including the initializer script, progress file structure, and git-based recovery, see [Effective harnesses for long-running agents](https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents).1005</Tip>10061007## Next steps10081009<CardGroup cols={2}>1010 <Card title="Bash tool" icon="terminal" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/bash-tool">1011 Execute shell commands in a persistent bash session.1012 </Card>10131014 <Card title="Context editing" icon="edit" href="https://platform.claude.com/docs/en/build-with-claude/context-editing">1015 Automatically manage conversation context as it grows with context editing.1016 </Card>10171018 <Card title="Compaction" icon="stack" href="https://platform.claude.com/docs/en/build-with-claude/compaction">1019 Server-side context compaction for managing long conversations that approach context window limits.1020 </Card>10211022 <Card title="Tool reference" icon="book" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-reference">1023 Directory of Anthropic-provided tools and reference for optional tool definition properties.1024 </Card>1025</CardGroup>1026