Quickstart
You need Node.js 24, 25, or 26 and an AssemblyAI API key. One key covers listening, thinking, and speaking. Get one from the AssemblyAI dashboard.
1. Create a project
Section titled “1. Create a project”npm i -g @alexkroman1/aai-cliaai init my-agentcd my-agentaai init writes a starter project and installs its dependencies.
Here is what you get:
my-agent/ agent.ts # the definition system-prompt.md # what the model is told tools/ get_weather.ts # one tool; the filename is its name agent.test.ts # tests — `aai test` agent.eval.test.ts # behaviour checks — `aai eval`package.json, tsconfig.json, and .env come with them. None of the five
files names another: the prompt and the tool are found where they sit.
Want a different starting point? aai templates lists them, and
aai init my-agent --template pizza-ordering-agent picks one.
2. Talk to it
Section titled “2. Talk to it”aai devThat starts a local server and prints a URL. Open it, click the microphone, and ask about the weather somewhere. Leave it running for the next two steps — it reloads when you save.
3. Change what it says
Section titled “3. Change what it says”agent.ts is the definition. Change any of it:
import { agent } from "@alexkroman1/aai";
export default agent({ name: "Quickstart Assistant", description: "Looks up the current weather for any city", greeting: "Hi — I can look up the weather anywhere. Which city?", voice: "jane",});system-prompt.md is what the model is told. It is plain markdown, and nothing
imports it — the build finds it because it sits beside agent.ts:
You are a friendly assistant on a voice call. Keep replies to one or twosentences — a caller is listening, not reading.
Use the get_weather tool whenever someone asks what it is like somewhere.Save either one and the running aai dev picks it up.
4. Give it something to do
Section titled “4. Give it something to do”A tool is a file in tools/, and the filename is the name the model calls it
by. So you already have a get_weather. A tool can be this small:
import { tool } from "@alexkroman1/aai";import { z } from "zod";
export default tool({ description: "Get the current weather for a city.", inputSchema: z.object({ city: z.string().describe("City name, e.g. Denver") }), execute: async ({ city }) => { const res = await fetch(`https://wttr.in/${city}?format=3`); return { report: await res.text() }; },});Two things the model reads before it decides to call your tool: description,
and the .describe() on each input. Spend a sentence on each.
Now copy the file to tools/get_forecast.ts and change the description and the
body. The model can call that one too. There is nothing to register, no list to
join, and no import to add.
Tools covers the rest — timeouts, failures, and calling your own APIs.
5. Ship it
Section titled “5. Ship it”aai login # onceaai publishaai publish uploads your source, copies the secrets from .env, builds and
deploys it, and prints a URL you can share. One command, including the first
time.
See Publish for the details, and Phone calls for putting it on a phone number.
- How it works — why the project is shaped this way
- Tools — talking to your own APIs
- Remembering things — state that survives the call