Building agent workflows
`lem` works well for AI agents. This page covers why it fits tool use and how to wire it into Bash, Python, and MCP workflows.
What you'll learn
Why
lemis a good fit for agent tool-use.How to drive
lemnon-interactively in a sandbox.Two end-to-end recipes (Bash and Python) for proposing and signing transactions from an agent loop.
How to expose
lemto MCP-aware agents.
Why lem is agent-friendly
lem is agent-friendlyJSON-by-default output
Every command prints a single JSON document to stdout. Feed it straight into the next tool-call without parsing prose. Pass --pretty only when a human will read it.
Structured errors on the same channel
Failures print { "error": { "code", "message", "suggestion" } } to stdout and set a non-zero exit code. Agents can branch on error.code instead of regexing English.
Stable exit codes
0 success, 2 validation, 3 no signer paired, 4 env misconfig, and 1 everything else. See the exit codes table in Command reference.
Idempotent reads
safe info, safe balances, safe nonce, tx list, and tx show are safe to retry or replay arbitrarily.
Refusal semantics
tx sign refuses to double-sign, re-sign an executed tx, or sign past the threshold. Agents can rely on the CLI to reject obviously wrong actions instead of encoding those checks themselves.
Built-in discovery
lem --help, lem <command> --help, and lem <command> <subcommand> --help produce stable, parseable help. Many agent frameworks can derive a tool schema from this output.
Deterministic signers for CI
--salt + --index derives a stable test signer from a single secret. There is no need to plumb a mnemonic through your agent runtime.
Step-by-step
1. Pair a non-interactive signer
For agents that operate on testnets and CI, derive a deterministic signer from a salt held in your secret manager:
For agents that propose on mainnet, keep a human in the loop: the agent prepares the transaction, but a human approves on a Ledger device. See the security note at the bottom of this page.
2. Set up env (only if self-hosting endpoints)
If your agent runtime uses Ledger's hosted Transaction Service and RPCs, skip this step. The distributed binary already knows where to call.
If you point lem at your own endpoints, export the env vars from the Command reference before running commands, or place them in a file passed via --env.
3. Call lem from a tool-use loop
lem from a tool-use loopBuild the calling convention into your agent's tool schema. For each lem command, define an input schema (the flags) and let the agent unmarshal stdout as JSON. A minimal contract:
Run the command.
On exit code 0, parse stdout as JSON and return to the model.
On non-zero exit code, parse stdout as
{ error: { code, message, suggestion } }and return that. Many agents will then retry with a corrected call, for example by runninglem connectafter aCONFIG_ERROR.
Recipe: Bash agent harness
Propose a payment, wait for the second signature, and execute, all from one script. Useful as a reference for shaping the tool-call schemas the agent will use.
Every line is a JSON-in / JSON-out call that an LLM agent can substitute for jq plumbing.
Recipe: Python agent tool
A minimal Python wrapper that an LLM tool-use agent (LangChain, OpenAI tools, Anthropic tools, etc.) can register as a single tool with multiple subcommands.
For agent tool-use, expose call_lem as a single tool whose argument is the array of CLI args. The model can then form arbitrary lem invocations and recover gracefully from errors using the code and suggestion fields.
Exposing lem over MCP
lem over MCPThe Model Context Protocol (MCP) lets agents discover and invoke external tools. To expose lem to an MCP-aware host:
Write a thin MCP server (one tool per
lemsubcommand, or a single "runlem" tool that accepts an args array. Both work).Map each tool's input schema to the flags documented in Command reference.
Forward stdout JSON as the tool's success result. Forward the error object as the failure result.
Run the MCP server alongside your agent. The host (Claude Desktop, Cursor, etc.) takes care of routing tool-calls.
The minimal-effort version is the "one tool with an args array" approach in the Python recipe above, wrapped in your MCP framework of choice. The more polished version is one MCP tool per lem subcommand, with input schemas derived from the flag tables in Command reference.
Security
Never give an agent direct access to a mainnet mnemonic.
--seedis a footgun outside of testnets. For mainnet, the agent should propose transactions withlem tx proposeagainst a Safe whose owners are real Ledger devices. Execution and the on-chain signature stay with humans.Treat
--saltas a secret. Anyone with the salt + index can sign as that signer. Store it in your secret manager, not in source.Scope agent capabilities. Even on testnets, you can run agents under a signer that is only an owner of low-value Safes, so an agent gone rogue cannot drain anything important.
Audit the trail. Every proposal made by the CLI carries
origin: { app: "les-multisig-cli" }in the Transaction Service, so you can filter agent-originated transactions in the Ledger Multisig UI.
Next steps
Command reference
Last updated