Skip to content

Trait System

AgentZero’s core principle is that every subsystem is a trait. This means you can swap implementations without touching the orchestration layer.

SubsystemTraitShips WithExtension
AI ModelsProviderOpenAI-compatible (OpenRouter, OpenAI, Anthropic, Ollama)Implement Provider trait
MemoryMemoryStoreSQLite, Turso/libsqlImplement MemoryStore trait
ToolsTool50+ built-in (file I/O, shell, networking, browser, delegation, memory, git, SOP, cron, hardware)Implement Tool trait, WASM plugin, or process plugin
ChannelsChannelTelegram, Discord, Slack, MattermostImplement Channel trait
SecurityToolSecurityPolicy + CapabilitySetAllowlists, OTP, audit, estop, leak guard, syscall anomaly; opt-in capability grants via [[capabilities]]Config-driven ([security.*] + [[capabilities]])
ObservabilityConfig-drivenRuntime traces, OpenTelemetry export[observability] config
RuntimeOrchestratorNative single-process[runtime] config (native/docker)
PluginsWASM sandboxwasmi interpreter (wasmtime JIT optional).wasm modules with manifest.json
SkillsSkill registryBuilt-in skillforge + SOP engineInstall from local/remote/git
IdentityConfig-drivenMarkdown, JSON[identity] config
GatewayHTTP serviceAxum-based REST APIEndpoint handlers
Agent StoreAgentStoreApiEncrypted JSON persistence (AgentStore)Implement AgentStoreApi trait
CostTrackerToken + USD tracking with limits[cost] config
PrivacyConfig-drivenNoise Protocol E2E encryption, sealed envelopes, key rotation, privacy boundaries[privacy] config

ToolSecurityPolicy (in agentzero-tools) is the runtime representation of all permission decisions. It carries two parallel enforcement paths:

  • Legacy booleans (enable_git, enable_web_search, etc.) — active when no [[capabilities]] array is configured. All existing configs use this path.
  • CapabilitySet (Sprint 86) — opt-in fine-grained grants. When at least one [[capabilities]] entry is present, CapabilitySet::allows_tool() replaces the boolean checks. The two paths are mutually exclusive per config: CapabilitySet::is_empty() determines which path is active.

See the config reference for TOML examples and the migration guide.

The Provider trait abstracts AI model access:

#[async_trait]
pub trait Provider: Send + Sync {
async fn complete(&self, request: CompletionRequest) -> Result<CompletionResponse>;
fn name(&self) -> &str;
}

Ships with an OpenAI-compatible implementation that works with OpenRouter, OpenAI, Anthropic, Ollama, and any /v1/chat/completions endpoint.

The MemoryStore trait abstracts conversation persistence:

#[async_trait]
pub trait MemoryStore: Send + Sync {
async fn append(&self, entry: MemoryEntry) -> Result<()>;
async fn recent(&self, limit: usize) -> Result<Vec<MemoryEntry>>;
async fn search(&self, query: &str, limit: usize) -> Result<Vec<MemoryEntry>>;
}

Ships with SQLite (default) and Turso/libsql (feature-gated).

The Tool trait abstracts agent capabilities:

#[async_trait]
pub trait Tool: Send + Sync {
fn name(&self) -> &'static str;
fn description(&self) -> &'static str { "" }
fn input_schema(&self) -> Option<serde_json::Value> { None }
async fn execute(&self, input: &str, ctx: &ToolContext) -> anyhow::Result<ToolResult>;
}

All 58+ built-in tools implement this trait with input_schema() for structured tool-use APIs. WASM plugins and process plugins are wrapped in Tool adapters. MCP servers are registered as first-class tools — each remote tool gets its own McpIndividualTool with a namespaced name (mcp__{server}__{tool}), the tool’s real description, and its real input schema. Dynamic tools created at runtime also implement this trait and persist across sessions.

The ToolSource trait enables mid-session tool registration:

pub trait ToolSource: Send + Sync {
fn additional_tools(&self) -> Vec<Box<dyn Tool>>;
}

Implemented by DynamicToolRegistry — when an agent creates a new tool via tool_create, the ToolSource makes it visible to the agent on the next tool loop iteration without restarting.

Each trait lives in agentzero-core. Implementations live in their own crates:

agentzero-core # Traits, types, security, delegation, routing
├── agentzero-providers # Provider implementations
├── agentzero-storage # MemoryStore + encrypted KV (absorbed crypto, memory)
├── agentzero-tools # 50+ tool implementations (absorbed autonomy, hardware, cron, skills)
├── agentzero-channels # Channel implementations (absorbed leak-guard)
├── agentzero-plugins # WASM plugin host (wasmi default, wasmtime optional)
└── agentzero-infra # Orchestration + runtime (absorbed runtime)

This ensures the core never depends on infrastructure — only the reverse.

Security is not a trait — it’s a policy layer enforced at construction time:

  1. Tool instances are created with their security config baked in
  2. Tools validate every call against allowlists, path restrictions, and size limits
  3. The agent orchestrator doesn’t need to know about security — it’s already enforced
User message → Agent → Tool::execute() → [security policy check] → actual execution

If a policy check fails, the tool returns an error. The agent sees the error and can adjust.