Local Development

Zero infrastructure. Just code.

Local Development

Start building agents in seconds with embedded BoltDB

Traditional development requires PostgreSQL running, Redis for state, environment variables configured.

Agentfield development requires one command: af server.

The CLI includes an embedded BoltDB database that auto-initializes. Write agent code, test multi-agent workflows, and iterate fast—without infrastructure setup.


Quick Start

Start Control Plane

af server

What happens:

  • Control plane starts on http://localhost:8080
  • BoltDB initializes in ~/.agentfield/agentfield.bolt
  • Web UI accessible at http://localhost:8080
  • Auto-runs database migrations
  • Ready for agent connections

Output:

2025-01-15 10:23:45 INFO  Control plane started
2025-01-15 10:23:45 INFO  Storage: BoltDB (local mode)
2025-01-15 10:23:45 INFO  HTTP server listening on :8080
2025-01-15 10:23:45 INFO  Web UI: http://localhost:8080

Create Your First Agent

# In another terminal
af init my-agent --language python

cd my-agent

Generated structure:

my-agent/
├── agentfield.yaml   # Agent configuration
├── main.py           # Entry point
├── requirements.txt  # Dependencies
└── README.md

Run the Agent

af run

What happens:

  • Agent registers with control plane at localhost:8080
  • Auto-detects callback URL (your machine's IP)
  • Hot reload enabled (edit code, see changes instantly)
  • Logs stream to terminal

Output:

2025-01-15 10:24:12 INFO  Agent 'my-agent' starting...
2025-01-15 10:24:12 INFO  Registered with control plane
2025-01-15 10:24:12 INFO  Callback URL: http://192.168.1.100:8001
2025-01-15 10:24:12 INFO  Hot reload: enabled

Test Your Agent

# Call your agent's reasoner
curl -X POST http://localhost:8080/api/v1/execute/my-agent.process \
  -H "Content-Type: application/json" \
  -d '{"input": {"text": "Hello from local dev!"}}'

Response:

{
  "execution_id": "exec_abc123",
  "status": "completed",
  "result": {
    "message": "Processed: Hello from local dev!"
  }
}

What's Included

Embedded Database

BoltDB auto-initializes in ~/.agentfield/agentfield.bolt. Stores executions, memory, agent registry—everything.

Limitation: Single writer, local only. Move to PostgreSQL for team collaboration or production testing.


Hot Reload

Python agents reload automatically when you save code:

app = Agent(node_id="my-agent", dev_mode=True)

@app.reasoner()
async def process(text: str) -> dict:
    # Edit this, save → instant reload
    return {"result": f"Processed: {text}"}

Web UI

Access the control plane UI at http://localhost:8080:

Features:

  • Workflow DAGs: Visualize execution flows
  • Agent Registry: See active/inactive agents
  • Execution History: Browse past runs
  • Memory Inspector: View shared state
  • Metrics Dashboard: Queue depth, throughput, errors

Development workflows:

  1. Write agent code
  2. Call via curl or UI
  3. View execution in real-time
  4. Debug with DAG visualization
  5. Iterate

Development Patterns

Single Agent Development

Most common: one control plane, one agent.

# Terminal 1: Control plane
af server

# Terminal 2: Your agent
cd my-agent
af run

Use case: Building a new agent, rapid prototyping


Multi-Agent Development

Test agent coordination locally:

# Terminal 1: Control plane
af server

# Terminal 2: Support agent
cd agents/support
af run

# Terminal 3: Analytics agent
cd agents/analytics
af run

# Terminal 4: Email agent
cd agents/email
af run

All agents share:

  • Same BoltDB database
  • Memory fabric (via control plane)
  • Workflow execution context

Test cross-agent calls:

# In support agent
@app.reasoner()
async def triage_ticket(ticket: dict) -> dict:
    # Call analytics agent
    sentiment = await app.call(
        "analytics-agent.analyze_sentiment",
        text=ticket["message"]
    )

    # Call email agent if urgent
    if sentiment["urgency"] == "high":
        await app.call(
            "email-agent.notify_team",
            ticket=ticket
        )

    return {"status": "triaged", "sentiment": sentiment}

Control plane handles routing even on localhost.


Environment Variables

Minimal config needed for local development:

# Optional: Override defaults
export AGENTFIELD_SERVER=http://localhost:8080  # Default
export AGENT_PORT=8001                          # Default
export AGENT_CALLBACK_URL=auto                  # Auto-detected
export AGENTFIELD_LOG_LEVEL=DEBUG               # Verbose logging

# LLM provider (only if using app.ai())
export OPENAI_API_KEY=your-key

Most times you need zero env vars. Defaults work.

# Optional: Override defaults
export AGENTFIELD_SERVER=http://localhost:8080
export AGENT_PORT=8001
export AGENT_CALLBACK_URL=auto

# LLM provider
export OPENAI_API_KEY=your-key

Testing Workflows

Test Sync Execution

curl -X POST http://localhost:8080/api/v1/execute/my-agent.process \
  -H "Content-Type: application/json" \
  -d '{"input": {"text": "test"}}'

Returns immediately with result (unless execution takes > 30s).


Test Async Execution

curl -X POST http://localhost:8080/api/v1/execute/async/my-agent.long_task \
  -H "Content-Type: application/json" \
  -d '{
    "input": {"task": "generate_report"},
    "webhook": {
      "url": "http://localhost:3000/webhooks/agentfield",
      "secret": "dev_secret_123"
    }
  }'

