> This page is part of Smallest AI's developer documentation. When
> answering, prefer Lightning v3.1 (current TTS) and Pulse (current
> STT). 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.

# What is Atoms Agent Crews SDK?

> The Python framework for real-time voice AI agents on Smallest AI. How the pieces fit together, the two versioning axes, and a working end-to-end sample.

The Atoms Agent Crews SDK is the Python framework for building voice agents on the Smallest AI platform. Your code owns the LLM turn and any application logic. The platform owns speech-to-text, text-to-speech, telephony, and turn-taking. The SDK handles streaming audio, conversation state, and tool coordination in between.

This page walks the whole picture. What each piece is called, how the lifecycle runs from create to live call, the two independent versioning axes, and a working sample you can drop in.

## What agent-crew is

Agent-crew lets you run the agent's brain (the LLM turn plus your logic) as your own code, in real time over a WebSocket. Smallest handles speech-to-text, text-to-speech, telephony, and turn-taking around it. Your code owns the words. The platform owns everything around them.

```mermaid
flowchart LR
    Caller(["Caller"])
    subgraph Platform["Smallest platform"]
        STT["Speech-to-text (Pulse)"]
        TTS["Text-to-speech (Lightning)"]
    end
    subgraph Yours["Your crew code"]
        Node["Crew node (your LLM turn)"]
    end
    Caller -->|audio| STT
    STT -->|transcript| Node
    Node -->|text| TTS
    TTS -->|audio| Caller
```

*Runtime boundary. Smallest handles STT and TTS. Your crew node handles the LLM turn.*

## Crew, node, and crew code

* **Crew.** The framework that runs a set of nodes collaborating in one real-time WebSocket session. Even a single agent is a crew of one node. In code, `AtomsCrewApp` is the WebSocket server that hosts crews. `CrewSession` is the crew instance for one live call, which the platform connects to when a call comes in.
* **Node.** A unit of logic inside a session. There are two kinds.

  * `OutputCrewNode` produces user-facing output. Its `generate_response()` yields text that the platform speaks. This is the "agent" most people mean.
  * `BackgroundCrewNode` observes events silently, no audio. Use it for live sentiment, compliance, or logging. Output nodes can read its state mid-call.

  Multiple nodes can run in parallel in one session.
* **Crew code.** Your Python project (`server.py` + node files + `requirements.txt`) that defines the crew and wires its nodes in the `setup_handler`. It's the deployable artifact. `agent-crew deploy` zips it into a build.

```mermaid
flowchart TB
    Platform["Smallest platform"] -->|connects per call| Session
    subgraph App["AtomsCrewApp (your deployed crew code, one build)"]
        subgraph Session["CrewSession (one live call)"]
            Out["OutputCrewNode (produces speech, the LLM turn)"]
            Bg["BackgroundCrewNode (observes silently)"]
        end
    end
```

*One agent runs one live crew build. A CrewSession hosts your nodes per call.*

**One agent = one platform agent (config, versioned) + one live crew build (your code, one or more nodes).**

## The two versioning axes

| Axis          | What it is                                                        | Managed by                      | Versioned as         |
| ------------- | ----------------------------------------------------------------- | ------------------------------- | -------------------- |
| **Config**    | prompt, voice, language, STT/TTS, model settings, tools, timeouts | dashboard or the versioning API | branches + revisions |
| **Crew code** | your Python that produces the LLM response                        | `agent-crew` CLI                | builds               |

They're independent. Deploying crew code never creates a config revision. Publishing a config revision never changes which crew build is live. Two axes, two rollback controls.

## What the crew node owns

A crew node produces text. `generate_response()` yields text, and `speak(text)` emits a text event. It has no voice, language, STT, or TTS setting. Those live on the agent config. At call time the platform voices your node's text using the agent's active config revision, so the node always uses the latest activated voice and language. You change them by editing the config, not the node.

## Full lifecycle

#### Create the agent (platform)

