Get started
Quickstart

Run Agent Barn locally

Start the local Docker and k3d stack, configure model access, and create an Agent without a GitHub token for runtime builds.

For
Evaluators and contributors
On this page
  1. Cost synchronization
  2. What you will accomplish
  3. Before you begin
  4. Clone the repository
  5. Create the local configuration
  6. Start Agent Barn
  7. Verify the environment
  8. Sign in
  9. Your first local Agent
  10. What is running
  11. Stop or resume the environment
  12. Success checklist
  13. Troubleshooting
  14. Next steps

Start the complete Agent Barn development environment with Docker. When you finish, you will have the web app, Product API, Ingest API, Communications service, Domain Event worker, LiteLLM and its PostgreSQL database, the application PostgreSQL and Redis services, a local k3d Kubernetes cluster, the Hermes and OpenClaw Runtime images, and Runtime Kubernetes resources for any Agent you start.

Application services run in Docker Compose. Agent Runtime resources run inside the local k3d cluster. The Communications service is required for Communication Connections and provider delivery, and Product, Ingest, and Communications are separate HTTP boundaries rather than one API.

What you will accomplish

By the end of this guide, you will be able to:

  • Open Agent Barn at http://localhost:3000
  • Sign in as the bootstrap Platform Administrator
  • Create an Organization
  • Hire and start a headless Agent inside the local Kubernetes cluster
  • Add a Communication Connection through the local Communications service
  • Route model requests through the local LiteLLM proxy
  • See Conversation Messages and Tool Calls arrive through their separate paths
  • Stop and resume the environment without losing local database data

Before you begin

Required software

You need only:

  • Git
  • Docker with Linux containers
  • A running Docker daemon
  • Sufficient local CPU, memory, and disk capacity
  • OpenSSL, used below to generate local keys

Run the commands in this guide from a Bash-compatible terminal. On Windows, use WSL2 with Docker Desktop integration enabled. If the openssl command is unavailable, install OpenSSL using your operating system's package manager before continuing.

Docker Desktop is the simplest option on macOS and Windows. On Windows, run the repository through WSL2 with Docker Desktop's Linux-container backend.

The complete Docker workflow does not require host installations of Python, Node.js, uv, pnpm, k3d, or Helm. The repository supplies a k3d-runner container for the k3d command. Native tools are needed only for host-managed development, testing, or selected maintenance workflows.

Required accounts and credentials

You need:

Both Agent Barn and aai-cli are public. You do not need membership in AAI Labs or permission to access a private repository.

You need an OpenRouter API key for the configured model-routing path. The runtime Dockerfiles clone the public aai-labs/aai-cli repository directly; the local build does not require a GitHub personal access token. An optional Agent GitHub tool Integration can separately use credentials.

Local ports

Make sure these default host ports are available before starting the stack:

PortService
3000Agent Barn web app
5432Application PostgreSQL database
6379Redis
7070LiteLLM
8000Product API
8001Ingest API
8002Communications service
16443Local k3d Kubernetes API

These are local development ports. They are not instructions to expose these services to the internet.

If a port is already in use, check the corresponding settings in .env.spec and the local cluster configuration before starting. Keep any changed port consistent with the addresses used later in this guide.

Clone the repository

Shell
git clone https://github.com/aai-labs/agent-barn.git
cd agent-barn

The GitHub repository uses the current agent-barn name. The local Kubernetes namespaces intentionally retain the historical agent-farm naming.

Create the local configuration

./run.sh expects a .env file in the repository root. You do not have to create it by hand:

Shell
./run.sh

If .env is missing, ./run.sh creates it from .env.spec, reports the values you still need to supply, and exits. Replace the empty or placeholder values, then run ./run.sh again.

.env.spec remains the authoritative inventory and description of every supported local variable. Read it when you need to know what a setting does.

Required values

The stack does not start until these values are set:

VariablePurpose
POSTGRES_USERApplication database user
POSTGRES_PASSWORDApplication database password
POSTGRES_DBApplication database name
POSTGRES_PORTPublished database port
SECRET_SIGNING_KEYSigns application tokens
PLATFORM_ADMIN_CREDENTIALSBootstrap Platform Administrator sign-in
ENVIRONMENTEnvironment name for the local run
UI_APP_URLPublic URL of the web app
API_PORTPublished Product API port
AGENT_TOKEN_ENCRYPTION_KEYEncrypts stored credentials
OPENROUTER_API_KEYUpstream model access for LiteLLM
LITELLM_MASTER_KEYProtects LiteLLM virtual keys
OPENCLAW_IMAGEPinned OpenClaw Runtime image reference
HERMES_IMAGEPinned Hermes Runtime image reference

