Skip to main content

Factory agents

Factory agents are ready-made agents you pull straight into your project with one command, then deploy. Under the hood each is a Zavu Function that declares an agent with defineAgent and its skills with defineTool — so what you pull is real, editable code you own, not a black box. npx zavudev agents pull fermi scaffolds the agent, registers it, and leaves you a directory to npx zavudev deploy. Voice agents answer phone calls; text agents run on WhatsApp, SMS, and more.
You’ll need an active sender in your Zavu project. For voice, the sender also needs a phone number (purchase one) and the Voice Agents feature enabled for your team.

1. Install the CLI

2. Browse the catalog

3. Find your sender

No sender yet? Create one — a phone number gives you voice and SMS right away:
npx zavudev agents init does all of this in one guided command: it creates the sender (buying a number if you want), pulls a factory agent, and sets SENDER_ID — so you can skip straight to npx zavudev deploy.

Connect more channels (from the CLI)

Voice and SMS work as soon as the sender has a number. The rich channels each connect with one command:
The agent answers on whichever of its channels are connected to the sender.

4. Pull the agent

This scaffolds an editable index.ts:
--sender sets the SENDER_ID secret for you. If you leave it off, set it before deploying with npx zavudev fn secrets set SENDER_ID <senderId>.
The voice block is what makes this agent answer calls. It runs the LLM co-located in the voice network for the lowest latency, independent of the model used for text. Remove the voice block and redeploy to turn the agent back into a text-only agent.

5. Deploy

Your agent is live. For a voice agent, the sender’s number now answers calls with Fermi; for a text agent, every inbound message hands off to it.

6. Call it

Dial the sender’s phone number from your phone. Fermi greets you, qualifies the lead, and calls qualify_lead near the end of the conversation. Prefer to test outbound? Place a call from code:

7. Watch it run

8. Iterate

Edit index.ts — tweak the prompt, add a defineTool, change the greeting — and redeploy:
The summary shows only what changed. There’s no separate agent config to keep in sync: the code is the source of truth.

Common pitfalls

Confirm the sender has a phone number assigned and the Voice Agents feature is enabled for your team (voice endpoints return 403 otherwise). Then check the deploy printed Agents synced: + Fermi and that the voice block has enabled: true.
A field in your voice block is out of range (e.g. maxCallDurationMinutes above the cap) or misspelled. The deploy warns and ships the agent as text-only rather than failing. Fix the value and redeploy.
The LLM decides when to call a tool from its description. Rewrite each description as the answer to “when should the model call this?” — vague descriptions don’t trigger.

Next steps

defineAgent in depth

Providers, models, prompts, and the voice block.

defineTool in depth

Schemas, handlers, returning structured data.

Voice configuration

Greetings, languages, voicemail, and transfer.

Secrets

Store SENDER_ID, API keys, and other env vars.