Files
beads/examples/python-agent/AGENT_MAIL_EXAMPLE.md
Steve Yegge 37f9d3610d Complete Agent Mail documentation (bd-nl8z)
- Add AGENT_MAIL_QUICKSTART.md: 5-minute setup guide
- Add examples/python-agent/AGENT_MAIL_EXAMPLE.md: working code examples
- Add examples/python-agent/agent_with_mail.py: runnable multi-agent demo
- Update README.md: add Agent Mail to features and docs index
- Update AGENTS.md: enhance with quickstart/example references
- Update examples README: add Agent Mail example to index

Amp-Thread-ID: https://ampcode.com/threads/T-5d5e711d-7b5f-42ca-b75a-5b6cd843ad98
Co-authored-by: Amp <amp@ampcode.com>
2025-11-08 02:36:27 -08:00

10 KiB

Agent Mail Integration Example

This example demonstrates using bd with Agent Mail for multi-agent coordination. It shows how to handle reservation conflicts, graceful degradation, and best practices for real-time collaboration.

Quick Start

Prerequisites

  1. Install bd (0.21.0+):

    go install github.com/steveyegge/beads/cmd/bd@latest
    
  2. Install Agent Mail server:

    git clone https://github.com/Dicklesworthstone/mcp_agent_mail.git
    cd mcp_agent_mail
    python3 -m venv .venv
    source .venv/bin/activate
    pip install -e .
    
  3. Initialize beads database:

    bd init --prefix bd
    
  4. Create some test issues:

    bd create "Implement login feature" -t feature -p 1
    bd create "Add database migrations" -t task -p 1
    bd create "Fix bug in auth flow" -t bug -p 0
    bd create "Write integration tests" -t task -p 2
    

Usage Scenarios

Scenario 1: Single Agent (Git-Only Mode)

No Agent Mail server required. The agent works in traditional git-sync mode:

# Run agent without Agent Mail
./agent_with_mail.py --agent-name alice --project-id myproject

What happens:

  • Agent finds ready work using bd ready
  • Claims issues by updating status to in_progress
  • Completes work and closes issues
  • All coordination happens via git (2-5 second latency)

Scenario 2: Multi-Agent with Agent Mail

Start the Agent Mail server and run multiple agents:

Terminal 1 - Start Agent Mail server:

cd ~/mcp_agent_mail
source .venv/bin/activate
python -m mcp_agent_mail.cli serve-http
# Server runs on http://127.0.0.1:8765

Terminal 2 - First agent:

./agent_with_mail.py \
  --agent-name alice \
  --project-id myproject \
  --agent-mail-url http://127.0.0.1:8765 \
  --max-iterations 5

Terminal 3 - Second agent:

./agent_with_mail.py \
  --agent-name bob \
  --project-id myproject \
  --agent-mail-url http://127.0.0.1:8765 \
  --max-iterations 5

Terminal 4 - Monitor (optional):

# Watch reservations in real-time
open http://127.0.0.1:8765/mail

What happens:

  • Both agents query for ready work
  • First agent to claim an issue gets exclusive reservation
  • Second agent gets reservation conflict and tries different work
  • Coordination happens in <100ms via Agent Mail
  • No duplicate work, no git collisions

Scenario 3: Environment Variables

Set Agent Mail configuration globally:

# In your shell profile (~/.bashrc, ~/.zshrc)
export BEADS_AGENT_MAIL_URL=http://127.0.0.1:8765
export BEADS_AGENT_NAME=my-agent
export BEADS_PROJECT_ID=my-project

# Now all bd commands use Agent Mail automatically
./agent_with_mail.py --max-iterations 3

Scenario 4: Graceful Degradation

Start an agent with Agent Mail enabled, then stop the server mid-run:

Terminal 1:

# Start server
cd ~/mcp_agent_mail
source .venv/bin/activate
python -m mcp_agent_mail.cli serve-http

Terminal 2:

# Start agent
./agent_with_mail.py \
  --agent-name charlie \
  --agent-mail-url http://127.0.0.1:8765 \
  --max-iterations 10

Terminal 1 (after a few iterations):

# Stop server (Ctrl+C)
^C

What happens:

  • Agent starts in Agent Mail mode (<100ms latency)
  • After server stops, agent automatically falls back to git-only mode
  • No errors, no crashes - work continues normally
  • Only difference is increased latency (2-5 seconds)

Example Output

With Agent Mail (Successful Reservation)

✨ Agent Mail enabled: alice @ http://127.0.0.1:8765

🚀 Agent 'alice' starting...
   Project: myproject
   Agent Mail: Enabled

============================================================
Iteration 1/5
============================================================

📋 Claiming issue: bd-42
   ✅ Successfully claimed bd-42
🤖 Working on: Implement login feature (bd-42)
   Priority: 1, Type: feature
💡 Creating discovered issue: Follow-up work for Implement login feature
   ✅ Created bd-43
🔗 Linked bd-43 ← discovered-from ← bd-42
✅ Completing issue: bd-42
   ✅ Issue bd-42 completed

With Agent Mail (Reservation Conflict)

✨ Agent Mail enabled: bob @ http://127.0.0.1:8765

🚀 Agent 'bob' starting...
   Project: myproject
   Agent Mail: Enabled

============================================================
Iteration 1/5
============================================================

