1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use anyhow::Result;
use clap::{Parser, Subcommand};
use std::path::PathBuf;
use tama::cmd;
use tama::skill::lint::lint_agent;
use tama::skill::parser::{parse_agent, parse_skill};
#[derive(Parser)]
#[command(
name = "tama",
about = "Markdown-native agent framework — write agents in .md, run in Docker"
)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum RunsCommand {
/// Show span tree for a run
Show {
trace_id: String,
/// Include full LLM prompts and responses
#[arg(long)]
llm: bool,
},
/// Re-run with the same task
Retry { trace_id: String },
/// Open browser dashboard (runs list + span graph)
Serve,
}
#[derive(Subcommand)]
enum Commands {
/// Create a new tama project
///
/// Creates a project directory with tama.toml, .env.example,
/// and a starter react agent. Name must be kebab-case.
///
/// Example:
/// tama init my-project
Init { name: String },
/// Add an agent or skill scaffold to the current project
///
/// AGENT PATTERNS:
/// react Tool-use loop until finish. Core workhorse.
/// critic draft → critique → refine.
/// orchestrator LLM decomposes → parallel workers → LLM merges.
/// parallel Fixed list of agents run simultaneously.
/// fsm Finite state machine: states + word-based routing.
/// scatter map → parallel workers → reduce. Worker declared in YAML.
/// debate position-a → position-b → judge synthesizes.
/// reflexion act → evaluate → reflect → loop.
/// constitutional generate → check principles → revise.
/// chain-of-verification generate → verify claims → revise.
/// plan-execute plan → execute → verify → loop.
/// best-of-n scatter N variants → judge picks best.
///
/// SKILL:
/// skill Create a SKILL.md (Anthropic-compatible tool definition).
///
/// Names must be kebab-case. Examples:
/// tama add react my-agent
/// tama add critic essay-critic
/// tama add skill search-web
Add { pattern: String, name: String },
/// Collect skill dependencies and build Docker image
///
/// Reads tama.toml, scans all SKILL.md files for tama.depends.apt/uv/bins,
/// and builds a distroless Docker image with all dependencies baked in.
///
/// Requires Docker to be running.
Brew,
/// Validate an agent directory (checks required prompt files exist)
///
/// Example:
/// tama lint agents/my-agent
Lint { path: PathBuf },
/// List available models from configured providers
Models,
/// Run a task through the agent graph, recording to .tama/runs.duckdb
///
/// Example:
/// tama run "summarise the README"
/// tama run --agent my-agent "write a blog post about Rust"
Run {
task: String,
/// Override the entrypoint agent
#[arg(long)]
agent: Option<String>,
/// Enable interactive step-through debugger (pause before/after each LLM call)
#[arg(long)]
debug: bool,
/// Only pause at this agent (may be repeated; default: pause at all agents)
#[arg(long = "break", value_name = "AGENT")]
breakpoints: Vec<String>,
},
/// Inspect past runs recorded in .tama/runs.duckdb
///
/// Examples:
/// tama runs list recent runs
/// tama runs show <id> span tree with timing
/// tama runs show <id> --llm include full prompts and responses
/// tama runs retry <id> re-run with same task
Runs {
#[command(subcommand)]
cmd: Option<RunsCommand>,
},
/// Open an interactive browser preview of the agent graph.
View,
/// Parse and print a SKILL.md (debug)
#[command(hide = true)]
Skill { path: PathBuf },
/// Parse and print an AGENT.md (debug)
#[command(hide = true)]
Agent { path: PathBuf },
}
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
match cli.command {
Commands::Init { name } => cmd::init::run(&name)?,
Commands::Add { pattern, name } => cmd::add::run(&pattern, &name)?,
Commands::Brew => cmd::brew::run()?,
Commands::Lint { path } => {
lint_agent(&path)?;
println!("ok");
}
Commands::Run {
task,
agent,
debug,
breakpoints,
} => cmd::run::run(&task, agent.as_deref(), debug, breakpoints).await?,
Commands::Runs { cmd } => match cmd {
None => cmd::runs::list()?,
Some(RunsCommand::Show { trace_id, llm }) => cmd::runs::show(&trace_id, llm)?,
Some(RunsCommand::Retry { trace_id }) => cmd::runs::retry(&trace_id).await?,
Some(RunsCommand::Serve) => cmd::runs::serve().await?,
},
Commands::Models => cmd::models::run().await?,
Commands::View => cmd::view::run().await?,
Commands::Skill { path } => println!("{:#?}", parse_skill(&path)?),
Commands::Agent { path } => println!("{:#?}", parse_agent(&path)?),
}
Ok(())
}