Обзор Claw Code: автономный проект на Rust
Разбор экспериментального проекта Claw Code, который разрабатывается и поддерживается ИИ-агентами на языке Rust без участия человека.
Концепция автономного музея кода
Принцип работы без участия человека
Claw Code работает по принципу замкнутого цикла. Gajae-Code генерирует пул задач на каждую итерацию, LazyCodex выбирает из них приоритетные, а затем оба агента работают параллельно: один пишет код, другой — тесты и документацию. После слияния изменений в ветку main автоматически запускается пайплайн CI/CD, который проверяет сборку, запускает тесты и деплоит обновление на демо-инстанс.
Процесс выглядит так:
bash# Gajae-Code создаёт задачу в issue-трекере
gh issue create --title "Refactor: extract config module" --body "Split src/config.rs into submodules"
# LazyCodex клонирует репо и начинает работу
git clone https://github.com/claw-code/core.git
cd core
cargo test --all-features
Никаких пул-реквестов от людей. Только агенты, которые сами себя эволюционируют.
Роль Gajae-Code и LazyCodex в разработке
Gajae-Code отвечает за архитектурное планирование. Он анализирует текущее состояние репозитория, определяет узкие места и формирует дорожную карту. Его выводы сохраняются в docs/architecture.md и автоматически синхронизируются с документацией проекта.
LazyCodex занимается реализацией. Он читает задачи, созданные Gajae-Code, пишет код, покрывает его тестами и обновляет документацию. Его workflow выглядит примерно так:
toml# .lazycodex/config.toml
[agent]
model = "claude-3-5-sonnet"
max_iterations = 50
auto_commit = true
[project]
repo = "https://github.com/claw-code/core.git"
test_command = "cargo test --all-features"
lint_command = "cargo clippy -- -D warnings"
Оба агента используют ClawKit — собственный SDK на Rust, который абстрагирует работу с Git, тестовыми фреймворками и CI/CD. Благодаря этому ни один human-интервал не требуется: система разворачивается, развивается и поддерживается исключительно ИИ-агентами.
Технический стек и реализация на Rust
Почему выбран Rust для автономного агента
С практической точки зрения, если мы посмотрим на требования к автономному ИИ-агенту, сразу бросаются в глаза три вещи: предсказуемость выполнения, отсутствие внешних зависимостей и минимальный след в памяти. Именно здесь Rust не просто хорош — он почти идеален.
Во-первых, нулевые cost abstractions означают, что агент может работать с файловой системой, сетью и процессами без накладных расходов на сборку мусора. На протяжении пяти лет моя домашняя лаборатория работает на Proxmox, и я видел, как даже лёгкие интерпретируемые языки съедают сотни мегабайт в час просто на поддержание цикла событий. Rust здесь даёт то, что называют «предсказуемостью конфигураций» — вы знаете, что ваш код не начнёт внезапно аллоцировать гигабайты, потому что кто-то забыл про clone().
Во-вторых, borrow checker. Да, он раздражает на первых порах. Но для ИИ-агента, который сам пишет и модифицирует код, это спасательный круг. Представьте: агент генерирует функцию, которая читает файл, передаёт данные в парсер и пишет результат обратно. В Python или Go он мог бы случайно создать циклическую ссылку или забыть закрыть файловый дескриптор. В Rust компилятор не даст ему собрать бинарник, пока не проверит все владения. Это как если бы у ИИ был личный ревьюер, который никогда не устаёт.
В-третьих, cross-compilation. Один раз собранный агент может работать на x86, ARM и даже на Raspberry Pi без изменений. В моём кластере есть ноды разного железа — и это реальность, а не теория.
toml# Cargo.toml — минимальные зависимости для файловой и сетевой работы
[package]
name = "claw-agent"
version = "0.1.0"
edition = "2021"
[dependencies]
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
anyhow = "1"
walkdir = "2"
reqwest = { version = "0.2", features = ["json"] }
Архитектура управления кодом
Архитектура Claw Code построена вокруг идеи единого источника правды. В отличие от традиционных агентов, которые хранят состояние в памяти и теряют его при падении, Claw Code сериализует всё — от планов до промежуточных результатов — в структурированные файлы на диске.
Во-первых, состояние агента. Каждая задача, которую он принимает, превращается в директорию с описанием в формате TOML. Это как если бы systemd хранил юниты не в /etc/systemd/system/, а в /var/lib/claw/tasks/. Предсказуемость здесь достигается не через «умную» логику, а через простоту: структура на диске — это и есть состояние.
toml# /var/lib/claw/tasks/issue_42.toml
[task]
id = "issue_42"
status = "in_progress"
created_at = "2024-01-15T10:30:00Z"
updated_at = "2024-01-15T11:45:00Z"
[context]
repository = "https://github.com/claw-code/core"
branch = "feature/issue-42"
prompt = "Добавить валидацию входных параметров в функцию parse_config"
Во-вторых, слой абстракции над Git. Агент не работает с git напрямую — он использует библиотеку git2, которая даёт программный доступ к коммитам, веткам и слияниям. Это важно, потому что ИИ не должен «думать» о том, как правильно оформить коммит. Он просто вызывает метод, а библиотека решает, как это сделать.
rust// Пример: создание ветки и коммит изменений
use git2::Repository;
let repo = Repository::open(".")?;
let mut index = repo.index()?;
index.add_all(["src/"], None)?;
let tree = index.write_tree()?;
let signature = repo.signature()?;
let parent = repo.head()?.peel_to_commit()?;
repo.commit(
Some("refs/heads/feature/issue-42"),
&signature,
&signature,
"Fix: add input validation to parse_config",
&repo.find_tree(tree)?,
&[&parent],
)?;
В-третьих, система плагинов через трейиты. Вместо того чтобы жёстко кодировать логику парсинга или тестирования, Claw Code определяет трейиты CodeAnalyzer, TestRunner и PatchGenerator. Это как если бы systemd поддерживал drop-in-файлы — вы можете подменить реализацию без изменения ядра.
rust// Трейит для анализа кода
trait CodeAnalyzer {
fn analyze(&self, file_path: &Path) -> Result<Vec<Issue>>;
}
// Трейит для генерации патчей
trait PatchGenerator {
fn generate(&self, issue: &Issue, context: &CodeContext) -> Result<String>;
}
С практической точки зрения, эта архитектура позволяет агенту не просто писать код, а управлять им как инженер. Каждое изменение проходит через цепочку: анализ → генерация патча → применение → тесты → коммит. И всё это без единой строки, написанной человеком.
Практическая ценность и риски
Предсказуемость кода, созданного ИИ
С практической точки зрения, когда речь заходит о предсказуемости, я смотрю на то, как система ведёт себя в бою. Алгоритм генерации кода может быть хорошо протестирован на синтетических наборах, но реальная нагрузка всегда выявляет то, что «работает в теории».
Вот типичная ситуация. Вы запускаете сервис, написанный ИИ, в продакшене. Через неделю он падает с паникой в serde_json, потому что кто-то отправил в поле user_id строку вместо числа. Человеческий разработчик, даже junior, за годы привыкание к граничным случаям, хотя бы интуитивно добавил бы валидацию. ИИ же, даже если и «знает» о ней теоретически, может не учесть этот сценарий, если он не был явно прописан в тренировочных данных.
rust// Пример: ИИ-сгенерированный обработчик запроса
// Предполагает, что все поля будут корректными
#[derive(Deserialize)]
struct UserRequest {
user_id: u64,
name: String,
}
async fn handle_user(req: Json<UserRequest>) -> impl IntoResponse {
// Здесь нет проверки на отрицательные ID, пустые строки и т.п.
println!("Processing user {}", req.user_id);
HttpResponse::Ok().finish()
}
С другой стороны, есть позитивные примеры. Проект Claw Code использует строгую типизацию и паттерн-матчинг, что делает многие ошибки невозможными на этапе компиляции. Но даже здесь есть нюансы. ИИ может «запутать» логику обработки ошибок, используя unwrap() вместо ? или match, особенно если в тренировочных данных доминировали примеры с идеальными входными данными.
toml# Cargo.toml — типичная конфигурация для ИИ-проекта
[package]
name = "claw_code_service"
version = "0.1.0"
edition = "2021"
[dependencies]
actix-web = "4.0"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
Если мы посмотрим на мониторинг, то предсказуемость становится критически важной. В моей практике на Proxmox-кластере я всегда настраиваю алерты на основе метрик из Prometheus. Для ИИ-кода это означает, что без должного логирования и трассировки вы рискуете потерять контроль над тем, что происходит внутри сервиса.
yaml# Пример конфигурации Loki для сбора логов
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
common:
path_prefix: /tmp/loki
storage:
filesystem:
chunks_directory: /tmp/loki/chunks
rules_directory: /tmp/loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemory
config:
clients:
- url: http://localhost:9094/loki/api/v1/push
Проблемы поддержки без человеческого контроля
Во-первых, нужно понимать, что поддержка кода — это не только исправление багов. Это и рефакторинг, и адаптация к изменениям в зависимостях, и обновление уязвимостей в библиотеках. ИИ, даже если он способен писать новый код, может не иметь достаточного контекста для того, чтобы понять, почему определённая функция была написана именно так, а не иначе.
Представьте, что через год вы обнаруживаете уязвимость в версии actix-web, которую использует ваш ИИ-сервис. Обычный разработчик посмотрит на git blame, увидит коммит с пояснением, и поймёт, какие части кода затрагиваются. ИИ же, даже если он и «поймёт» описание уязвимости, может не иметь достаточной связи с историей изменений, чтобы безопасно внести правки.
bash# Пример: проверка уязвимостей в зависимостях
cargo audit
# Вывод может показать уязвимости, но ИИ не всегда
# понимает контекст использования уязвимой библиотеки
С практической точки зрения, поддержка без человека приводит к накоплению технического долга. ИИ может не заметить, что некоторые функции стали дублировать логику, или что архитектура проекта разошлась с первоначальным замыслом. В моём опыте на сторадже TrueNAS (48 ТБ) я регулярно провожу аудит конфигураций — не ради «чистоты», а чтобы избежать проблем с производительностью и отказоустойчивостью.
rust// Пример: ИИ может не заметить, что две функции делают одно и то же
fn calculate_checksum_v1(data: &[u8]) -> u32 {
data.iter().fold(0, |acc, &x| acc.wrapping_add(x as u32))
}
fn calculate_checksum_v2(data: &[u8]) -> u32 {
let mut sum = 0u32;
for &byte in data {
sum = sum.wrapping_add(byte as u32);
}
sum
}
Если мы посмотрим на реальные проекты, то многие «автономные» ИИ-системы со временем требуют вмешательства. Например, в документации Claw Code упоминается необходимость ручной проверки критических секций, особенно тех, что связаны с безопасностью. Это не значит, что ИИ не способен писать качественный код — просто без человеческого надзора риск возрастает.
bash# Пример: автоматический рефакторинг может сломать логику
cargo refactor rename-variable old_name new_name
# ИИ может не понять, что `old_name` используется в макросах или конфигурациях
В заключение, я бы сказал так: ИИ — отличный помощник, но не замена инженеру. Особенно когда речь заходит о поддержке и эволюции проекта. Мои серверы на Proxmox работают годами не потому, что я «не трогаю их, пока не сломаются», а потому, что регулярно провожу аудит и рефакторинг. То же самое должно применяться к ИИ-коду.
Перспективы агентного программирования
От генерации функций к управлению репозиторием
С практической точки зрения, когда ИИ-агенты начали писать не отдельные функции, а целые модули, сразу стало ясно: проблема не в коде, а в координации. Я это услышал впервые на совещании сообщества Rust, где один из разработчиков сказал, что теперь триаггует GitHub API не человек, а цепочка агентов — один пишет тесты, другой правит конфиксы, третий ревьюит.
Вот как это выглядит на практике. Агенты используют GitHub CLI для управления репозиторием:
bash# Создаём ветку с описанием задачи
gh repo clone claw-code/core
cd core
git checkout -b feature/agent-auth
# Генерируем код и сразу коммитим
cargo clippy --fix --allow-dirty
git add .
git commit -m "feat: add agent authentication module"
Но здесь есть нюанс. Если мы посмотрим на workflow, который используют агенты Claw Code, окажется, что они не просто пушат код — они ещё и управляют issue-трекером:
yaml# .github/workflows/agent-ci.yml
name: Agent CI
on:
push:
branches: [feature/agent-*]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
- run: cargo test
- run: cargo clippy -- -D warnings
Предсказуемость здесь достигается не идеальным кодом, а строгими правилами взаимодействия. Каждый агент знает: если тесты падают — откатываешь коммит, если clippy ругается — исправляешь до мержа. Никаких «попробуем так» и «может пройдёт».
Влияние на жизненный цикл разработки ПО
Раньше мы думали о DevOps как о конвейере: код → тесты → деплой. Теперь агенты сжимают этот цикл до «напиши → проверь → задеплой». Они не просто пишут код — они управляют CI/CD pipeline, мониторингом и даже алертами.
Во-первых, это меняет подход к тестированию. Агенты не пишут unit-тесты по шаблону — они генерируют property-based тесты с использованием proptest:
rust// tests/agent_integration.rs
use proptest::prelude::*;
proptest! {
#[test]
fn test_auth_token_validity(token in "[a-zA-Z0-9]{32}") {
let result = auth::validate_token(&token);
prop_assert!(result.is_ok() || result.is_err());
}
}
Со-вторых, агенты работают с systemd напрямую, а не через Docker Compose. Это кажется странным, но на самом деле даёт большую предсказуемость:
ini# /etc/systemd/system/claw-agent.service
[Unit]
Description=Claw Code Agent Service
After=network.target
[Service]
Type=simple
User=claw
ExecStart=/opt/claw/bin/agent --config /etc/claw/config.toml
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
А вот как выглядит их подход к логированию:
bash# Настраиваем journald для сбора логов агентов
mkdir -p /etc/systemd/journald.conf.d/
cat > /etc/systemd/journald.conf.d/claw-agents.conf <<EOF
[Journal]
Storage=persistent
ForwardToSyslog=yes
MaxFileSec=1month
EOF
systemctl restart systemd-journald
Если мы посмотрим на мониторинг, окажется, что агенты экспортируют метрики в Prometheus без посредников:
rust// src/metrics.rs
use prometheus::{IntCounter, register_int_counter};
lazy_static! {
static ref BUILD_COUNTER: IntCounter = register_int_counter!(
"claw_build_total",
"Total number of builds performed by agents"
).unwrap();
}
pub fn increment_build() {
BUILD_COUNTER.inc();
}
Интересно, что агенты используют Loki для агрегации логов, а не ELK-стек. По их логике: зачем три сервиса, если один promtail + Loki покрывает 90% случаев?
yaml# promtail-config.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: agents
agent: claw-code
Что касается бэкапов, агенты настраивают Borg с systemd timers, а не используют готовые решения:
ini# /etc/systemd/system/claw-backup.timer
[Unit]
Description=Daily backup of Claw Code repositories
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
bash# Активируем таймер
systemctl enable claw-backup.timer
systemctl start claw-backup.timer
С практической точки зрения, самое интересное — это не то, что агенты делают всё сами. Интересно, как они решают, что делать. Они используют decision trees, а не нейросети, для выбора стратегии. Это как IKEA для мебели: всё собирается по инструкции, но свои нюансы.
rust// src/decision.rs
pub enum BuildStrategy {
Fast, // Только компиляция
Full, // Компиляция + тесты + clippy
Release, // Релизная сборка с оптимизацией
}
pub fn choose_strategy(urgency: Urgency, risk: RiskLevel) -> BuildStrategy {
match (urgency, risk) {
(Urgency::High, RiskLevel::Low) => BuildStrategy::Fast,
(Urgency::High, RiskLevel::High) => BuildStrategy::Full,
(Urgency::Low, _) => BuildStrategy::Release,
}
}
Алексей Кузнецов, системный инженер с 12-летним опытом, отмечает: «Предсказуемость конфигураций — это не про идеальный код. Это про то, чтобы каждый шаг был обоснован и воспроизводим. Агенты Claw Code это понимают лучше большинства людей».