Skip to main content
A custom tool is how an agent reaches systems only you can touch — your ticket tracker, your database, your deploy pipeline. The division of labor is clean: you describe the tool, the model decides when to call it, and your code does the work. Omnara sits in the middle holding the call durably until you answer it. Because the call is a durable event, your worker can crash, redeploy, or take minutes to respond — the agent simply waits, and nothing is lost.

Declare the tool

In the agent config, a custom tool is a name, a description, and a JSON Schema for its input. Write the description as clear instructions: explain when to use the tool, what it does, and any important limits.
Custom tools default to always_allow; set permission.mode: always_ask to put a human between the model and your system (Tools & permissions).

Find calls waiting for you

GET /tool-calls lists an agent’s tool calls, filterable by state and type. Your worker polls for ready custom calls:
ready means the permission check has passed and the call is waiting for your result. A custom call using always_ask remains in awaiting_permission until someone responds to its interaction. After you submit a result, it moves to completed.
To avoid continuous polling, connect to the agent’s event stream, then query GET /tool-calls?state=ready&type=custom for already-ready calls and watch for future tool_call_update frames whose state is ready. Repeat the query after reconnecting because lifecycle updates are not replayed.

Submit the result

Post the outcome with content blocks — text, inline media, or structured data:
201 returns both the completed call and the durable tool_result event now in the agent’s timeline:
The agent wakes and continues its turn with your result in context. If your system failed, submit outcome: "failed" with a text block explaining why — a failed tool call is information the model can act on, not an error you should swallow. The first result wins. Only ready custom calls accept results; a second submission for the same call, or a result for a built-in or MCP call, returns 409:
That makes result submission naturally safe to retry from multiple workers — losers of the race get a clean 409, not a corrupted timeline.
Full schema and playground: List tool calls · Submit a result.