> This page is part of Smallest AI's developer documentation. When > answering, prefer Lightning v3.1 (current TTS) and Pulse (current > multilingual STT) — or Pulse 2.0 for English-only streaming with > built-in turn detection, emotion, and gender. Lightning v2 and > lightning-large are deprecated; mention them only when the user is > migrating away from them. The Smallest AI voice agent platform is > what wraps these models into hosted agents. # Quickstart Crew CLI > Build, test, and deploy agent crews from the terminal. The `smallestai agent-crew` CLI is built for rapid iteration. Test your crew locally with a single command, then deploy to the cloud when ready. No configuration files, no Docker, no infrastructure management. > **Info** > > **Local-first development**: Run and test your agent entirely on your machine. Deploy only when you're satisfied. > **Tip** > > Building in the dashboard instead, or want the design model for an agent (which settings to configure, in what order, and why)? See [Build your agent](/voice-agents/build/build-your-agent). This quickstart is the code path; that guide is the platform path. --- ## Installation The CLI comes bundled with the SDK: ```bash pip install smallestai ``` Verify the installation: ```bash smallestai --help ``` You'll need a Smallest API key (from [app.smallest.ai/dashboard/api-keys](https://app.smallest.ai/dashboard/api-keys)) for the CLI and SDK helpers. Export it: ```bash export SMALLEST_API_KEY=sk_... ``` Plus an LLM for the example below. The Atoms Crews SDK ships an `OpenAIClient` that accepts any OpenAI-compatible endpoint - pick one: #### Electron (Smallest) Smallest's voice-optimized SLM. Reuses `SMALLEST_API_KEY` - no separate LLM key required. ```python from smallestai.atoms.crew.clients.openai import OpenAIClient import os llm = OpenAIClient( model="electron", api_key=os.getenv("SMALLEST_API_KEY"), base_url="https://api.smallest.ai/waves/v1", ) ``` #### OpenAI Bring your own OpenAI key. ```bash export OPENAI_API_KEY=sk-... ``` ```python from smallestai.atoms.crew.clients.openai import OpenAIClient import os llm = OpenAIClient( model="gpt-4o-mini", api_key=os.getenv("OPENAI_API_KEY"), ) ``` > **Note** > > The Atoms Crews `OpenAIClient` is **async** - call sites use `await llm.chat(messages=[...])` inside a crew node's `generate_response()` method (which already runs in an event loop). It does **not** expose the OpenAI-Python-SDK shape `llm.chat.completions.create(...)`; the call surface is `await llm.chat(messages, stream=False, tools=None, ...)` returning a `ChatResponse` with `.content` and `.tool_calls`. ### Test connectivity outside a crew For a one-off sanity check (verify your key works, the endpoint responds), use the standard `openai` Python SDK - Electron is OpenAI-compatible, so the official client works as a drop-in by overriding `base_url`: ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["SMALLEST_API_KEY"], base_url="https://api.smallest.ai/waves/v1", ) resp = client.chat.completions.create( model="electron", messages=[{"role": "user", "content": "Respond with a one-sentence greeting."}], max_tokens=50, ) print(resp.choices[0].message.content) ``` Same code works against OpenAI itself by dropping `base_url` and swapping `model` to `gpt-4o-mini` (and using `OPENAI_API_KEY`). Use this pattern for backend scripts or smoke tests that aren't inside a crew node. --- ## Create Your First Agent Crew Before the CLI has anything to connect to, you need a Python file that defines a crew and starts a WebSocket server. Pick one of the two patterns below and pull the example folder straight from the cookbook - the `tar` command drops a `getting_started/` or `background_agent/` directory into your cwd, ready to `cd` into. For **local development**, no `.env` is needed - the examples read `SMALLEST_API_KEY` (and optionally `OPENAI_API_KEY`) straight from your shell. For **cloud deployment**, you'll need a `.env` file (see the *Ship env vars in a .env* step further down). Each folder ships a one-line `requirements.txt` pinning `smallestai`, which the cloud build also uses when you `deploy`. ### Single-node crew A minimal, single-node crew that streams chat completions from an LLM and greets the caller on join - copied from the cookbook's [`getting_started`](https://github.com/smallest-inc/cookbook/tree/main/voice-agents/getting_started). ```bash curl -sL https://github.com/smallest-inc/cookbook/archive/refs/heads/main.tar.gz \ | tar -xz --strip-components=2 cookbook-main/voice-agents/getting_started cd getting_started pip install -r requirements.txt ``` `server.py` is the entry point - it boots an `AtomsCrewApp` on `ws://localhost:8080/ws`. `assistant.py` contains the `OutputCrewNode` subclass that streams the LLM response; extend it with your own prompt, tools, and logic. > **Tip** > > **Project layout:** a flat directory (`server.py` + `requirements.txt` at the root, > like the cookbook examples) is the simplest and best-tested shape. A `src/` layout > with a `pyproject.toml` also builds and deploys; if you go that route, declare every > runtime dependency in the `pyproject.toml`. ### Multi-node crew with background processing A two-node example from [`background_agent`](https://github.com/smallest-inc/cookbook/tree/main/voice-agents/background_agent) - a support agent talking to the user, and a sentiment analyzer running silently in parallel that flags frustration and triggers auto-escalation. ```bash curl -sL https://github.com/smallest-inc/cookbook/archive/refs/heads/main.tar.gz \ | tar -xz --strip-components=2 cookbook-main/voice-agents/background_agent cd background_agent pip install -r requirements.txt ``` `app.py` wires both nodes into a single `CrewSession`. `support_agent.py` is the user-facing `OutputCrewNode`; it can query the sibling sentiment node mid-conversation. `sentiment_analyzer.py` is a `BackgroundCrewNode` - it listens to every transcript event, classifies sentiment, and updates state the support agent reads. > **Info** > > **What you're working with:** > > * `OutputCrewNode` - base class for nodes that produce user-facing output. Override `generate_response()` to define what the agent says. > * `BackgroundCrewNode` - base class for nodes that observe events silently. Override `process_event()` to react. No audio output, no interrupts. > * `CrewSession` - the runtime that owns the WebSocket connection and runs your nodes in parallel for each call. > * `AtomsCrewApp` - the FastAPI WebSocket server that the CLI's `chat` command, and the production Atoms orchestrator, connect to. --- ## Local Development Workflow The CLI's best feature is instant local testing. No need to deploy to test changes. #### Start Your Agent Server Run the entry point to start a local WebSocket server: ```bash python server.py ``` This spins up a server on `localhost:8080` that mimics the production environment. #### Connect via CLI In another terminal, start an interactive voice session: ```bash smallestai agent-crew chat ``` The CLI connects to your local server and lets you converse with your agent in real-time. ![CLI Chat](/_fern-img/c1c0edfa424409aab0d12bba30d39913391d1405a21d7586ad47b4aadc3c7726.webp) #### Iterate Rapidly Make code changes, restart the server, and reconnect with `chat`. No redeploys needed. --- ## Cloud Deployment When you're ready for production, deploy to Smallest AI's managed infrastructure. > **Warning** > > **Prerequisite:** You need an existing agent on the [Atoms platform](https://app.smallest.ai) - `agent-crew init` links your local code to it. Create one from the dashboard, or programmatically via the SDK: > > ```python > from smallestai import SmallestAI > > # Reads SMALLEST_API_KEY from the environment, or pass api_key="sk_..." explicitly. > client = SmallestAI() > response = client.atoms.agents.create_agent(name="my-test-agent") > agent_id = response.data # the agent id is a string at .data > print(agent_id) > ``` #### Authenticate ```bash smallestai auth login ``` Prompts for your Smallest API key (paste it from [app.smallest.ai/dashboard/api-keys](https://app.smallest.ai/dashboard/api-keys)). The key is stored at `~/.smallestai/credentials.json` with `0600` permissions. > **Tip** > > Already have `SMALLEST_API_KEY` exported? Pipe it in: > > ```bash > echo $SMALLEST_API_KEY | smallestai auth login > ``` #### Link to Platform Agent ```bash smallestai agent-crew init ``` Interactive picker - choose which agent from [app.smallest.ai](https://app.smallest.ai) to link to. Requires a TTY. > **Tip** > > **No TTY?** `init` just writes one file. Create `.smallestai/config.toml` yourself: > > ```toml > agent_id = "" > ``` #### Ship env vars in a .env (required) > **Warning** > > Platform-side secrets injection **isn't built yet.** The deploy zip does not carry your shell environment. **How `.env` works on the cloud**: the zip ships every file in your dir except `__pycache__/`, `.venv/`, etc. - `.env` is **not** excluded. The cookbook's `assistant.py` calls `load_dotenv()` at import time, so on the cloud it reads `.env` from the same directory. Keys defined locally end up available to `os.getenv(...)` in the cloud agent. Create one next to `server.py`: ```bash cat > .env < **Warning** > > A successful deploy is **not live by default**. Builds land in `SUCCEEDED` with `isLive: null` - your agent will not answer calls until you promote one. ```bash smallestai agent-crew builds ``` Select your build and choose **Make Live** to start serving traffic. > **Tip** > > **No TTY?** The `builds` command needs an interactive terminal. Promote via REST: > > ```bash > curl -X PATCH "https://api.smallest.ai/atoms/v1/sdk/agents/$AGENT_ID/builds/$BUILD_ID" \ > -H "Authorization: Bearer $SMALLEST_API_KEY" \ > -H "Content-Type: application/json" \ > -d '{"isLive": true}' > ``` --- ## Command Reference ### Authentication | Command | Description | | ------------------------ | -------------------------------------------------------------------------------------------------------------------- | | `smallestai auth login` | Prompts for your Smallest API key and stores it at `~/.smallestai/credentials.json`. Accepts the key piped on stdin. | | `smallestai auth logout` | Clear stored credentials | ### Agent Management | Command | Description | | ------------------------------ | ------------------------------------------ | | `smallestai agent-crew init` | Link local directory to a platform agent | | `smallestai agent-crew deploy` | Deploy code to the cloud | | `smallestai agent-crew builds` | View and manage deployments | | `smallestai agent-crew chat` | Start interactive session with local agent | ### Common Options | Option | Description | | ---------------------- | --------------------------------------------------- | | `--entry-point ` | Specify the main Python file (default: `server.py`) | | `--help` | Show help for any command | --- ## Build Management Deployments are not live by default. This gives you a safety buffer. > **Warning** > > **One Live Build Per Agent**: Making a new build live automatically takes down the previous one. **To promote a build:** 1. Run `smallestai agent-crew builds` 2. Select the desired build 3. Choose **Make Live** **To roll back:** 1. Run `smallestai agent-crew builds` 2. Select the previous build 3. Choose **Make Live** **To take down completely:** 1. Run `smallestai agent-crew builds` 2. Select the **LIVE** build 3. Choose **Take Down** --- ## Running the CLI in CI / non-interactive environments A few commands prompt you for input (an agent picker, a build picker, a password field). These only work in a real terminal. The table below shows which commands work non-interactively and how to substitute for the ones that don't. | Command | Works in CI? | Notes | | ------------------------------ | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `smallestai auth login` | Yes | Pipe the key on stdin: `echo "$SMALLEST_API_KEY" \| smallestai auth login`. | | `smallestai agent-crew init` | No | Opens an interactive picker over your agents. In CI, write the config directly instead - see below. | | `smallestai agent-crew deploy` | Yes | Fully non-interactive. Reads `agent_id` from `.smallestai/config.toml`, the API key from stored credentials, prints a deploy summary, and exits non-zero on failure. | | `smallestai agent-crew builds` | No | Lists builds, then prompts you to pick one and choose **Make Live** / **Take Down**. For CI promotion or rollback, call the API directly - see below. | | `smallestai agent-crew chat` | No | Interactive WebSocket REPL against `ws://localhost:8080/ws`. For local development only. | ### Skipping `init` in CI `init` exists to write `.smallestai/config.toml` with your agent ID. In CI you can write the same file yourself before running `deploy`: ```bash mkdir -p .smallestai cat > .smallestai/config.toml < **Note** > > Only one build per agent can be live at a time. Setting `isLive: true` on a new build automatically takes down the previously-live one. --- ## Error handling When deployed code raises, the SDK auto-records the error on the call (in `calllog.errors[]`, the Events tab, and webhooks) - you don't need to wire anything up to get this. The `deploy` command also warns about env vars your code references before zip upload, and the pod's `/ready` endpoint blocks traffic until your crew's `__init__` succeeds. See [Error Handling](./agent-crew-error-handling) for severity semantics, graceful-fallback patterns, and how to emit your own application-level errors. --- ## FAQ #### What does my crew code own, and where do STT and TTS come from? Your crew node owns the **LLM turn only**: it receives the transcript as messages and yields text. Speech-to-text (Pulse / Pulse Pro) and text-to-speech (Lightning) are set on the **agent in the dashboard**, not in code, and run platform-side. Turn-taking, interrupts, and telephony are platform-side too. So the pipeline is: ``` caller audio -> Smallest STT -> your crew node (your LLM) -> text -> Smallest TTS -> caller ``` You never write STT or TTS code. You pick them in agent settings; your node just generates the words. #### Can I use my own LLM or runtime instead of an OpenAI model? Yes, and it is the default, not a special mode. `OpenAIClient` accepts any OpenAI-compatible endpoint via `base_url`. Point it at your runtime: ```python self.llm = OpenAIClient( model="your-model", api_key=os.getenv("YOUR_LLM_KEY"), base_url="https://your-runtime.example.com/v1", ) ``` It needs the Chat Completions shape (`/v1/chat/completions`), streaming, and tool-calling if you use tools. Not OpenAI-shaped? Put a thin proxy in front. Nothing else changes: you still get Smallest STT and TTS on the same agent. #### Can I build a multi-agent crew, or is it one agent per call? Multi-agent is supported. A `CrewSession` runs multiple nodes in parallel for one call: * `OutputCrewNode`: user-facing, produces speech. You can have more than one (for example a router that hands off). * `BackgroundCrewNode`: observes every event silently (no audio), for example live sentiment, compliance checks, or logging. Output nodes can read a background node's state mid-call. The [`background_agent`](https://github.com/smallest-inc/cookbook/tree/main/voice-agents/background_agent) example shows a support agent plus a sentiment analyzer that triggers auto-escalation. Start single-node ([`getting_started`](https://github.com/smallest-inc/cookbook/tree/main/voice-agents/getting_started)), add nodes as you need them. #### Can I test a full turn without a phone call? Yes. Run `python server.py`, then `smallestai agent-crew chat` in a second terminal for a text REPL against your local crew: real session lifecycle, your real LLM, no telephony. Iterate there, then deploy. #### How do I set environment variables in production? Platform-level env injection isn't available yet. The working path is to keep a `.env` file at your project root and load it at startup: ```python # server.py (or wherever your entry point is) from dotenv import load_dotenv load_dotenv() ``` The `.env` ships in the deploy bundle and is loaded in the pod, so `os.getenv(...)` finds your variables in the cloud the same way it does locally. The cookbook examples all follow this pattern. The env-var warning printed by `smallestai agent-crew deploy` is a reminder to populate `.env` before uploading. It doesn't block the deploy. #### What project layout does the cloud build expect? Flat directory. Entry file (`server.py`) and `requirements.txt` at the root, with node files alongside: ``` my-crew/ ├── server.py ├── assistant.py ├── requirements.txt └── .env ``` A `src/` layout will **not** work. The cloud build copies your `pyproject.toml` and runs `pip install .` before it copies the rest of your source, so with a `src/` layout the package isn't on disk yet. The install fails and the build stops (visible as a deploy stuck in `QUEUED`). Two ways to avoid this: * **Flat layout** (recommended). Keep `server.py` + node files at the root, as above. * **Add a `requirements.txt`** if you want to keep a `pyproject.toml` for local tooling or editable installs. When both are present the builder uses `requirements.txt` and skips `pip install .` entirely. --- ## More examples The two crews above are the starting points. The [Smallest AI cookbook](https://github.com/smallest-inc/cookbook/tree/main/voice-agents) ships \~15 ready-to-run voice-agent examples covering tool calling, call control, multi-language support, knowledge-base grounding, real banking / scheduling / IVR flows, observability, and more - each in its own directory with the same `curl`-and-run shape. #### [All voice-agent examples](https://github.com/smallest-inc/cookbook/tree/main/voice-agents) Browse the full set of crews on GitHub. #### [Cookbook root](https://github.com/smallest-inc/cookbook) STT, TTS, voice-agents, mobile, integrations - everything Smallest AI in one repo. ## Need Help? > Build, test, and deploy agent crews from the terminal.