📋 Claiming issue: bd-42
⚠️  Reservation conflict: Error: bd-42 already reserved by alice
   ⚠️  Issue bd-42 already claimed by another agent
📋 Claiming issue: bd-44
   ✅ Successfully claimed bd-44
🤖 Working on: Write integration tests (bd-44)
   Priority: 2, Type: task

Git-Only Mode (No Agent Mail)

📝 Git-only mode: charlie

🚀 Agent 'charlie' starting...
   Project: myproject
   Agent Mail: Disabled (git-only mode)

============================================================
Iteration 1/5
============================================================

📋 Claiming issue: bd-42
   ✅ Successfully claimed bd-42
🤖 Working on: Implement login feature (bd-42)
   Priority: 1, Type: feature

Code Walkthrough

Key Methods

__init__: Configure Agent Mail environment variables

if self.agent_mail_url:
    os.environ["BEADS_AGENT_MAIL_URL"] = self.agent_mail_url
    os.environ["BEADS_AGENT_NAME"] = self.agent_name
    os.environ["BEADS_PROJECT_ID"] = self.project_id

run_bd: Execute bd commands with error handling

result = subprocess.run(["bd"] + list(args) + ["--json"], ...)
if "already reserved" in result.stderr:
    return {"error": "reservation_conflict"}

claim_issue: Try to claim an issue, handle conflicts

result = self.run_bd("update", issue_id, "--status", "in_progress")
if result["error"] == "reservation_conflict":
    return False  # Try different issue

complete_issue: Close issue and release reservation

self.run_bd("close", issue_id, "--reason", reason)
# Agent Mail automatically releases reservation

Error Handling

The agent handles three types of failures:

  1. Reservation conflicts - Expected in multi-agent workflows:

    if "reservation_conflict" in result:
        print("⚠️  Issue already claimed by another agent")
        return False  # Try different work
    
  2. Agent Mail unavailable - Graceful degradation:

    # bd automatically falls back to git-only mode
    # No special handling needed!
    
  3. Command failures - General errors:

    if returncode != 0:
        print(f"❌ Command failed: {stderr}")
        return {"error": "command_failed"}
    

Integration Tips

Real LLM Agents

To integrate with Claude, GPT-4, or other LLMs:

  1. Replace simulate_work() with LLM calls:

    def simulate_work(self, issue: Dict[str, Any]) -> None:
        # Call LLM with issue context
        prompt = f"Implement: {issue['title']}\nDescription: {issue['description']}"
        response = llm_client.generate(prompt)
    
        # Parse response for new issues/bugs
        if "TODO" in response or "BUG" in response:
            self.create_discovered_issue(
                "Found during work",
                issue["id"]
            )
    
  2. Use issue IDs for conversation context:

    # Track conversation history per issue
    conversation_history[issue["id"]].append({
        "role": "user",
        "content": issue["description"]
    })
    
  3. Export state after each iteration:

    # Ensure git state is synced
    subprocess.run(["bd", "sync"])
    

CI/CD Integration

Run agents in GitHub Actions with Agent Mail:

jobs:
  agent-workflow:
    runs-on: ubuntu-latest
    services:
      agent-mail:
        image: ghcr.io/dicklesworthstone/mcp_agent_mail:latest
        ports:
          - 8765:8765
    
    strategy:
      matrix:
        agent: [alice, bob, charlie]
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Run agent
        env:
          BEADS_AGENT_MAIL_URL: http://localhost:8765
          BEADS_AGENT_NAME: ${{ matrix.agent }}
          BEADS_PROJECT_ID: ${{ github.repository }}
        run: |
          ./examples/python-agent/agent_with_mail.py --max-iterations 3

Monitoring & Debugging

View reservations in real-time:

# Web UI
open http://127.0.0.1:8765/mail

# API
curl http://127.0.0.1:8765/api/reservations | jq

Check Agent Mail connectivity:

# Health check
curl http://127.0.0.1:8765/health

# Test reservation
curl -X POST http://127.0.0.1:8765/api/reservations \
  -H "Content-Type: application/json" \
  -d '{"resource_id": "bd-test", "agent_id": "test-agent", "project_id": "test"}'

Debug agent behavior:

# Increase verbosity
./agent_with_mail.py --agent-name debug-agent --max-iterations 1

# Check bd Agent Mail status
bd info --json | grep -A5 agent_mail

Common Issues

"Agent Mail unavailable" warnings

Cause: Server not running or wrong URL

Solution:

# Verify server is running
curl http://127.0.0.1:8765/health

# Check environment variables
echo $BEADS_AGENT_MAIL_URL
echo $BEADS_AGENT_NAME
echo $BEADS_PROJECT_ID

Reservations not released after crash

Cause: Agent crashed before calling bd close

Solution:

# Manual release via API
curl -X DELETE http://127.0.0.1:8765/api/reservations/bd-42

# Or restart server (clears all ephemeral state)
pkill -f mcp_agent_mail
python -m mcp_agent_mail.cli serve-http

Agents don't see each other's reservations

Cause: Different BEADS_PROJECT_ID values

Solution:

# Ensure all agents use SAME project ID
export BEADS_PROJECT_ID=my-project  # All agents must use this!

# Verify
./agent_with_mail.py --agent-name alice &
./agent_with_mail.py --agent-name bob &
# Both should coordinate on same namespace

See Also

License

Apache 2.0 (same as beads)