Zeroclaw — технический обзор
Repo: https://github.com/zeroclaw-labs/zeroclaw
Язык: Rust (edition 2021, MSRV 1.87)
Лицензия: MIT / Apache-2.0
Локальная копия: ~/zeroclaw/
Что это
Zeroclaw — autonomous agent runtime на Rust. Единый бинарник, trait-driven архитектура, заточен под минимальное потребление ресурсов (<5MB RAM). Позиционируется как универсальный фреймворк: от серверов до embedded-устройств (ARM, RISC-V).
Ключевая идея — всё через traits + factory: провайдеры, каналы, инструменты, память, безопасность, рантайм. Плагины регистрируют tools и hooks через PluginApi.
Архитектура (модули)
src/
├── agent/ # Оркестрация: loop, session, prompt, research
├── providers/ # LLM-провайдеры (не интересно — мульти-провайдер)
├── channels/ # Транспорт (Telegram, Discord, Slack и т.д.)
├── tools/ # Инструменты + MCP-клиент
├── memory/ # Persistence: SQLite, Postgres, embeddings
├── security/ # Sandbox, pairing, allowlists
├── gateway/ # HTTP/WebSocket сервер (Axum)
├── runtime/ # Адаптеры: native, docker, WASM
├── peripherals/ # Hardware (STM32, Raspberry Pi GPIO)
├── plugins/ # Система плагинов (tools + hooks)
├── observability/ # Метрики, events, tracing
├── coordination/ # Multi-agent message bus
├── hooks/ # Lifecycle event handlers
└── config/ # Конфигурация (TOML)
Ключевые абстракции
Tool trait
#[async_trait]
pub trait Tool: Send + Sync {
fn name(&self) -> &str;
fn description(&self) -> &str;
fn parameters_schema(&self) -> serde_json::Value;
async fn execute(&self, args: serde_json::Value) -> Result<ToolResult>;
fn spec(&self) -> ToolSpec { /* auto from name/desc/schema */ }
}
pub struct ToolResult {
pub success: bool,
pub output: String,
pub error: Option<String>,
}70+ встроенных инструментов: shell, file r/w, web fetch, memory, cron, browser, PDF/XLSX/DOCX, hardware GPIO, delegation, и т.д.
Memory trait
#[async_trait]
pub trait Memory: Send + Sync {
async fn store(&self, key: &str, content: &str, category: MemoryCategory, session_id: Option<&str>) -> Result<()>;
async fn recall(&self, query: &str, limit: usize, session_id: Option<&str>) -> Result<Vec<MemoryEntry>>;
async fn get(&self, key: &str) -> Result<Option<MemoryEntry>>;
async fn forget(&self, key: &str) -> Result<bool>;
async fn reindex(&self, ...) -> Result<usize>;
}
pub enum MemoryCategory { Core, Daily, Conversation, Custom(String) }SQLite-бэкенд с гибридным поиском: vector (cosine similarity на embeddings) + keyword (FTS5 BM25), weighted fusion 0.7/0.3. Есть time decay (7 дней half-life) и Core boost (+0.3 score).
Hook система
Два типа хуков:
Void hooks — параллельные, fire-and-forget:
on_session_start/endon_llm_input/outputon_after_tool_callon_message_senton_heartbeat_tick
Modifying hooks — последовательные по приоритету, могут отменить операцию:
before_prompt_build— модификация промптаbefore_llm_call— модификация сообщений/моделиbefore_tool_call— модификация имени/аргументов тулаon_message_received— модификация входящего сообщенияon_message_sending— модификация исходящегоbefore_compaction/after_compaction— контроль сжатия истории
pub enum HookResult<T> {
Continue(T), // продолжить с (возможно изменёнными) данными
Cancel(String), // отменить операцию
}Plugin система
pub trait Plugin: Send + Sync {
fn manifest(&self) -> &PluginManifest;
fn register(&self, api: &mut PluginApi) -> Result<()>;
}
// PluginApi позволяет:
api.register_tool(Box::new(MyTool {}));
api.register_hook(Box::new(MyHook {}));
api.plugin_config(); // JSON config из TOML
api.logger(); // scoped loggerMCP-клиент
Полная реализация MCP (Model Context Protocol):
- JSON-RPC 2.0 поверх stdio / HTTP / SSE транспортов
- Автообнаружение tools через
tools/list - Префикс
server_name__tool_nameдля избежания коллизий - Timeout: 180s по умолчанию (max 600s)
- Non-fatal: сбой сервера логируется и пропускается
Observer (observability)
pub trait Observer: Send + Sync + 'static {
fn record_event(&self, event: &ObserverEvent);
fn record_metric(&self, metric: &ObserverMetric);
}
// Events: AgentStart, LlmRequest, LlmResponse, ToolCallStart, ToolCall,
// AgentEnd, ChannelMessage, Error, HeartbeatTick
// Metrics: RequestLatency, TokensUsed, ActiveSessions, QueueDepthБэкенды: LogObserver, Prometheus, OpenTelemetry, CostObserver, MultiObserver.
Session management
pub trait SessionManager: Send + Sync {
async fn get_history(&self, session_id: &str) -> Result<Vec<ChatMessage>>;
async fn set_history(&self, session_id: &str, history: Vec<ChatMessage>) -> Result<()>;
async fn delete(&self, session_id: &str) -> Result<()>;
async fn cleanup_expired(&self) -> Result<usize>;
}
pub enum AgentSessionStrategy {
Main, // одна сессия на всех
PerChannel, // по каналу
PerSender, // по (канал, отправитель)
}In-memory (TTL) и SQLite реализации.
Channel trait (транспорт)
#[async_trait]
pub trait Channel: Send + Sync {
fn name(&self) -> &str;
async fn send(&self, message: &SendMessage) -> Result<()>;
async fn listen(&self, tx: mpsc::Sender<ChannelMessage>) -> Result<()>;
// Draft message updates (streaming в Telegram/Discord)
fn supports_draft_updates(&self) -> bool;
async fn send_draft(&self, message: &SendMessage) -> Result<Option<String>>;
async fn update_draft(&self, recipient: &str, message_id: &str, text: &str) -> Result<Option<String>>;
async fn finalize_draft(&self, recipient: &str, message_id: &str, text: &str) -> Result<()>;
// Approval prompts для tool calls
async fn send_approval_prompt(&self, recipient: &str, request_id: &str, tool_name: &str, arguments: &Value, thread_ts: Option<String>) -> Result<()>;
}Security
Sandboxtrait:wrap_command()для isolating shell commands (landlock, bubblewrap)- Pairing guard для HTTP gateway
- Credential scrubbing: regex-based redaction из tool output перед отправкой LLM
- Deny-by-default allowlists
Agent Loop (оркестрация)
Основной цикл:
- Получить сообщение из канала
- Resolve session (Main / PerChannel / PerSender)
- Загрузить релевантные memories (hybrid search)
- Построить system prompt
- Вызвать LLM через Provider
- Если ответ содержит tool_calls → выполнить tools (параллельно или последовательно)
- Loop detection: 3 стратегии:
- No-progress repeat (один tool+args+output 3+ раз) → warning → hard stop
- Ping-pong (A→B→A→B 2+ цикла) → warning
- Failure streak (один tool фейлит 3+ раз) → warning
- Credential scrubbing на выходе tools
- Добавить результаты в историю, вернуться к шагу 5
- Финальный ответ → отправить в канал
- Обновить memory и session
History compaction:
- Перед компакцией — извлечь durable facts в Core memories
- Max 12,000 символов для summarization, max 2,000 summary
- Сохраняет 20 последних не-system сообщений
- Никогда не разрезает пару assistant(tool_calls) → tool results
Что полезно для tagopi
Сравнение с текущим состоянием tagopi (Go, Telegram↔Claude CLI bridge)
1. Hook/lifecycle система — высокий приоритет
Tagopi сейчас: монолитный handleMessage → runTurn без точек расширения.
Zeroclaw предлагает: чёткие lifecycle hooks с двумя режимами (void / modifying). Это даёт:
before_tool_call— логирование, фильтрация опасных toolson_message_received— пре-процессинг входящих (команды, авто-перевод, фильтры)on_message_sending— пост-процессинг ответов (форматирование, цензура)on_after_tool_call— аналитика по использованию tools
Реализация для tagopi: Не нужен полноценный plugin API. Достаточно:
type Hook interface {
// Void hooks
OnToolStart(ctx context.Context, name string, args json.RawMessage)
OnToolDone(ctx context.Context, name string, result string, dur time.Duration)
OnTurnComplete(ctx context.Context, sessionKey string, result TurnResult)
// Modifying hooks
BeforePrompt(ctx context.Context, prompt string) (string, error)
BeforeResponse(ctx context.Context, text string) (string, error)
}2. Loop detection — высокий приоритет
Tagopi сейчас: нет защиты от зацикливания. Claude CLI имеет свой max_turns, но внутри одного turn agent может зациклиться на tool calls.
Zeroclaw: три стратегии — no-progress repeat, ping-pong, failure streak. Сначала inject warning в промпт, потом hard stop.
Для tagopi это менее актуально, т.к. Claude CLI сам управляет tool loop. Но можно добавить:
- Timeout на весь turn (уже есть IdleTimeout, но это per-output, а не global)
- Счётчик tool calls в одном turn с hard limit
3. Observability — средний приоритет
Tagopi сейчас: slog.Info/Error в main.go.
Zeroclaw: Observer trait с events и metrics, pluggable бэкенды.
Для tagopi достаточно:
type Observer interface {
RecordEvent(event Event)
}
type Event struct {
Type string // "tool_call", "turn_complete", "error"
Tool string
Duration time.Duration
Success bool
Tokens TokenUsage
}Даже простой файловый лог events даст полезную аналитику.
4. MCP-клиент (нативный) — средний приоритет
Tagopi сейчас: Claude CLI сам управляет MCP серверами через --mcp-config.
Zeroclaw: собственный MCP-клиент (JSON-RPC 2.0 поверх stdio/HTTP/SSE).
Для tagopi: пока не критично, т.к. CLI справляется. Но если перейти с CLI на прямой API — понадобится. Архитектура zeroclaw (transport abstraction + registry + prefix naming) — хороший референс.
5. Memory система — низкий/средний приоритет
Tagopi сейчас: session store (SQLite) хранит только session mapping и token usage.
Zeroclaw: полноценная semantic memory с embeddings, hybrid search, categories, time decay.
Для tagopi интересны:
- Персистентная история разговоров (tagopi делегирует это Claude CLI через
--session-id) - Auto-save ключевых фактов из разговора
- Recall при старте нового turn
6. Draft message updates — уже реализовано
Tagopi statusMsg уже делает то, что zeroclaw называет “draft updates”: progressive message editing с throttling. Реализация в tagopi даже лучше заточена под Telegram (escape, split, fallback).
7. Session strategies — низкий приоритет
Tagopi сейчас: per-chat/thread (единственный нужный вариант).
Zeroclaw: Main / PerChannel / PerSender. Добавлять другие стратегии в tagopi пока нет смысла.
8. Credential scrubbing — хорошая идея
Zeroclaw: regex-based redaction (token=xxx, api_key="...") из tool output перед LLM.
Для tagopi: полезно добавить в пост-процессинг ответов, хотя бы базовый regex.
9. Approval system — интересно
Zeroclaw: send_approval_prompt — канал может запросить у пользователя подтверждение перед выполнением tool.
Для tagopi: можно реализовать inline-кнопки в Telegram для опасных операций (delete files, git push и т.д.).
Что НЕ интересно (по запросу)
- Мульти-провайдеры (20+ LLM-бэкендов) — tagopi работает только с Claude
- Мульти-каналы (27+ реализаций Channel) — tagopi = Telegram only
- Provider capability negotiation / tool format conversion
- Model routing, fallback, quota management
- Gateway HTTP API / OpenAI-compatible endpoints
- Hardware peripherals
- WASM runtime
- Multi-agent coordination
Архитектурные принципы (из CLAUDE.md zeroclaw)
Полезные для любого проекта:
- KISS: простой control flow, explicit matching, localized errors
- YAGNI: никаких спекулятивных фич без конкретного use case
- Fail Fast: явные ошибки, никогда silent fallback
- Secure by Default: deny-by-default, least privilege
- Determinism: воспроизводимые билды и поведение
Резюме
Zeroclaw — зрелый, хорошо спроектированный фреймворк с trait-driven архитектурой. Для tagopi наиболее ценны:
- Hooks — точки расширения в lifecycle (реализуемо за день)
- Loop detection — защита от зацикливания (частично покрыто CLI)
- Observability — structured events для аналитики
- Credential scrubbing — базовая гигиена безопасности
- Approval flow — inline Telegram кнопки для подтверждения
Остальное (мульти-провайдеры, мульти-каналы, semantic memory) — overkill для текущего scope tagopi.