use std::collections::{HashMap, HashSet};
use serde::{Deserialize, Serialize};
use once_cell::sync::Lazy;
use std::sync::RwLock;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolPersonality {
pub name: String,
pub programmer: String,
pub description: String,
pub tools: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub environment: Option<HashMap<String, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub philosophy: Option<String>,
}
impl ToolPersonality {
pub fn new(
name: impl Into<String>,
programmer: impl Into<String>,
description: impl Into<String>,
tools: Vec<String>,
) -> Self {
Self {
name: name.into(),
programmer: programmer.into(),
description: description.into(),
tools,
environment: None,
philosophy: None,
}
}
pub fn with_philosophy(mut self, philosophy: impl Into<String>) -> Self {
self.philosophy = Some(philosophy.into());
self
}
pub fn with_environment(mut self, env: HashMap<String, String>) -> Self {
self.environment = Some(env);
self
}
}
pub struct PersonalityRegistry {
personalities: HashMap<String, ToolPersonality>,
active_personality: Option<String>,
}
impl PersonalityRegistry {
pub fn new() -> Self {
Self {
personalities: HashMap::new(),
active_personality: None,
}
}
pub fn register(&mut self, personality: ToolPersonality) {
self.personalities.insert(personality.name.clone(), personality);
}
pub fn get(&self, name: &str) -> Option<&ToolPersonality> {
self.personalities.get(name)
}
pub fn list(&self) -> Vec<&ToolPersonality> {
self.personalities.values().collect()
}
pub fn set_active(&mut self, name: &str) -> Result<(), String> {
if !self.personalities.contains_key(name) {
return Err(format!("Personality '{}' not found", name));
}
self.active_personality = Some(name.to_string());
if let Some(personality) = self.personalities.get(name) {
if let Some(env) = &personality.environment {
for (key, value) in env {
std::env::set_var(key, value);
}
}
}
Ok(())
}
pub fn get_active(&self) -> Option<&ToolPersonality> {
self.active_personality
.as_ref()
.and_then(|name| self.personalities.get(name))
}
pub fn get_active_tools(&self) -> HashSet<String> {
self.get_active()
.map(|p| p.tools.iter().cloned().collect())
.unwrap_or_default()
}
}
static REGISTRY: Lazy<RwLock<PersonalityRegistry>> = Lazy::new(|| {
let mut registry = PersonalityRegistry::new();
register_default_personalities(&mut registry);
RwLock::new(registry)
});
const ESSENTIAL_TOOLS: &[&str] = &["read", "write", "edit", "tree", "bash", "think"];
const UNIX_TOOLS: &[&str] = &["grep", "find_files", "bash", "process", "diff"];
const BUILD_TOOLS: &[&str] = &["bash", "npx", "uvx", "process"];
const VERSION_CONTROL: &[&str] = &["git_search", "diff"];
const AI_TOOLS: &[&str] = &["agent", "consensus", "critic", "think"];
const SEARCH_TOOLS: &[&str] = &["search", "symbols", "grep", "git_search"];
const DATABASE_TOOLS: &[&str] = &["sql_query", "sql_search", "graph_add", "graph_query"];
fn register_default_personalities(registry: &mut PersonalityRegistry) {
registry.register(
ToolPersonality::new(
"guido",
"Guido van Rossum",
"Python's BDFL - readability counts",
vec![ESSENTIAL_TOOLS, &["uvx", "jupyter", "multi_edit", "symbols", "rules"], AI_TOOLS, SEARCH_TOOLS]
.concat()
.iter()
.map(|s| s.to_string())
.collect(),
)
.with_philosophy("There should be one-- and preferably only one --obvious way to do it.")
.with_environment(HashMap::from([
("PYTHONPATH".to_string(), ".".to_string()),
("PYTEST_ARGS".to_string(), "-xvs".to_string()),
])),
);
registry.register(
ToolPersonality::new(
"matz",
"Yukihiro Matsumoto",
"Ruby creator - optimize for developer happiness",
vec![ESSENTIAL_TOOLS, &["npx", "symbols", "batch", "todo"], SEARCH_TOOLS]
.concat()
.iter()
.map(|s| s.to_string())
.collect(),
)
.with_philosophy("Ruby is designed to make programmers happy.")
.with_environment(HashMap::from([
("RUBY_VERSION".to_string(), "3.0".to_string()),
("BUNDLE_PATH".to_string(), "vendor/bundle".to_string()),
])),
);
registry.register(
ToolPersonality::new(
"brendan",
"Brendan Eich",
"JavaScript creator - dynamic and flexible",
vec![ESSENTIAL_TOOLS, &["npx", "watch", "symbols", "todo", "rules"], BUILD_TOOLS, SEARCH_TOOLS]
.concat()
.iter()
.map(|s| s.to_string())
.collect(),
)
.with_philosophy("Always bet on JS.")
.with_environment(HashMap::from([
("NODE_ENV".to_string(), "development".to_string()),
("NPM_CONFIG_LOGLEVEL".to_string(), "warn".to_string()),
])),
);
registry.register(
ToolPersonality::new(
"dennis",
"Dennis Ritchie",
"C creator - close to the metal",
vec![ESSENTIAL_TOOLS, &["symbols", "content_replace"], UNIX_TOOLS]
.concat()
.iter()
.map(|s| s.to_string())
.collect(),
)
.with_philosophy("UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity.")
.with_environment(HashMap::from([
("CC".to_string(), "gcc".to_string()),
("CFLAGS".to_string(), "-Wall -O2".to_string()),
])),
);
registry.register(
ToolPersonality::new(
"bjarne",
"Bjarne Stroustrup",
"C++ creator - zero-overhead abstractions",
vec![ESSENTIAL_TOOLS, &["symbols", "multi_edit", "content_replace"], UNIX_TOOLS, BUILD_TOOLS]
.concat()
.iter()
.map(|s| s.to_string())
.collect(),
)
.with_philosophy("C++ is designed to allow you to express ideas.")
.with_environment(HashMap::from([
("CXX".to_string(), "g++".to_string()),
("CXXFLAGS".to_string(), "-std=c++20 -Wall".to_string()),
])),
);
registry.register(
ToolPersonality::new(
"linus",
"Linus Torvalds",
"Linux & Git creator - pragmatic excellence",
vec![ESSENTIAL_TOOLS, &["git_search", "diff", "content_replace", "critic"], UNIX_TOOLS]
.concat()
.iter()
.map(|s| s.to_string())
.collect(),
)
.with_philosophy("Talk is cheap. Show me the code.")
.with_environment(HashMap::from([
("KERNEL_VERSION".to_string(), "6.0".to_string()),
("GIT_AUTHOR_NAME".to_string(), "Linus Torvalds".to_string()),
])),
);
registry.register(
ToolPersonality::new(
"graydon",
"Graydon Hoare",
"Rust creator - memory safety without GC",
vec![ESSENTIAL_TOOLS, &["symbols", "multi_edit", "critic", "todo"], BUILD_TOOLS]
.concat()
.iter()
.map(|s| s.to_string())
.collect(),
)
.with_philosophy("Memory safety without garbage collection, concurrency without data races.")
.with_environment(HashMap::from([
("RUST_BACKTRACE".to_string(), "1".to_string()),
("CARGO_HOME".to_string(), "~/.cargo".to_string()),
])),
);
registry.register(
ToolPersonality::new(
"andrej",
"Andrej Karpathy",
"AI educator & Tesla AI director",
vec![ESSENTIAL_TOOLS, AI_TOOLS, &["uvx", "jupyter", "symbols", "watch"], SEARCH_TOOLS]
.concat()
.iter()
.map(|s| s.to_string())
.collect(),
)
.with_philosophy("The unreasonable effectiveness of neural networks.")
.with_environment(HashMap::from([
("CUDA_VISIBLE_DEVICES".to_string(), "0".to_string()),
("PYTHONUNBUFFERED".to_string(), "1".to_string()),
])),
);
registry.register(
ToolPersonality::new(
"ilya",
"Ilya Sutskever",
"OpenAI co-founder",
vec![ESSENTIAL_TOOLS, AI_TOOLS, &["uvx", "jupyter", "symbols", "batch"], SEARCH_TOOLS]
.concat()
.iter()
.map(|s| s.to_string())
.collect(),
)
.with_philosophy("AGI is the goal.")
.with_environment(HashMap::from([
("OPENAI_API_KEY".to_string(), "".to_string()),
("PYTORCH_ENABLE_MPS".to_string(), "1".to_string()),
])),
);
registry.register(
ToolPersonality::new(
"carmack",
"John Carmack",
"id Software - Doom & Quake creator",
vec![ESSENTIAL_TOOLS, &["symbols", "multi_edit", "watch", "process"], BUILD_TOOLS, UNIX_TOOLS]
.concat()
.iter()
.map(|s| s.to_string())
.collect(),
)
.with_philosophy("Focus is a matter of deciding what things you're not going to do.")
.with_environment(HashMap::from([
("GL_VERSION".to_string(), "4.6".to_string()),
("VULKAN_SDK".to_string(), "/usr/local/vulkan".to_string()),
])),
);
registry.register(
ToolPersonality::new(
"satoshi",
"Satoshi Nakamoto",
"Bitcoin creator",
vec![ESSENTIAL_TOOLS, &["symbols", "critic", "content_replace"], UNIX_TOOLS, VERSION_CONTROL]
.concat()
.iter()
.map(|s| s.to_string())
.collect(),
)
.with_philosophy("A purely peer-to-peer version of electronic cash.")
.with_environment(HashMap::from([
("BITCOIN_NETWORK".to_string(), "mainnet".to_string()),
("RPC_USER".to_string(), "bitcoin".to_string()),
])),
);
registry.register(
ToolPersonality::new(
"vitalik",
"Vitalik Buterin",
"Ethereum creator",
vec![ESSENTIAL_TOOLS, &["symbols", "multi_edit", "todo"], BUILD_TOOLS, SEARCH_TOOLS]
.concat()
.iter()
.map(|s| s.to_string())
.collect(),
)
.with_philosophy("Decentralized world computer.")
.with_environment(HashMap::from([
("ETH_NETWORK".to_string(), "mainnet".to_string()),
("WEB3_PROVIDER".to_string(), "https://mainnet.infura.io".to_string()),
])),
);
registry.register(
ToolPersonality::new(
"hanzo",
"Hanzo AI Default",
"Balanced productivity and quality",
vec![
ESSENTIAL_TOOLS,
AI_TOOLS,
SEARCH_TOOLS,
BUILD_TOOLS,
VERSION_CONTROL,
&["multi_edit", "symbols", "watch", "todo", "rules", "jupyter", "uvx", "npx"]
]
.concat()
.iter()
.map(|s| s.to_string())
.collect(),
)
.with_philosophy("AI-powered development at scale.")
.with_environment(HashMap::from([
("HANZO_MODE".to_string(), "enabled".to_string()),
("AI_ASSIST".to_string(), "true".to_string()),
])),
);
registry.register(
ToolPersonality::new(
"10x",
"10x Engineer",
"Maximum productivity, all tools enabled",
vec![
ESSENTIAL_TOOLS,
AI_TOOLS,
SEARCH_TOOLS,
BUILD_TOOLS,
VERSION_CONTROL,
DATABASE_TOOLS,
UNIX_TOOLS,
&["multi_edit", "symbols", "watch", "todo", "rules", "jupyter",
"uvx", "npx", "batch", "consensus", "llm", "agent"]
]
.concat()
.iter()
.map(|s| s.to_string())
.collect(),
)
.with_philosophy("Move fast and optimize everything.")
.with_environment(HashMap::from([
("PRODUCTIVITY".to_string(), "MAX".to_string()),
("TOOLS".to_string(), "ALL".to_string()),
])),
);
registry.register(
ToolPersonality::new(
"minimal",
"Minimalist",
"Just the essentials",
ESSENTIAL_TOOLS.iter().map(|s| s.to_string()).collect(),
)
.with_philosophy("Less is more.")
.with_environment(HashMap::from([
("MINIMAL_MODE".to_string(), "true".to_string()),
])),
);
}
pub mod api {
use super::*;
pub fn register(personality: ToolPersonality) -> Result<(), String> {
REGISTRY.write()
.map_err(|_| "Failed to acquire write lock")?
.register(personality);
Ok(())
}
pub fn get(name: &str) -> Option<ToolPersonality> {
REGISTRY.read().ok()?.get(name).cloned()
}
pub fn list() -> Vec<ToolPersonality> {
REGISTRY.read()
.ok()
.map(|r| r.list().into_iter().cloned().collect())
.unwrap_or_default()
}
pub fn set_active(name: &str) -> Result<(), String> {
REGISTRY.write()
.map_err(|_| "Failed to acquire write lock")?
.set_active(name)
}
pub fn get_active() -> Option<ToolPersonality> {
REGISTRY.read().ok()?.get_active().cloned()
}
pub fn get_active_tools() -> HashSet<String> {
REGISTRY.read()
.ok()
.map(|r| r.get_active_tools())
.unwrap_or_default()
}
pub fn activate_from_env() -> Option<String> {
let mode_name = std::env::var("HANZO_MODE")
.or_else(|_| std::env::var("PERSONALITY"))
.or_else(|_| std::env::var("MODE"))
.ok()?;
set_active(&mode_name).ok()?;
Some(mode_name)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_personality_creation() {
let personality = ToolPersonality::new(
"test",
"Test Programmer",
"A test personality",
vec!["read".to_string(), "write".to_string()],
);
assert_eq!(personality.name, "test");
assert_eq!(personality.programmer, "Test Programmer");
assert_eq!(personality.tools.len(), 2);
}
#[test]
fn test_registry() {
let mut registry = PersonalityRegistry::new();
let personality = ToolPersonality::new(
"test",
"Test Programmer",
"A test personality",
vec!["read".to_string()],
);
registry.register(personality.clone());
assert!(registry.get("test").is_some());
assert_eq!(registry.list().len(), 1);
assert!(registry.set_active("test").is_ok());
assert_eq!(registry.get_active().map(|p| p.name.clone()), Some("test".to_string()));
}
#[test]
fn test_global_api() {
let personalities = api::list();
assert!(personalities.len() > 0);
assert!(api::get("guido").is_some());
assert!(api::get("linus").is_some());
assert!(api::get("hanzo").is_some());
}
}