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 use AI coding CLIs (Claude, Auggie, Codex) or custom processes.

Agent Properties

PropertyTypeDescription
idUUIDUnique identifier
nameStringHuman-readable canonical name
nicknameStringHuman-facing display name — auto-assigned from 1920s-era names if not provided
role_idOption<String>Explicit role for routing (e.g., "worker", "reviewer", "researcher")
agent_typeEnumWorker or Supervisor
stateEnumCurrent lifecycle state
cliStringCLI being used (claude, auggie, etc.)
current_taskOptionTask being worked on
parent_agent_idOption<AgentId>Parent agent for delegated subtasks
spawn_modeSpawnModeHow the session was created: Fresh, ForkedContext, or Resumed
current_scopeOption<String>Free-text description of current assigned scope
created_atDateTimeWhen agent was created
last_heartbeatDateTimeLast activity timestamp
tasks_completedu64Count of completed tasks

Roles

Roles are explicit metadata rather than inferred from agent names. The mission scheduler prefers role_id for routing work to agents, falling back to name-based matching only when no role is set.

Built-in roles: worker, reviewer, researcher, architect, tester, devops.

# Spawn with an explicit role
tt spawn backend --role worker
tt spawn qa --role reviewer --nickname "Quality Gate"
tt spawn alice --role researcher --parent backend

Nicknames

Every agent automatically gets a nickname from the 1920s — the decade Tiny Town, Colorado was founded. Names like Robert, Dorothy, Helen, James, and Margaret are deterministically assigned based on the agent’s UUID.

You can override the auto-nickname with --nickname:

tt spawn backend                           # Gets a 1920s name like "Dorothy"
tt spawn backend --nickname "The Builder"  # Overrides to "The Builder"

Spawn Modes

ModeDescription
FreshDefault. New agent with no inherited context.
ForkedContextAgent forked from a parent, inheriting its context with boundary markers.
ResumedAgent resumed from a previous session.

Agent States

┌───────────┐
│  Starting │ ── Agent is initializing
└─────┬─────┘
      │
      ▼
┌───────────┐     ┌───────────┐
│   Idle    │ ◄──►│  Working  │ ── Can accept work / Executing task
└─────┬─────┘     └───────────┘
      │
      ├─────────────────────┐
      ▼                     ▼
┌───────────┐     ┌───────────┐     ┌───────────┐
│  Paused   │     │ Draining  │     │   Error   │
└─────┬─────┘     └─────┬─────┘     └───────────┘
      │                 │
      ▼                 ▼
┌───────────┐     ┌───────────┐
│  Stopped  │     │   Cold    │
└───────────┘     └───────────┘
StateDescription
StartingAgent is initializing
IdleReady to accept work
WorkingExecuting a task
PausedTemporarily paused via tt interrupt — resumes with tt resume
DrainingFinishing current work before stopping (via tt close)
ColdGracefully shut down after draining
ErrorSomething went wrong
StoppedAgent has terminated

Control-Plane Operations

CommandEffect
tt interrupt <agent>Pauses the agent — it stops processing messages until resumed
tt resume <agent>Resumes a paused agent
tt close <agent>Gracefully drains current work, then transitions to Cold
tt wait <agent> [--timeout N]Blocks until the agent reaches a terminal state
tt kill <agent>Requests the agent to stop at the start of its next round

Creating Agents

CLI

# Basic spawn
tt spawn worker-1
tt spawn worker-1 --cli claude

# With role and nickname
tt spawn backend --role worker --nickname "API Developer"

# With parent (for delegated subtasks)
tt spawn subtask-1 --role worker --parent backend

# With all metadata
tt spawn qa --role reviewer --nickname "Quality Gate" --cli auggie

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 CLIs

Tinytown comes with presets for popular AI coding agents:

CLICommandAgent
claudeclaude --print --dangerously-skip-permissionsAnthropic Claude
auggieauggie --printAugment Code
codexcodex exec --dangerously-bypass-approvals-and-sandboxOpenAI Codex
codex-minicodex exec --dangerously-bypass-approvals-and-sandbox -m gpt-5.4-mini -c model_reasoning_effort="medium"OpenAI Codex
geminigeminiGoogle Gemini
copilotgh copilotGitHub Copilot
aideraider --yes --no-auto-commits --messageAider
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