Skip to content
API > API reference

Tool definitions

How client-executed tools are declared and round-tripped.


The relay does not run tools. It forwards the tools array from your agent streaming request to the model and streams back tool_calls; your client executes them locally and posts the results on the next leg. The tools you send define what the agent can do — the relay adds nothing. The Mel app sends the definitions on this page, gated by the request's tool_role; a third-party client can reuse them verbatim.

ToolDef shape

{
  "name": "read_file",
  "description": "Read a file from the workspace",
  "parameters": { "type": "object", "required": ["path"],
    "properties": { "path": { "type": "string" } } }
}

parameters is a JSON Schema object describing the arguments.

The tool-call round-trip

  1. You POST a leg with messages and tools.
  2. The relay streams a tool_calls event: {"calls": [{"id", "name", "arguments"}], "usage?": ...}arguments is a JSON-encoded string.
  3. Your client executes each call locally (read the file, run the command, ...).
  4. You append the assistant message carrying the tool_calls, then one role:"tool" message per call whose tool_call_id equals the call's id and whose content is the result text.
  5. You POST the next leg with the extended message list. Repeat until the relay emits done instead of tool_calls.

The tool_call_id pairing is what tells the model which result answers which call — never omit it, and never reorder ids across calls. Each leg is one paid provider call and one quota unit.

Base tools (every role)

{"name":"read_file",  "parameters":{"type":"object","required":["path"],
  "properties":{"path":{"type":"string"},
    "offset":{"type":"integer"},
    "limit":{"type":"integer"}}}}
{"name":"list_dir",   "parameters":{"type":"object",
  "properties":{"path":{"type":"string"}}}}
{"name":"grep",       "parameters":{"type":"object","required":["pattern"],
  "properties":{"pattern":{"type":"string"}}}}
{"name":"find_files", "parameters":{"type":"object","required":["pattern"],
  "properties":{"pattern":{"type":"string"}}}}
{"name":"write_file", "parameters":{"type":"object","required":["path","content"],
  "properties":{"path":{"type":"string"},"content":{"type":"string"}}}}
{"name":"edit_file",  "parameters":{"type":"object","required":["path","old_string","new_string"],
  "properties":{"path":{"type":"string"},"old_string":{"type":"string"},
    "new_string":{"type":"string"},"replace_all":{"type":"boolean"}}}}
{"name":"run_command","parameters":{"type":"object","required":["command"],
  "properties":{"command":{"type":"string"}}}}
{"name":"web_search", "parameters":{"type":"object","required":["query"],
  "properties":{"query":{"type":"string"}}}}
{"name":"write_plan", "parameters":{"type":"object","required":["title","markdown"],
  "properties":{"title":{"type":"string"},"markdown":{"type":"string"}}}}
{"name":"create_pdf", "parameters":{"type":"object","required":["content","output_path"],
  "properties":{"content":{"type":"string"},"output_path":{"type":"string"},"title":{"type":"string"}}}}

Notes: read_file truncated reads report the offset to resume from; grep and find_files are project-wide and take no path/directory argument; edit_file requires an exact, unique old_string match; run_command results come back as exit_code=N followed by combined stdout+stderr; create_pdf renders via the best local engine (Chrome/Edge/Chromium, then wkhtmltopdf/weasyprint) with a built-in renderer as the guaranteed floor, and reports which one produced the file.

Shared project memory tools

Workers and orchestrators also get remember/recall. The project is derived automatically from the working directory server-side — the model supplies no project or query argument (do not add one):

{"name":"remember","parameters":{"type":"object","required":["note"],
  "properties":{"note":{"type":"string"}}}}
{"name":"recall",  "parameters":{"type":"object","properties":{}}}

These back onto the project memory store.

Orchestration tools

A lead agent driving parallel workers uses open_pane (a CLI agent such as claude or codex, or a shell command, in a pane) and spawn_agent (a Mel agent worker):

{"name":"open_pane",  "parameters":{"type":"object","required":["layout"],
  "properties":{"layout":{"type":"string","enum":["right","down","tab"]},
    "command":{"type":"string"}}}}
{"name":"spawn_agent","parameters":{"type":"object","required":["layout","task"],
  "properties":{"layout":{"type":"string","enum":["right","down","tab"]},
    "model":{"type":"string"},
    "task":{"type":"string"}}}}
{"name":"send_keys", "parameters":{"type":"object","required":["pane","text"],
  "properties":{"pane":{"type":"integer"},"text":{"type":"string"}}}}
{"name":"send_agent","parameters":{"type":"object","required":["pane","text"],
  "properties":{"pane":{"type":"integer"},"text":{"type":"string"}}}}
{"name":"read_pane", "parameters":{"type":"object","required":["pane"],
  "properties":{"pane":{"type":"integer"}}}}
{"name":"read_agent","parameters":{"type":"object","required":["pane"],
  "properties":{"pane":{"type":"integer"}}}}
{"name":"list_panes","parameters":{"type":"object","properties":{}}}

The layout enum is load-bearing. On open_pane / spawn_agent, layout must be constrained to enum: ["right", "down", "tab"]. Without the enum, models emit invalid values and pane placement breaks. Constrain it in the schema; the Mel app additionally normalizes any unknown value to "tab" as a safety net.

Role gating

The Mel app sends the set matching the request's tool_role:

tool_roleTools sent
null (normal)base tools only
workerbase + recall, remember
orchestrator (CLI)base + open_pane, send_keys, read_pane, list_panes, recall, remember
orchestrator (agent)base minus write_file/edit_file (the lead delegates, doesn't author) + spawn_agent, send_agent, read_agent, list_panes, recall, remember