Writes Python source code to tools/<name>.py and immediately reloads it into the system. The new tool becomes a permanent part of your capabilities — available in every future session.
name (string, required) — tool filename without .py, e.g. "task_manager"code (string, required) — full Python source code (see format below)Every tool file must define exactly these four things at module level, in this order:
name = "tool_name" # must match the filename
description = "When and why to use this tool. Be specific — this is what you read to decide whether to call it."
parameters = {
"type": "object",
"properties": {
"param1": {"type": "string", "description": "What this parameter is for"},
"param2": {"type": "integer", "description": "..."},
},
"required": ["param1"],
}
async def execute(params: dict) -> str:
value = params["param1"]
# your implementation here
return "result as a plain string"
Rules:
execute MUST be asyncexecute MUST return a plain str — not dict, not Noneexecute() or at the top of the file — both are fineIf the tool needs to store data between calls, use a JSON file inside the tools/ directory:
import json, os
DATA_FILE = os.path.join(os.path.dirname(__file__), "my_tool_data.json")
def _load():
if os.path.exists(DATA_FILE):
with open(DATA_FILE) as f:
return json.load(f)
return {}
def _save(data):
with open(DATA_FILE, "w") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
import json, os
name = "notes"
description = (
"Save and retrieve short text notes by key. "
"Use this to remember things across sessions: facts, preferences, reminders. "
"Actions: save (store a note), get (retrieve by key), list (show all keys)."
)
parameters = {
"type": "object",
"properties": {
"action": {"type": "string", "enum": ["save", "get", "list"]},
"key": {"type": "string", "description": "Note identifier"},
"value": {"type": "string", "description": "Note content (for save)"},
},
"required": ["action"],
}
_FILE = os.path.join(os.path.dirname(__file__), "notes_data.json")
async def execute(params: dict) -> str:
action = params["action"]
data = json.loads(open(_FILE).read()) if os.path.exists(_FILE) else {}
if action == "save":
key, value = params["key"], params["value"]
data[key] = value
open(_FILE, "w").write(json.dumps(data, ensure_ascii=False, indent=2))
return f"Saved: {key}"
if action == "get":
key = params["key"]
if key not in data:
raise KeyError(f"Note '{key}' not found. Use action=list to see all keys.")
return data[key]
if action == "list":
if not data:
return "No notes saved yet."
return "Saved notes: " + ", ".join(data.keys())
raise ValueError(f"Unknown action: {action}")
name, description, parameters, async def execute must all be present in the code_If the check fails, you get a clear error with the list of what's missing. If the file loads but has a Python error, you get the exact traceback.
The tool is registered and added to tools/enabled.json. It will be available starting from the next user message — not the current one.