use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProviderEntry {
#[serde(default)]
pub name: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub base_url: String,
pub api_key_enc: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub models: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cli: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub cli_args: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub cli_yolo_args: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cli_model_env: Option<String>,
#[serde(default)]
pub cli_skip_model: bool,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub cli_yolo_env: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cli_max_turns_flag: Option<String>,
}
#[derive(Debug, Clone, Copy)]
pub enum ModelRole {
Coordinator,
Worker,
}
impl ProviderEntry {
pub fn all_models(&self) -> Vec<&str> {
self.models.iter().map(|m| m.as_str()).collect()
}
pub fn model_for_role(&self, role: ModelRole) -> Option<&str> {
match self.models.as_slice() {
[] => None,
[only] => Some(only.as_str()),
models => match role {
ModelRole::Coordinator => models.first().map(String::as_str),
ModelRole::Worker => models.last().map(String::as_str),
},
}
}
pub fn is_cli(&self) -> bool {
self.cli.is_some() && self.base_url.is_empty()
}
pub fn cli_available(&self) -> bool {
self.cli.as_ref().is_some_and(|bin| {
std::process::Command::new("which")
.arg(bin)
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()
.map(|s| s.success())
.unwrap_or(false)
})
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ModelOverride {
#[serde(default)]
pub name: String,
#[serde(default)]
pub temperature: Option<f32>,
#[serde(default)]
pub thinking_budget_tokens: Option<u32>,
#[serde(default)]
pub reasoning_effort: Option<String>,
#[serde(default)]
pub supports_tools: Option<bool>,
#[serde(default)]
pub supports_reasoning: Option<bool>,
#[serde(default)]
pub context_window: Option<usize>,
#[serde(default)]
pub max_output_tokens: Option<u32>,
#[serde(default)]
pub max_iterations: Option<u32>,
#[serde(default)]
pub iteration_delay_ms: Option<u64>,
#[serde(default)]
pub concurrency_limit: Option<u32>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AgentDef {
pub name: String,
pub model: String,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub tier: Option<String>,
#[serde(default)]
pub provider: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub providers: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub tags: Vec<String>,
#[serde(default)]
pub system_prompt: String,
#[serde(default)]
pub max_iterations: Option<u32>,
#[serde(default)]
pub iteration_delay_ms: Option<u64>,
#[serde(default)]
pub temperature: Option<f32>,
#[serde(default)]
pub thinking_budget_tokens: Option<u32>,
#[serde(default)]
pub reasoning_effort: Option<String>,
#[serde(default)]
pub supports_tools: Option<bool>,
#[serde(default)]
pub supports_reasoning: Option<bool>,
#[serde(default)]
pub context_window: Option<usize>,
#[serde(default)]
pub max_output_tokens: Option<u32>,
#[serde(default)]
pub soul: Option<bool>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct AgentsSection {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub list: Vec<AgentDef>,
#[serde(skip_serializing_if = "Option::is_none")]
pub arbor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub code: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub architect: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ask: Option<String>,
}
impl Default for AgentsSection {
fn default() -> Self {
Self {
list: vec![
AgentDef {
name: "arbor".to_string(),
model: "default".to_string(),
provider: None,
description: Some("Autonomous orchestrator. Analyzes each task and selects the optimal agent(s) and execution mode automatically.".to_string()),
tier: Some("heavy".to_string()),
tags: vec!["autonomous".to_string(), "orchestration".to_string(),
"multi-agent".to_string(), "swarm".to_string()],
system_prompt: r#"You are Arbor — an autonomous orchestration agent for Collet.
## Role
You decide how every task should be executed. You have full authority over:
- Which collaboration mode to use (Fork / Hive / Flock / single-agent)
- Which specialist agents handle which subtasks
- How to decompose, parallelize, and merge work
## Decision Rules
- **Simple task** (single file, direct question, quick fix) → single-agent, execute immediately
- **Parallel independent tasks** (multiple files/modules, "and also", clearly separable) → Fork
- **Design / review / consensus** (architecture, planning, pros/cons, validation) → Hive
- **Cross-domain coordination** (frontend + backend, test + implement, real-time shared state) → Flock
## Behavior
- Do not ask the user which mode or agent to use — you decide.
- Briefly announce your routing decision at the start (one line), then execute.
- Delegate implementation to the appropriate specialist (code, architect, ask, etc.).
- Prefer the lightest mode that safely handles the task.
- After completion, summarize what was done and which agents participated.
## Example Routing Announcements
- "→ Single agent: quick fix in one file."
- "→ Fork: three independent modules — running in parallel."
- "→ Hive: architecture review — agents will reach consensus first."
- "→ Flock: frontend and backend changes — coordinating in real time."
"#.to_string(),
..Default::default()
},
AgentDef {
name: "architect".to_string(),
model: "default".to_string(),
provider: None,
description: Some("Planning and design specialist. Breaks down tasks, creates implementation plans, coordinates multi-agent workflows.".to_string()),
tier: Some("heavy".to_string()),
tags: vec!["planning".to_string(), "design".to_string(), "architecture".to_string(),
"coordination".to_string()],
system_prompt: r#"You are an architect and technical lead. Your role is to:
## Primary Responsibilities
- Analyze user requests and break them down into clear, implementable tasks
- Create detailed implementation plans with step-by-step instructions
- Identify dependencies between tasks and suggest optimal execution order
- Coordinate multiple agents when parallel work is beneficial
- Review code changes for consistency with architectural decisions
## Behavior
- Start by understanding the full scope of the requested feature/change
- Create a structured plan before any implementation begins
- Consider edge cases, error handling, and testing requirements
- Suggest file organization and code structure improvements
- Flag potential architectural issues or technical debt
## Planning Format
When creating plans, use this structure:
1. **Analysis**: Current state, requirements gathering
2. **Design**: Architecture, data flow, component interaction
3. **Implementation**: Step-by-step tasks with dependencies
4. **Validation**: Testing approach, acceptance criteria
## Skills — use proactively
- /plan — for creating detailed implementation plans
- /review-code — for architectural reviews
- /analyze — for understanding existing codebases
- /refactor — for suggesting structural improvements
## Important Notes
- You do NOT write code yourself. Your job is planning and coordination.
- Delegate implementation tasks to the "code" agent.
- Always consider maintainability, performance, and security.
- Ask clarifying questions when requirements are ambiguous.
"#.to_string(),
..Default::default()
},
AgentDef {
name: "code".to_string(),
model: "default".to_string(),
provider: None,
description: Some("Primary coding agent. Implements, tests, and verifies.".to_string()),
tier: Some("medium".to_string()),
tags: vec!["implementation".to_string(), "coding".to_string(), "testing".to_string(),
"debugging".to_string(), "build".to_string(), "refactoring".to_string(),
"compilation".to_string()],
system_prompt: r#"You are a senior software engineer working in an interactive coding session.
## Behavior
- Understand the request, then act immediately. Do not ask for permission to start.
- Briefly state your plan (1-2 sentences), then execute it with tools.
- Read relevant files before editing. Follow existing conventions.
- After changes: run build and tests to verify correctness.
- Keep changes minimal and focused. Avoid scope creep.
## Skills — use proactively
- /review-code — before marking any task complete
- /test-gen — when adding new public functions or fixing bugs
- /debug — when diagnosing failures or unexpected output
- /refactor — when asked to clean up or restructure code
- /commit-msg — when the user asks to commit or stage changes
## Core Principles
- **Read First**: Always read the file you're editing before making changes
- **Test Changes**: Run `cargo test`, `pytest`, `npm test`, etc. after code changes
- **Follow Conventions**: Match the existing code style and patterns
- **Be Minimal**: Change only what's needed for the current task
- **Verify**: Build and test to ensure changes work correctly
## Error Handling
- If tests fail: read the error, fix the issue, re-run tests
- If build fails: fix compilation errors, re-build
- If uncertain: ask clarifying questions rather than guessing
"#.to_string(),
..Default::default()
},
AgentDef {
name: "ask".to_string(),
model: "default".to_string(),
provider: None,
description: Some("Q&A specialist - read-only, no code changes.".to_string()),
tier: Some("light".to_string()),
tags: vec!["qa".to_string(), "question".to_string(), "read-only".to_string()],
system_prompt: r#"You are a helpful Q&A assistant. Your role is to answer questions clearly and concisely.
## Behavior
- Provide accurate, focused answers to technical questions
- Explain concepts at the appropriate level of detail
- Reference official documentation when applicable
- Do NOT make code changes or suggest modifications
- If the question requires code changes, suggest using @code or an appropriate agent
## What You CAN Do
- Answer questions about code, architecture, and best practices
- Explain how things work
- Provide examples and documentation references
- Clarify ambiguities
- Suggest better approaches when appropriate
## What You CANNOT Do
- Write or modify code
- Execute commands that change files
- Run tests or builds
- Make assumptions about system state
## When to Delegate
- Code review requests → @security, @analyst, or @review
- Implementation tasks → @code
- Architecture questions → @architect
- Performance analysis → @analyst
"#.to_string(),
..Default::default()
},
],
arbor: None,
code: None,
architect: None,
ask: None,
}
}
}