# Tutorial: Single Agent Workflow
Let's build a complete workflow with one agent doing a coding task.
## What We'll Build
A simple system that:
1. Creates a coding task
2. Assigns it to an agent
3. Waits for completion
4. Reports the result
## Setup
```bash
mkdir single-agent-demo && cd single-agent-demo
tt init --name demo
```
## The Code
Create `main.rs`:
```rust
use tinytown::{Town, Task, Result};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<()> {
// Connect to town
let town = Town::connect(".").await?;
// Create an agent
let agent = town.spawn_agent("coder", "claude").await?;
println!("š¤ Spawned agent: {}", agent.id());
// Create a task
let task = Task::new(
"Create a Rust function that calculates fibonacci numbers recursively"
);
println!("š Created task: {}", task.id);
// Assign to agent
let task_id = agent.assign(task).await?;
println!("ā
Assigned task {} to coder", task_id);
// Check status periodically
loop {
tokio::time::sleep(Duration::from_secs(5)).await;
if let Some(state) = agent.state().await? {
println!(" Agent state: {:?}", state.state);
match state.state {
tinytown::AgentState::Idle => {
println!("š Agent completed work!");
break;
}
tinytown::AgentState::Error => {
println!("ā Agent encountered error");
break;
}
_ => continue,
}
}
}
// Get task result
if let Some(task) = town.channel().get_task(task_id).await? {
println!("\nš Task result:");
println!(" State: {:?}", task.state);
if let Some(result) = task.result {
println!(" Output: {}", result);
}
}
Ok(())
}
```
## Running It
```bash
# In terminal 1: Keep the town running
tt start
# In terminal 2: Run your code
cargo run
```
## What Happens
1. **Town connects** to the existing town (and its Redis)
2. **Agent spawns** with state `Starting` ā `Idle`
3. **Task creates** with state `Pending`
4. **Assignment** sends a `TaskAssign` message to agent's inbox
5. **Agent receives** the message (in a real setup, Claude would process it)
6. **Polling** checks agent state every 5 seconds
7. **Completion** when agent returns to `Idle`
## The Message Flow
```
Your Code Redis Agent
ā ā ā
ā spawn_agent() ā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāŗā ā
ā ā SET tt:<town>:agent:xxx ā
ā ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā ā ā
ā assign(task) ā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāŗā ā
ā ā SET tt:<town>:task:yyy ā
ā ā RPUSH tt:<town>:inbox:xxx ā
ā ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā ā ā
ā ā BLPOP tt:<town>:inbox:xxx ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā ā ā
ā state() ā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāŗā ā
ā ā GET tt:<town>:agent:xxx ā
āāāāāāāāāāāāāāāāāāāāāāāāāāā ā ā
```
## Simulating the Agent
In a real workflow, Claude (or another AI) receives the task. For testing, you can simulate completion:
```bash
# In redis-cli (replace <town> with your town name)
redis-cli -s ./redis.sock
# Get the inbox message
LPOP tt:<town>:inbox:550e8400-e29b-41d4-a716-446655440000
# Update agent state to idle
# (In practice, the agent process does this)
```
## Key Takeaways
1. **Towns manage Redis** ā You don't need to start it manually
2. **Agents are stateful** ā Their state persists in Redis
3. **Tasks are tracked** ā Full lifecycle from pending to complete
4. **Messages are reliable** ā Redis lists ensure delivery
## Next Steps
- [Multi-Agent Coordination](./multi-agent.md) ā Coordinate multiple agents
- [Task Pipelines](./pipelines.md) ā Chain tasks together