Client-side tool guidelines
How to implement tools that run locally in Letta Code.
Contract
- Function signature:
(args, opts?) => Promise<{ toolReturn: string; status: "success" | "error"; stdout?: string[]; stderr?: string[] }> - Optional
opts.signal?: AbortSignal. If you spawn a subprocess, wire this signal to it so Esc/abort can kill it cleanly. If you’re pure in-process, you can ignore it.
Subprocess tools (e.g., Bash)
- Pass the provided
AbortSignaltoexec/spawnso abort kills the child. Normalize abort errors totoolReturn: "User interrupted tool execution", status: "error". - Avoid running multiple subprocesses unless you also expose a cancel hook; we execute tools serially to avoid races.
In-process tools (read/write/edit)
- You can ignore the signal, but still return a clear
toolReturnandstatus. - Be deterministic and side-effect aware; the runner keeps tools serial to avoid file races.
Errors
- Return a concise error message in
toolReturnand setstatus: "error". - Don’t
console.errorfrom tools; the UI surfaces the returned message.