Database and application

Environment
POSTGRES_USER=agentbarn
POSTGRES_PASSWORD=<local-database-password>
POSTGRES_DB=agentbarn
POSTGRES_PORT=5432

API_PORT=8000
ENVIRONMENT=local
UI_APP_URL=http://localhost:3000

SECRET_SIGNING_KEY=<random-signing-key>
PLATFORM_ADMIN_CREDENTIALS=admin@example.com:<secure-password>

The Platform Administrator password must contain:

  • At least eight characters
  • An uppercase letter
  • A lowercase letter
  • A digit

Generate a random signing key with:

Shell
openssl rand -hex 32

Do not use the generated signing key as the Platform Administrator password.

Credential encryption

Agent Barn uses an encryption key to protect stored credentials.

From your terminal, generate a new key:

Shell
openssl rand -base64 32 | tr '+/' '-_'

Copy the generated value into the AGENT_TOKEN_ENCRYPTION_KEY entry in the .env file at the repository root:

Environment
AGENT_TOKEN_ENCRYPTION_KEY=PASTE_THE_GENERATED_VALUE_HERE

Replace PASTE_THE_GENERATED_VALUE_HERE with the complete output from the command. Do not enter the command itself as the value.

Generate this key once for your local installation and keep it stable across restarts. Replacing it later prevents Agent Barn from reading credentials encrypted with the previous key.

Keep .env private and do not commit it to Git.

Model routing

Environment
OPENROUTER_API_KEY=<openrouter-api-key>
LITELLM_MASTER_KEY=<stable-litellm-master-key>

Generate a local LiteLLM master key with:

Shell
printf 'sk-%s\n' "$(openssl rand -hex 16)"

Set the generated value once and keep it stable. LiteLLM uses it to protect the virtual keys it stores. Changing it between runs breaks Agents created with keys protected by the previous value.

Agent Runtime images

Read the versions pinned by the repository:

Shell
printf 'OpenClaw: '
cat openclaw-base/VERSION

printf 'Hermes: '
cat hermes-base/VERSION

Set both image references using those exact tags:

Environment
OPENCLAW_IMAGE=agentbarn-openclaw-base:<openclaw-version>
HERMES_IMAGE=agentbarn-hermes-base:<hermes-version>

The image tag must match the corresponding VERSION file. Startup stops with a clear error when the values do not match.

Optional ports

These settings have working defaults and only need changing when a port is already in use:

VariableDefault
INGEST_PORT8001
COMMUNICATIONS_PORT8002
UI_PORT3000
LITELLM_PORT7070

You do not need to set API_K8S_KUBECONFIG_PATH. ./run.sh writes the expected in-container kubeconfig path automatically.

Start Agent Barn

Start the complete environment:

Shell
./run.sh

To start without following logs:

Shell
./run.sh --detach

The launcher:

  1. Confirms Docker exists and the daemon is running.
  2. Loads .env and validates required values.
  3. Starts the local k3d cluster and LiteLLM.
  4. Loads the Hermes and OpenClaw base images into k3d, skipping images already present.
  5. Configures the API container to use the generated internal kubeconfig.
  6. Starts PostgreSQL and Redis.
  7. Builds the API image.
  8. Runs Alembic migrations.
  9. Builds and starts the API, worker, Communications, and UI services.
  10. Follows Compose logs unless detached mode was selected.

Verify the environment

Check the containers

Shell
docker compose -f compose.yml ps

Expected long-running application services:

  • db
  • redis
  • api
  • worker
  • communications
  • ui
  • LiteLLM services started through the k3d profile

Check the Product API

Shell
curl --fail http://localhost:8000/api/v1/health

This confirms that the Product API can reach PostgreSQL. It does not prove that Ingest, Communications, LiteLLM, or any Agent Runtime is healthy.

Check the Ingest API

Shell
curl --fail http://localhost:8001/ingest/v1/openapi.json

Check the Communications service

Shell
curl --fail http://localhost:8002/health

Optional cluster inspection

If you have kubectl installed, you can inspect the local cluster with the generated host kubeconfig:

Shell
kubectl \
  --kubeconfig .k3d/kubeconfig-host.yaml \
  get namespace agent-farm

Sign in

Open:

http://localhost:3000