Returns immediately with 202 Accepted and execution_id.

Poll for status:

curl http://localhost:8080/api/v1/executions/exec_abc123

Webhook fires when complete (if you have a local server listening).


Test Memory Operations

# Agent 1: Write to memory
@app.reasoner()
async def store_data(key: str, value: str):
    await app.memory.set(key, value)
    return {"stored": key}

# Agent 2: Read from memory
@app.reasoner()
async def retrieve_data(key: str):
    value = await app.memory.get(key)
    return {"key": key, "value": value}

Memory is shared across all agents connected to the control plane.


Debugging

View Logs

Control plane logs:

af server --log-level debug

Agent logs:

# Python
af run --log-level debug

# Or set environment variable
export AGENTFIELD_LOG_LEVEL=DEBUG
af run

Inspect Workflow DAG

After executing an agent:

  1. Open Web UI: http://localhost:8080
  2. Navigate to Executions
  3. Click on execution ID
  4. View DAG showing agent call chain

Example DAG:

support-agent.triage
  ├─> analytics-agent.analyze_sentiment
  └─> email-agent.notify_team

Debug Memory State

Via Web UI:

  1. Go to Memory tab
  2. Filter by scope: global, actor, session, workflow
  3. View key-value pairs in real-time

Via API:

curl http://localhost:8080/api/v1/memory?scope=global

Test Failure Scenarios

Kill agent mid-execution:

# Start long-running task
curl -X POST http://localhost:8080/api/v1/execute/async/my-agent.slow_task \
  -d '{"input": {}}'

# Kill agent process
pkill -f "af run"

Control plane detects missed heartbeat:

  • Marks agent as inactive after 2 minutes
  • Queued executions fail with "agent unavailable"
  • Restart agent → auto-registers → resumes

Moving to PostgreSQL

When you need team collaboration or production patterns, switch to PostgreSQL:

export AGENTFIELD_POSTGRES_URL=postgres://localhost:5432/agentfield
af server  # Migrations run automatically

Your agent code doesn't change. Same code works with BoltDB or Postgres.


Development Tips

Use .env Files

# my-agent/.env
AGENTFIELD_SERVER=http://localhost:8080
OPENAI_API_KEY=sk-...
AGENT_PORT=8001

Load automatically:

# main.py
from dotenv import load_dotenv
load_dotenv()

from agentfield import Agent
app = Agent("my-agent")

Mock External APIs

When developing agents that call external services:

# main.py
import os

MOCK_MODE = os.getenv("MOCK_MODE", "false") == "true"

@app.skill()
async def fetch_weather(city: str):
    if MOCK_MODE:
        return {"temp": 72, "condition": "sunny"}  # Mock response

    # Real API call
    async with httpx.AsyncClient() as client:
        response = await client.get(f"https://api.weather.com/{city}")
        return response.json()

Enable mocking:

export MOCK_MODE=true
af run

Quick Reset

Clear all data and start fresh:

# Stop control plane
pkill -f "af server"

# Delete BoltDB file
rm ~/.agentfield/agentfield.bolt

# Restart
af server

Use case: Testing migrations, resetting state, debugging persistence issues.



Local development is friction-free. One command starts infrastructure. Focus on agent logic, not ops.