Expand description
CODE-REGISTERED tools — the embedder seam.
An embedder building its own binary on the agentd-core library can
register native Rust tools the agent calls alongside MCP tools:
agentd::tools::register(agentd::tools::CodeTool::new(
"shout",
"Uppercase the input text.",
serde_json::json!({"type": "object", "properties": {"text": {"type": "string"}},
"required": ["text"]}),
|args| {
let text = args.get("text").and_then(serde_json::Value::as_str).unwrap_or("");
Ok(serde_json::json!({ "text": text.to_uppercase() }))
},
))
.expect("unique tool name");Design constraints (binding):
- The registry is process-global and must be populated in
main, BEFORE the subagent dispatch. Subagents re-execcurrent_exe(); the child runs the embedder’smainagain, which re-registers the same tools — that is how a tool registered “by code” is visible in every process of the tree (the exact pattern the stock CLI uses for nothing, preserving its no-local-code posture: agentd-cli registers zero tools, so this registry is empty in every stock binary). - Dispatch priority is self-tools → code tools → MCP. A registered tool
cannot shadow agentd’s own orchestration primitives
(
SELF_CONTROL_TOOLS— registration refuses those names), and a remote MCP server cannot steal a code tool’s calls by publishing a colliding name (the code tool wins the catalogue slot and the dispatch). - Workflows address code tools as the reserved server name
code({"kind": "tool", "server": "code", "tool": "shout", …}); config validation refuses an--mcpserver namedcode. - Handlers are
Fn(&Value) -> Result<Value, String> + Send + Sync: they may be called from the agent loop, from workflowtoolnodes, and from parallel foreach/parallel lanes (threads of the same process) concurrently. Keep them reentrant; hold no lock across a call into agentd. - Trust: a code tool is the embedder’s own compiled code — it is
first-party by definition, like the binary itself. It sits OUTSIDE the
--mcp-tagstrifecta accounting; an embedder whose tool does egress or touches secrets owns that risk the way it owns the rest of its binary.
Structs§
- Code
Tool - One registered native tool: an MCP-shaped definition (name + description + input JSON Schema) plus the Rust handler.
Functions§
- call
- Call a registered code tool directly — the PUBLIC entry the runtime’s tool
executor (
registryroutecode) and an embedder’s dispatcher use.None= unregistered;Some(Ok(v))/Some(Err(reason))mirror the handler. The handler runs outside the registry lock. - count
- How many tools are registered (the capabilities manifest surfaces this).
- register
- Register a tool. Refuses (Err) an empty name, a duplicate, or a name that collides with agentd’s own self/control primitives — a code tool may shadow a remote MCP tool (first-party wins) but never the orchestration surface.
- unregister
- Remove a registered tool (dynamic embedders). Returns whether it existed.
Prefer registering once in
main— see the module doc’s re-exec rule.
Type Aliases§
- Code
Tool Fn - The handler signature: JSON arguments in, JSON result (or a refusal string)
out.
Errtakes the tool-error path (the model sees it as a failed call; a workflowtoolnode takes itserroredge).