Sign in with the email and password from PLATFORM_ADMIN_CREDENTIALS in .env. From there:

  1. Create or select an Organization.
  2. Create a headless Agent.
  3. Start the Agent.
  4. Add a Communication Connection separately, when provider messaging is required.

Continue with Create your first Organization, then Hire your first Agent.

Your first local Agent

Hiring creates a headless Agent. Communication is a separate, later step.

  1. Create an Organization.
  2. Review the Organization model allowlist and default.
  3. Hire a headless Agent.
  4. Choose Hermes or OpenClaw.
  5. Select a Template.
  6. Configure required Skills and tool Integration credentials.
  7. Start the Agent.
  8. Add one or more Communication Connections.
  9. Complete provider-side setup.
  10. Verify Runtime health and Connection health separately.
  11. Send one allowed provider message.
  12. Inspect the Connection-scoped Conversation.
  13. Use a controlled tool request before expecting a Tool Call.

Hiring does not create Slack, Microsoft Teams, Telegram, or Discord configuration. See Connect a Platform for the Connection workflow and Verify your Agent for the layered checks.

What is running

ServiceLocal addressResponsibility
Web apphttp://localhost:3000User interface
Product APIhttp://localhost:8000/api/v1Product and administration operations
Ingest APIhttp://localhost:8001/ingest/v1Runtime Tool Call telemetry
Communicationshttp://localhost:8002/communications/v1Runtime communication protocol and provider delivery
LiteLLMhttp://localhost:7070Model routing and Agent key usage
PostgreSQLlocalhost:5432 by defaultAgent Barn application database

A few details matter when you are reading logs or debugging a port:

  • Product and Ingest run as separate processes in the api container.
  • Communications runs in its own communications container.
  • Containers reach Redis through the Compose network. Redis is also published on host port 6379 by default for local development.
  • LiteLLM uses its own PostgreSQL database, separate from the application database.
  • Host ports can differ when the corresponding .env values are changed.

The Communications service

Communications runs from the API image as a separate FastAPI application. It listens on port 8002 by default, and its API is mounted beneath /communications/v1. It:

  • Supervises supported provider sessions
  • Processes durable inbound and outbound Communication Deliveries
  • Exposes the Runtime-neutral Communications protocol
  • Persists canonical Conversation Messages
  • Maintains Connection health and operational metrics

Agent Runtime pods inside k3d reach it through host.docker.internal. The default local base URL is equivalent to:

Text
http://host.docker.internal:8002/communications/v1

COMMUNICATIONS_BASE_URL is configured for Agent Runtime resources and is distinct from the Product API URL.

Who writes Conversations and Tool Calls

The two Activity paths have different writers:

  • Ingest stores authenticated Runtime Tool Call telemetry.
  • The Communications Gateway writes canonical inbound and outbound Conversation Messages.
  • Product API routes provide authorized reads for both.
  • Conversation identity includes a Communication Connection.

That separation shapes how local failures look:

  • A broken Ingest path can leave Tool Calls empty while provider Conversations continue to work.
  • A broken Communications path can prevent provider messaging while Tool Call ingest and the Product API remain healthy.

See Activity, conversations, and runtime telemetry.

How local services reach each other

Application services run in Docker Compose while Agent workloads run in k3d, so Agent Runtime resources reach the application through host-published ports.

Browser to Product API

The browser reaches the web app, and the web app reaches the Product API through the existing local application configuration.

Agent Runtime to Ingest

Text
http://host.docker.internal:8001/ingest/v1

Agent Runtime to Communications

Text
http://host.docker.internal:8002/communications/v1

Agent Runtime to LiteLLM

Text
http://host.docker.internal:7070

These host hops are required because of the split between Compose and k3d. Do not substitute Compose-only DNS names in Agent Runtime configuration; a Compose service name is not resolvable from inside a k3d pod.

For how these resources are assembled, see Runtime assembly and deployment.

Stop or resume the environment

Stop the environment:

Shell
./stop.sh

or:

Shell
make stop

The normal stop:

  • Stops application containers
  • Stops the local k3d cluster
  • Stops LiteLLM services
  • Preserves PostgreSQL and Redis volumes
  • Preserves the k3d cluster for a faster restart

Resume with:

Shell
./run.sh --detach

To stop and reset the local cluster:

Shell
./stop.sh --clean

or:

Shell
make stop-clean

The clean option:

  • Removes the application containers
  • Deletes the k3d cluster
  • Removes generated .k3d files
  • Preserves named database and Redis volumes
  • Requires Agent Runtime images to be loaded again at the next startup

Success checklist

