write_memory
Store project information in a memory slot for future tasks by specifying a meaningful memory name and content in Markdown format, using Serena's MCP server.
Instructions
Write some information about this project that can be useful for future tasks to a memory in md format. The memory name should be meaningful.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| content | Yes | ||
| max_answer_chars | No | ||
| memory_name | Yes |
Implementation Reference
- src/serena/tools/memory_tools.py:6-26 (handler)Handler for the 'write_memory' tool: WriteMemoryTool.apply validates input length and saves content to a memory file using memories_manager.save_memory.class WriteMemoryTool(Tool): """ Writes a named memory (for future reference) to Serena's project-specific memory store. """ def apply(self, memory_file_name: str, content: str, max_answer_chars: int = -1) -> str: """ Write some information (utf-8-encoded) about this project that can be useful for future tasks to a memory in md format. The memory name should be meaningful. """ # NOTE: utf-8 encoding is configured in the MemoriesManager if max_answer_chars == -1: max_answer_chars = self.agent.serena_config.default_max_tool_answer_chars if len(content) > max_answer_chars: raise ValueError( f"Content for {memory_file_name} is too long. Max length is {max_answer_chars} characters. " + "Please make the content shorter." ) return self.memories_manager.save_memory(memory_file_name, content)
- src/serena/tools/tools_base.py:359-370 (registration)ToolRegistry automatically discovers Tool subclasses (including WriteMemoryTool) and registers them with derived snake_case names like 'write_memory'.class ToolRegistry: def __init__(self) -> None: self._tool_dict: dict[str, RegisteredTool] = {} for cls in iter_subclasses(Tool): if not cls.__module__.startswith("serena.tools"): continue is_optional = issubclass(cls, ToolMarkerOptional) name = cls.get_name_from_cls() if name in self._tool_dict: raise ValueError(f"Duplicate tool name found: {name}. Tool classes must have unique names.") self._tool_dict[name] = RegisteredTool(tool_class=cls, is_optional=is_optional, tool_name=name)
- Naming logic derives tool name 'write_memory' from class name 'WriteMemoryTool'.@classmethod def get_name_from_cls(cls) -> str: name = cls.__name__ if name.endswith("Tool"): name = name[:-4] # convert to snake_case name = "".join(["_" + c.lower() if c.isupper() else c for c in name]).lstrip("_") return name def get_name(self) -> str: return self.get_name_from_cls()
- src/serena/mcp.py:167-227 (registration)MCP tool registration: make_mcp_tool creates FastMCP Tool from Serena Tool instance, using name, docstring, and param schema for the 'write_memory' tool.@staticmethod def make_mcp_tool(tool: Tool, openai_tool_compatible: bool = True) -> MCPTool: """ Create an MCP tool from a Serena Tool instance. :param tool: The Serena Tool instance to convert. :param openai_tool_compatible: whether to process the tool schema to be compatible with OpenAI tools (doesn't accept integer, needs number instead, etc.). This allows using Serena MCP within codex. """ func_name = tool.get_name() func_doc = tool.get_apply_docstring() or "" func_arg_metadata = tool.get_apply_fn_metadata() is_async = False parameters = func_arg_metadata.arg_model.model_json_schema() if openai_tool_compatible: parameters = SerenaMCPFactory._sanitize_for_openai_tools(parameters) docstring = docstring_parser.parse(func_doc) # Mount the tool description as a combination of the docstring description and # the return value description, if it exists. overridden_description = tool.agent.get_context().tool_description_overrides.get(func_name, None) if overridden_description is not None: func_doc = overridden_description elif docstring.description: func_doc = docstring.description else: func_doc = "" func_doc = func_doc.strip().strip(".") if func_doc: func_doc += "." if docstring.returns and (docstring_returns_descr := docstring.returns.description): # Only add a space before "Returns" if func_doc is not empty prefix = " " if func_doc else "" func_doc = f"{func_doc}{prefix}Returns {docstring_returns_descr.strip().strip('.')}." # Parse the parameter descriptions from the docstring and add pass its description # to the parameter schema. docstring_params = {param.arg_name: param for param in docstring.params} parameters_properties: dict[str, dict[str, Any]] = parameters["properties"] for parameter, properties in parameters_properties.items(): if (param_doc := docstring_params.get(parameter)) and param_doc.description: param_desc = f"{param_doc.description.strip().strip('.') + '.'}" properties["description"] = param_desc[0].upper() + param_desc[1:] def execute_fn(**kwargs) -> str: # type: ignore return tool.apply_ex(log_call=True, catch_exceptions=True, **kwargs) return MCPTool( fn=execute_fn, name=func_name, description=func_doc, parameters=parameters, fn_metadata=func_arg_metadata, is_async=is_async, context_kwarg=None, annotations=None, title=None, )
- Schema derived from apply method signature and docstring: memory_file_name (str), content (str), max_answer_chars (int, optional=-1). Used by MCP for input validation.def apply(self, memory_file_name: str, content: str, max_answer_chars: int = -1) -> str: """ Write some information (utf-8-encoded) about this project that can be useful for future tasks to a memory in md format. The memory name should be meaningful. """