Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Agents

An Agent is a worker that executes tasks. Agents can be AI models (Claude, Auggie, Codex) or custom processes.

Agent Properties

PropertyTypeDescription
idUUIDUnique identifier
nameStringHuman-readable name
agent_typeEnumWorker or Supervisor
stateEnumCurrent lifecycle state
cliStringCLI being used (claude, auggie, etc.)
current_taskOptionTask being worked on
created_atDateTimeWhen agent was created
last_heartbeatDateTimeLast activity timestamp
tasks_completedu64Count of completed tasks

Agent States

┌───────────┐
│  Starting │ ── Agent is initializing
└─────┬─────┘
      │
      ▼
┌───────────┐     ┌───────────┐
│   Idle    │ ◄──►│  Working  │ ── Can accept work / Executing task
└─────┬─────┘     └───────────┘
      │
      ▼
┌───────────┐     ┌───────────┐
│  Paused   │     │   Error   │ ── Temporarily paused / Something went wrong
└─────┬─────┘     └───────────┘
      │
      ▼
┌───────────┐
│  Stopped  │ ── Agent has terminated
└───────────┘

Creating Agents

CLI

# With default model
tt spawn worker-1

# With specific model
tt spawn worker-1 --model claude
tt spawn worker-2 --model auggie
tt spawn reviewer --model codex

Rust API

#![allow(unused)]
fn main() {
use tinytown::{Town, Agent, AgentType};

let town = Town::connect(".").await?;

// Spawn returns a handle
let handle = town.spawn_agent("worker-1", "claude").await?;

// Handle provides operations
let id = handle.id();
let state = handle.state().await?;
let inbox_len = handle.inbox_len().await?;
}

Built-in Models

Tinytown comes with presets for popular AI coding agents:

ModelCommandAgent
claudeclaude --printAnthropic Claude
auggieaugmentAugment Code
codexcodexOpenAI Codex
geminigeminiGoogle Gemini
copilotgh copilotGitHub Copilot
aideraiderAider
cursorcursorCursor

Agent Types

Worker (Default)

Workers execute tasks assigned to them:

#![allow(unused)]
fn main() {
let agent = Agent::new("worker-1", "claude", AgentType::Worker);
}

Supervisor

A special agent that coordinates workers:

#![allow(unused)]
fn main() {
let supervisor = Agent::supervisor("coordinator");
}

The supervisor has a well-known ID and can send messages to all workers.

Working with Agent Handles

#![allow(unused)]
fn main() {
let handle = town.spawn_agent("worker-1", "claude").await?;

// Assign a task
let task_id = handle.assign(Task::new("Build the API")).await?;

// Send a message
handle.send(MessageType::StatusRequest).await?;

// Check inbox
let pending = handle.inbox_len().await?;

// Get current state
if let Some(agent) = handle.state().await? {
    println!("State: {:?}", agent.state);
    println!("Current task: {:?}", agent.current_task);
}

// Wait for completion
handle.wait().await?;
}

Agent Storage in Redis

Agents are persisted in Redis using town-isolated keys:

tt:<town_name>:agent:<uuid>  →  JSON serialized Agent struct
tt:<town_name>:inbox:<uuid>  →  List of pending messages

This town-isolated format allows multiple Tinytown projects to share the same Redis instance without key conflicts. See tt migrate for upgrading from older key formats.

This means:

  • Agent state survives Redis restarts (with persistence)
  • Multiple processes can coordinate via the same town
  • Multiple towns can share the same Redis instance
  • You can inspect state with redis-cli