Skip to content

Create Your First Agent

This guide explains how to build and run a single-agent swarm in SwarmForge. It does not cover multi-agent routing or FastAPI deployment.

This guide is for Python developers who already installed SwarmForge and want the shortest path to a working agent. It assumes that you can run Python code and configure a provider-backed model.

After reading this guide, you should be able to:

  • define a single SwarmNode
  • attach Python tools to that node
  • run the agent with process_swarm_stream(...)

In SwarmForge, a first agent is usually a single-node swarm. You define one SwarmNode, wrap it in a SwarmDefinition, and run it through process_swarm_stream(...) with a session.

This page shows the shortest path in three parts:

  • create the agent
  • add tools
  • run a full example

Before running the full example, copy .env.example to .env, set MODEL_PROVIDER, set LLM_MODEL, and add the matching API key. For the tool example on this page, use a model that supports tool calling.

Quick Start Tabs

python
from swarmforge.swarm import SwarmDefinition, SwarmNode, SwarmSession


swarm = SwarmDefinition(
    id="assistant",
    name="Assistant Swarm",
    nodes=[
        SwarmNode(
            id="assistant",
            node_key="assistant",
            name="Assistant",
            system_prompt=(
                "You are a concise support assistant. "
                "Answer directly and ask for one missing detail when needed."
            ),
            is_entry_node=True,
        )
    ],
)

session = SwarmSession(id="session-1", swarm=swarm)
python
from swarmforge.swarm import function_tool


async def lookup_order(order_id: str, state=None, context=None):
    """Fetch order status for a customer order.

    Args:
        order_id: The order identifier.
    """

    return {
        "order_id": order_id,
        "tenant": state["tenant"],
        "account_id": context.state.get("account_id"),
        "status": "shipped",
    }


swarm.nodes[0].enabled_tools = [function_tool(handler=lookup_order)]
python
import asyncio
import json

from swarmforge.env import require_env_vars
from swarmforge.evaluation.provider import ModelConfig
from swarmforge.swarm import (
    InMemorySessionStore,
    SwarmDefinition,
    SwarmNode,
    SwarmSession,
    build_turn_runner,
    function_tool,
    process_swarm_stream,
)


async def lookup_order(order_id: str, state=None, context=None):
    """Fetch order status for a customer order.

    Args:
        order_id: The order identifier.
    """

    return {
        "order_id": order_id,
        "tenant": state["tenant"],
        "account_id": context.state.get("account_id"),
        "status": "shipped",
    }


tool_registry = {"lookup_order": lookup_order}


swarm = SwarmDefinition(
    id="assistant",
    name="Assistant Swarm",
    nodes=[
        SwarmNode(
            id="assistant",
            node_key="assistant",
            name="Assistant",
            system_prompt=(
                "You are a concise support assistant. "
                "Always call lookup_order before answering an order-status question."
            ),
            enabled_tools=[function_tool(handler=lookup_order)],
            is_entry_node=True,
        )
    ],
)


async def main():
    require_env_vars("MODEL_PROVIDER", "LLM_MODEL")
    session = SwarmSession.from_state(
        id="session-1",
        swarm=swarm,
        state={"account_id": "ACME-991"},
    )
    store = InMemorySessionStore()
    turn_runner = build_turn_runner(ModelConfig())
    async for event in process_swarm_stream(
        session,
        "Where is order 123?",
        store=store,
        turn_runner=turn_runner,
        tool_registry=tool_registry,
        tool_state={"tenant": "acme"},
    ):
        print(json.dumps(event, indent=2))


if __name__ == "__main__":
    asyncio.run(main())

What Each Part Does

Create Agent

SwarmNode is the agent definition. For a first agent, you usually only need:

  • id
  • node_key
  • name
  • system_prompt
  • is_entry_node=True

Put that node inside a SwarmDefinition, then create a SwarmSession for runtime state. Fields such as intent and capabilities are optional metadata, not required for the basic runtime path.

Pass External State

If your application already knows request-scoped facts, pass them directly into the session:

python
session = SwarmSession.from_state(
    id="session-1",
    swarm=swarm,
    state={"account_id": "ACME-991", "priority": "high"},
)

Those values are then available in two places:

  • tools through context.state
  • dynamic prompts through SystemPromptContext.state

Add Tools

function_tool(...) plus a plain tool_registry mapping is the simplest way to add Python tools:

  • define a sync or async Python function
  • let SwarmForge infer the tool schema from the function signature
  • attach the tool schema to a node with function_tool(handler=...)
  • pass tool_registry={"tool_name": handler} into process_swarm_stream(...) so the runtime can resolve the callable
  • pass tool_state=... when the handler needs shared runtime-only dependencies

Injected runtime-only parameters such as context, state, session, visible_state, and visible_global_variables are available to handlers but are not exposed in the model-visible JSON schema.

Example Usage

The runnable example uses the shared OpenAI-compatible turn runner helper. Set MODEL_PROVIDER, LLM_MODEL, and the matching API key before running it. Exact phrasing varies by model, but the runner still forwards the same runtime inputs:

  • config.system_instruction
  • config.tools
  • config.state
  • the current turn history in contents

When To Use This Pattern

Use this page's pattern when you want:

  • one assistant with no handoffs yet
  • a fast way to test tool execution
  • a minimal runtime integration before moving to a larger multi-agent graph

If you need handoffs between multiple agents, continue with Create Your First Multi-Agent Swarm. If you want prompt-generated graph definitions, continue with Authoring.

Released as open source.