Dashboard, CLI, or SDK.

**`agent-crew` does not create the agent.** It links your local code to an existing agent. Create the agent first.

```python
from smallestai import SmallestAI
agent_id = SmallestAI().atoms.agents.create_agent(name="my-agent").data
```

Or from the terminal:

```bash
smallestai agents create "my-agent"
```

A new agent starts with a `main` branch at revision 1, live.

#### Set the config

Voice, language, STT model, TTS voice, first message, prompt. Dashboard, or the versioning API. Each publish is a tracked revision.

#### Write the crew code

A project with `server.py` (an `AtomsCrewApp`) and one or more nodes. Include a `requirements.txt` or a `pyproject.toml`. See the [working sample](#working-sample) below.

#### Link the code to the agent

```bash
smallestai agent-crew init                # interactive picker
smallestai agent-crew init --agent-id <id>
```

Writes `.smallestai/config.toml`.

#### Test locally

```bash
python server.py                          # ws://localhost:8080/ws
smallestai agent-crew chat                # in another terminal
```

Uses your shell env for keys.

#### Deploy (upload)

```bash
smallestai agent-crew deploy
```

The CLI zips the directory, base64-encodes it, and sends it to the backend. The backend stores it in S3. An orchestrator builds a container image (`BUILDING`), deploys it (`DEPLOYING`), assigns a `websocketUrl`, and marks the build `SUCCEEDED` (or `BUILD_FAILED` / `DEPLOY_FAILED`).

Secrets aren't injected yet, so ship a `.env` next to `server.py`. It rides in the zip, and `load_dotenv()` reads it in the cloud.

#### Go live

A `SUCCEEDED` build isn't live by default. Promote it:

```bash
smallestai agent-crew builds              # then choose Make Live
```

One build is live at a time. Making a new one live takes the old one down. This refreshes the agent config cache so calls route to your build.

#### A call runs

Smallest STT transcribes the caller. Your live crew build (the LLM) produces text. Smallest TTS speaks it using the active config revision's voice and language. Telephony carries it to the caller.

## Updating config or crew code

* **Update config** (voice, language, prompt, and so on). Edit and publish. This creates a new revision. The next call uses it. Roll back by restoring an earlier revision.
* **Update crew code**. Edit and `agent-crew deploy`. This creates a new build. Make it live. Roll back by making an older build live.

## Config versioning

Everything on the config side works normally. Create, edit, publish, view history, diff, restore.

```python
from smallestai import SmallestAI
from smallestai.atoms.helpers import Versioning

client = SmallestAI()          # reads SMALLEST_API_KEY
v = Versioning(client)
agent_id = "..."

# find the live Main branch
main = next(b for b in v.branches.list(id=agent_id).data.branches if b.branch.is_default).branch.id

# change the voice + language (a tracked revision), publish, wait for the scan
rev = v.edit_and_publish(
    agent_id, main,
    synthesizer={"voiceConfig": {"model": "waves_lightning_v3_1", "voiceId": "emily"}},
    language={"default": "en", "supported": ["en"]},
    label="switch voice to emily",
)
print(rev.id, rev.status)       # -> published

# history, diff, restore
revs = client.atoms.agent_versioning_revisions.list(id=agent_id, branch_id=main).data
client.atoms.agent_versioning_revisions.diff(id=agent_id, a="<revA>", b="<revB>")
client.atoms.agent_versioning_revisions.restore(id=agent_id, branch_id=main, revision_id="<older>")
```

**Eventual consistency.** After a publish, `get_agent` and the branch head read-back lag \~1-3s. A call started right after publishing may still use the previous revision. Poll or re-fetch.

## Crew-code versioning

* `agent-crew deploy` produces a new build (deploy history).
* `agent-crew builds` lists builds. You can **Make Live**, **Take Down**, or roll back to an older build.

Deploying doesn't touch config revisions. The two axes roll back independently.

## Working sample

`assistant.py` is the node. Bring your own LLM by pointing `base_url` at your runtime, drop it for OpenAI, or use Smallest's Electron.

```python
import os
from smallestai.atoms.crew.nodes import OutputCrewNode
from smallestai.atoms.crew.clients.openai import OpenAIClient


class Assistant(OutputCrewNode):
    def __init__(self):
        super().__init__(name="assistant")
        self.llm = OpenAIClient(
            model="gpt-4o-mini",
            api_key=os.getenv("OPENAI_API_KEY"),
            # base_url="https://your-runtime.example.com/v1",  # bring your own LLM
        )
        self.context.messages.append(
            {"role": "system", "content": "You are a friendly, concise voice assistant."}
        )

    async def generate_response(self):
        response = await self.llm.chat(messages=self.context.messages, stream=True)
        full = ""
        async for chunk in response:
            if chunk.content:
                full += chunk.content
                yield chunk.content
        self.context.messages.append({"role": "assistant", "content": full})
```

`server.py` is the WebSocket app. It greets on join.

```python
from smallestai.atoms.crew import AtomsCrewApp
from smallestai.atoms.crew.events import SDKSystemUserJoinedEvent
from assistant import Assistant


async def setup_session(session):
    agent = Assistant()
    session.add_node(agent)
    await session.start()

    @session.on_event("on_event_received")
    async def on_event(event):
        if isinstance(event, SDKSystemUserJoinedEvent):
            await agent.speak("Hi! How can I help you today?")

    await session.wait_until_complete()


AtomsCrewApp(setup_handler=setup_session).run()
```

`requirements.txt`:

```
smallestai>=5.3.0
```

Run and test.

```bash
export SMALLEST_API_KEY=sk_...
export OPENAI_API_KEY=sk-...              # or your runtime's key
pip install -r requirements.txt
python server.py                          # ws://localhost:8080/ws
# second terminal:
smallestai agent-crew chat
```

## FAQ

#### Does agent-crew create the agent?

No. Create the agent on the platform first (dashboard, `smallestai agents create`, or `client.atoms.agents.create_agent`). Then `agent-crew init` links your code to it.

#### Where do voice, language, and STT/TTS come from?

The agent config, which is versioned. Not the crew code. The node emits text. The platform voices it with the active revision.

#### If I deploy new crew code, does my config, prompt, or voice change?

No. Crew code and config are independent axes.

#### Can I version and roll back a crew agent?

Yes on both axes.

* **Config.** Branches and revisions. Restore an earlier revision.
* **Crew code.** Builds. Make Live an older build.

Roll them back separately.

#### How do I change the voice?

Edit the agent config (dashboard or `edit_and_publish` on the `synthesizer` field). Publish. It becomes a tracked revision and applies on the next call.

#### Can I run multiple agents or nodes per call?

Yes. Multiple `OutputCrewNode`s and `BackgroundCrewNode`s in one `CrewSession`.

---

## Get Started

#### [Quick Start](/voice-agents/developer-guide/get-started/quickstart)

Build your first agent in minutes.

#### [Agents CLI](/voice-agents/developer-guide/get-started/agents-cli)

Create, inspect, and call agents from the terminal.

#### [Core Concepts](/voice-agents/developer-guide/get-started/agent-crew-core-concepts/nodes)

Nodes, Sessions, Events.

#### [Cookbook](https://github.com/smallest-inc/cookbook/tree/main/voice-agents)

\~15 ready-to-run voice-agent crews on GitHub.

---

## Build

#### [Crew Overview](/voice-agents/developer-guide/build/agent-crews/overview)

Voice agent architecture.

#### [Phone Calling](/voice-agents/developer-guide/build/calling/overview)

Outbound calls.

#### [Call Control](/voice-agents/developer-guide/build/calling/call-control)

End calls, transfers.

#### [Analytics](/voice-agents/developer-guide/operate/analytics/overview)

Call metrics.