The local environment is ready when you can confirm:

  • Docker is running
  • .env contains all required values
  • PostgreSQL and Redis are healthy
  • Migrations completed
  • The Product API is reachable on 8000
  • Ingest is reachable on 8001
  • Communications is reachable on 8002
  • The UI is reachable on 3000
  • LiteLLM is reachable through the configured local port
  • The k3d cluster is running
  • The Hermes and OpenClaw images were loaded
  • Platform Administrator sign-in works
  • An Organization can be created or selected
  • A headless Agent can be hired and started
  • A Communication Connection can be added separately
  • Conversation and Tool Call paths are understood as separate

Troubleshooting

./run.sh reports missing values

Open .env and replace the empty or placeholder values named by the script. Use .env.spec for descriptions, then run ./run.sh again.

Do not remove a variable from the validation list to bypass the error.

Docker is unavailable

Start Docker and confirm Linux containers are enabled. Retry after this succeeds:

Shell
docker info

Migration fails

Application services do not complete startup when migrations fail. Review the retained migration output and correct the database or migration issue before rerunning.

Do not repeatedly restart the stack without understanding the schema state.

Startup fails while creating the Platform Administrator

Check PLATFORM_ADMIN_CREDENTIALS. Its password must contain at least eight characters, an uppercase letter, a lowercase letter, and a digit.

The high-level error can appear as:

Text
500: Error while initializing startup data

The API log immediately before that message contains the underlying validation error.

The Product API works but Tool Calls remain empty

Check Ingest on port 8001, then confirm that Agent Runtime resources use the correct Ingest base URL:

Text
http://host.docker.internal:8001/ingest/v1

Also confirm the request actually invoked a tool. A request that uses no tool is not expected to produce a Tool Call.

Do not diagnose this as a Conversation persistence failure.

The Product API works but provider Conversations remain empty

Check Communications on port 8002, then confirm:

  • The Agent has an enabled Communication Connection
  • Provider credentials and provider-side setup are complete
  • The Connection's access and mention policy allow the message
  • The Agent Runtime is running

Do not check Ingest as the canonical Conversation writer. See Communication Connections.

A Conversation appears but no reply arrives

Review Agent Runtime health, then review Connection health and delivery diagnostics separately. Confirm outbound provider permissions and that the source Connection remains enabled.

An Agent cannot start in k3d

Confirm that:

  • The Runtime images were loaded
  • The API container can reach the generated kubeconfig
  • k3d is running

Then review model, Template, Skill, and Integration requirements, along with the Agent lifecycle logs.

Communications cannot be reached from an Agent pod

Confirm that:

  • The communications container is running
  • Host port 8002 is published
  • COMMUNICATIONS_BASE_URL uses host.docker.internal
  • A local firewall or Docker networking rule is not blocking the host-published port

On native Linux, also verify that the host firewall permits traffic from the k3d bridge network.

Runtime image tags do not match

OPENCLAW_IMAGE and HERMES_IMAGE must end with the versions stored in:

Text
openclaw-base/VERSION
hermes-base/VERSION

Update .env so each tag matches its file exactly.

The Runtime-image build cannot read aai-cli

The runtime Dockerfiles clone the public repository directly. Check network access to GitHub and the public source URL; a GitHub token is not a local runtime-build prerequisite.

An Agent is stuck in ImagePullBackOff

Confirm that the image reference in .env matches the imported image and the repository VERSION file.

Reload missing images with:

Shell
bash docker/k3d/k3d-load-images.sh

Agent pods are killed with exit code 137

Exit code 137 or OOMKilled normally means the Docker environment ran out of memory.

Inspect current usage:

Shell
docker stats --no-stream

Increase the Docker memory allocation or stop unrelated workloads before retrying.

Next steps

Microsoft Teams requires a webhook that Microsoft can reach over public HTTPS. A localhost-only installation does not meet that prerequisite. Before following the Microsoft Teams guide, arrange a public endpoint with your installation administrator or prepare a self-hosted deployment.

Cost freshness and synchronization

See Cost synchronization for the entrypoint, credentials, schedule, backfill, and healing behavior.

Calls can occur while Costs remains empty or stale. Check cost-sync scheduling and logs, database access, LiteLLM master-key lookup, and upstream availability. An absent record or unresolved OpenRouter lookup does not prove a call was free. Review attribution and recovery backlog separately from Runtime health.

Docker Compose and run.sh do not schedule cost synchronization automatically. Local reporting needs an explicit invocation in a configured application environment; refreshing Costs does not perform synchronization.

Documentation