Skip to content

npx zavudev agents

Create, test, connect and inspect agents from the terminal

View .md

An agent is a standalone object with its own id. It can answer on several senders, and it can exist with none while you build it.

terminal
npx zavudev agents list
Code
id name kind enabled senders model qd75detym58c6has4sfrye3vws8b6ygt Atlas voice yes 1 openai/gpt-5.6-luna qd7ck28evcskdc3xx4wzevtmeh8b6bcm Pizza Desk text no 0 gpt-4o-mini

kind reflects what the agent actually is — an agent named for voice whose voice block is missing reads as text, which is usually the thing you wanted to know.

Test an agent

The command you will use most. It runs the real prompt, model and knowledge base and prints what the agent would reply. Nothing is delivered and no execution is logged. The run is billed like a live reply: on the zavu provider its tokens are charged to your balance (the cost is in the output), on your own provider key it costs your provider.

terminal
npx zavudev agents test --agent <agentId> --message "where is order ORD-001?"
Code
Your order ORD-001 shipped on Tuesday and arrives Thursday. 1418→40 tokens · 5249ms · 1 knowledge chunk(s)
Flag
--agent <agentId>The agent. Get it from agents list.
--sender <senderId>Address it by sender instead (resolves to that sender's one agent)
--message <text>What to say
--turn <text...>Prior turns, alternating user/assistant, oldest first. Repeatable.
--no-knowledgeSkip retrieval, to isolate prompt behaviour from the knowledge base
--execute-toolsRun the tools the agent calls, for real, and reply with their results. Without it the run stops at the tool the agent chose.
--jsonRaw response

Multi-turn:

terminal
npx zavudev agents test --agent <agentId> \ --turn "I need to change my booking" --turn "Sure — which one?" \ --message "the one on Friday"

Start from a factory agent

terminal
npx zavudev agents catalog # what is available npx zavudev agents pull kepler --dir kepler # scaffold it locally cd kepler && npm install npx zavudev deploy

pull writes a real TypeScript project: index.ts with the agent and its skills, a tsconfig.json, and @zavudev/functions as a dependency so your editor and tsc resolve it. Edit it freely — the code is the source of truth and npx zavudev deploy reconciles whatever it declares.

Flag
--dir <path>Where to scaffold. Defaults to ./<id>.
--sender <senderId>Sets the SENDER_ID secret for you
--calendar <provider>For booking agents: webhook (default) or calcom

Booking agents

Kepler, Hopper and Fermi book meetings. By default they scaffold against a generic webhook — an HTTPS endpoint you build and host that returns open slots and books them. Until it exists the agent cannot book, and says so rather than inventing a time.

Point it at Cal.com instead and it works with an API key:

terminal
npx zavudev agents pull kepler --calendar calcom

pull then lists every secret the agent needs, with a hint for each:

Code
npx zavudev fn secrets set CALCOM_API_KEY <value> ↳ Cal.com API key (Settings → Developer → API keys). npx zavudev fn secrets set CALCOM_EVENT_TYPE_ID <value> ↳ Numeric id of the Cal.com event type to book.

The Cal.com client only reports a booking when Cal.com accepted it. An event type that requires confirmation comes back pending, and telling a caller they are booked at that point is the worst outcome on that line.

npx zavudev agents init walks the same path interactively: pick or create a sender, pick an agent, get ready to deploy.

Create one from scratch

terminal
npx zavudev agents create --sender <senderId> \ --name "Order desk" --provider zavu --model openai/gpt-5.6-luna \ --channels whatsapp,sms \ --prompt "You are the order desk for Tony's Pizza. Answer in one or two sentences."

Use --prompt-file for anything longer than a line — terminal paste mangles newlines. --data / --file take a full JSON body for advanced fields.

Connect senders

A sender is the identity a conversation happens on. An agent can answer on several; a sender answers with at most one agent.

terminal
npx zavudev agents senders connect --agent <agentId> --sender <senderId> npx zavudev agents senders disconnect --agent <agentId> --sender <senderId>

Connecting a sender that is already in use is rejected, naming the agent that holds it — otherwise you would have an agent that looks connected and never receives a message.

Tools

terminal
npx zavudev agents tools list --sender <senderId> npx zavudev agents tools test --sender <senderId> <toolId> --params '{"orderId":"ORD-1"}'

Tools declared in code with defineTool are managed by their function: they appear here read-only and are changed by redeploying.

To run a handler in isolation, without deploying:

terminal
npx zavudev fn invoke --tool get_order --args '{"orderId":"ORD-1"}'

Knowledge bases

terminal
npx zavudev agents knowledge-bases create --sender <senderId> --name "Product docs" npx zavudev agents knowledge-bases documents add --sender <senderId> --kb <kbId> \ --title "Pricing" --content-file ./pricing.md npx zavudev agents knowledge-bases documents list --sender <senderId> --kb <kbId>

Processing takes a few seconds. Verify retrieval actually fires with agents test — it reports how many chunks the answer used.

Flows

terminal
npx zavudev agents flows list --sender <senderId> npx zavudev agents flows create --sender <senderId> --file flow.json

A flow is a deterministic sequence with a trigger. Steps take a config object; a tool step names its tool through config.toolName, or the older config.toolId. Either field is accepted, and either one may hold the tool's name or its id. A flow naming a tool the agent does not have is rejected at creation, listing the ones it does have.

Flows are not evaluated by agents test — they run on a real message, and agents test says so when the agent has any.

Inspect what happened

terminal
npx zavudev agents stats --sender <senderId> npx zavudev agents executions list --sender <senderId> npx zavudev agents executions get --sender <senderId> <executionId> npx zavudev agents reset-thread --sender <senderId>

executions get carries errorMessage and responseText — the place to look when a live reply went wrong. reset-thread closes the conversation and any flow session for one contact so the next inbound starts fresh.

Dry runs do not appear in stats or executions; they are not executions.

Calls

terminal
npx zavudev calls list --status completed npx zavudev calls get <callId> # includes the transcript, turn by turn npx zavudev calls hangup <callId>

calls get prints the conversation including tool calls. It is the only record of what the agent actually said, and the first place to look after a call went wrong.

terminal
npx zavudev calls create --to +14155551234