Продвинутый

Ultraworkers/claw-code: агент‑управляемый музей стенд на...

Алексей Кузнецов
Алексей Кузнецов
Системный администратор15 ноября 2026 г.11 мин чтения

Агент‑управляемый музейный стенд, написанный на Rust с Gajae‑Code/LazyCodex, полностью автономен и не требует вмешательства человека.

Ultraworkers/claw-code: агент‑управляемый музей стенд на Rust

Агент‑управляемый музейный стенд, написанный на Rust с Gajae‑Code/LazyCodex, полностью автономен и не требует вмешательства человека.

Концепция и архитектура

Роль автономного агента

Автономный агент — это процесс, который полностью самостоятельно контролирует работу музейного стенда: собирает метрики, принимает решения на основе заранее заданных правил и инициирует корректирующие действия без участия человека.

Во-первых, агент постоянно опрашивает сенсоры (температуру, уровень нагрузки на CPU, состояние диска) через systemd‑unit с watchdog‑таймаутом. При превышении порога он генерирует событие в journald, после чего система алертинга Alertmanager отправляет уведомление в чат.

Пример systemd‑юнита для агента:

ini
[Unit]
Description=Музейный стенд‑агент
After=network.target

[Service]
ExecStart=/usr/local/bin/claw-agent --config /etc/claw-agent.yaml
Restart=on-failure
WatchdogSec=30
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Команда systemctl enable --now claw-agent запускает сервис и гарантирует его автозапуск при загрузке системы.

Во-вторых, агент использует LazyCodex — декларативный DSL для описания правил поведения. Правила написаны в YAML‑файле и компилируются в Rust‑код во время старта. Пример правила, который автоматически перезапускает контейнер, если его процесс не отвечает более 5 минут:

yaml
rules:
  - name: "restart_unresponsive"
    when:
      - metric: "container_cpu_usage"
        operator: ">"
        value: 0.0
      - timer: "last_restart"
        operator: ">"
        value: 300s
    then:
      - action: "restart_container"
        target: "museum-service"

LazyCodex преобразует этот DSL в Rust‑функцию, которая вызывается из основного цикла агента.

В-третьих, автономность достигается за счёт self‑healing: при любой ошибке (например, падение контейнера) агент сразу инициирует systemctl restart museum-service и фиксирует событие в Loki. Таким образом стенд остаётся доступным 24/7, а человеку не нужно вмешиваться в рутину.

Технологический стек: Rust + Gajae-Code/LazyCodex

Выбор Rust обусловлен рядом причин. Язык обеспечивает память без garbage‑collector, что критично для небольших встроенных устройств, а его строгая типизация фиксирует ошибки на этапе компиляции. Кроме того, в Rust легко писать безопасный сетевой код и работать с системными вызовами через libc‑обёртки.

В проекте используется Cargo как менеджер пакетов. Минимальный Cargo.toml выглядит так:

toml
[package]
name = "claw-agent"
version = "0.1.0"
edition = "2021"

[dependencies]
clap = "4.0"
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9"
lazycodex = "0.3"
tokio = { version = "1.0", features = ["full"] }
prometheus = "0.13"

Код агента написан в стиле «модульность»: основной цикл находится в src/main.rs, а бизнес‑логика вынесена в отдельные модули (rules.rs, orchestrator.rs). Пример функции, которая проверяет состояние контейнера и инициирует перезапуск:

rust
pub async fn check_and_restart(container: &str) {
    let usage = prometheus::gather_container_cpu().await;
    if usage > 0.0 {
        // правило LazyCodex уже сработало, отправляем сигнал перезапуска
        println!("Перезапуск контейнера {}", container);
        std::process::Command::new("docker")
            .args(&["restart", container])
            .status()
            .expect("не удалось выполнить docker restart");
    }
}

Gajae-Code — это higher‑level orchestration layer, которая генерирует Rust‑код из YAML‑описания. Она отвечает за управление зависимостями между сервисами, динамическое изменение конфигураций и интеграцию с systemd. Пример конфигурации, описывающей весь стенд, выглядит так:

yaml
services:
  - name: "museum-display"
    image: "ultraworkers/claw-display:latest"
    ports:
      - "8080:80"
    depends_on:
      - "museum-db"
  - name: "museum-db"
    image: "postgres:15"
    environment:
      POSTGRES_USER: "claw"
      POSTGRES_PASSWORD: "secret"
    volumes:
      - "db-data:/var/lib/postgresql/data"

volumes:
  db-data:

Запуск этого стека выглядит так:

bash
cargo run --release -- --config /etc/claw-agent.yaml

После старта агент регистрирует себя в Prometheus через pushgateway и начинает собирать метрики. В Grafana‑дашборде визуализируются такие показатели, как CPU‑нагрузка, количество запросов к API и состояние диска.

Таким образом, сочетание Rust (производительность и надёжность) и Gajae-Code/LazyCodex (высокоуровневая декларация) даёт возможность построить полностью автономный музейный стенд, который самостоятельно решает возникающие задачи, не требуя постоянного вмешательства оператора.

Разработка и развертывание

### Настройка среды разработки

Во-первых, убедитесь, что на машине установлен Rust Toolchain 1.70 и выше – это минимальная версия, поддерживающая текущие версии lazycodex и gajae-code.
Самый простой способ установить Rust через rustup:

bash
curl https://sh.rustup.rs -sSf | sh -s -- -y
source $HOME/.cargo/env
rustc --version   # должно отобразиться 1.70.0 или новее

Создайте новый бинарный проект, который будет служить агентом‑управляющим стендом:

bash
cargo new claw-code-museum --bin
cd claw-code-museum

Добавьте зависимости в Cargo.toml. Ниже пример минимального набора:

toml
[package]
name = "claw-code-museum"
version = "0.1.0"
edition = "2021"

[dependencies]
gajae-code = "0.3"
lazycodex = "0.5"
tokio = { version = "1.38", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

После изменения файла выполните cargo fetch – Cargo загрузит все необходимые crates в директорию ~/.cargo/registry.

Для удобства отладки удобно добавить скрипт в Makefile:

makefile
.PHONY: run build test

run:
	cargo run --release

build:
	cargo build --release

test:
	cargo test

Теперь можно запускать приложение локально:

bash
make run

Если требуется кросс‑компиляция под ARM‑платформы (например, Raspberry Pi), используйте cross:

bash
cargo install cross
cross build --target aarch64-unknown-linux-gnu --release

Важно: при работе с lazycodex убедитесь, что в конфигурации указали путь к базе данных модели, иначе агент не сможет генерировать ответы. Подробные настройки см. в документации lazycodex.

Автоматическое развертывание через CI/CD

С практической точки зрения полностью автономный стенд удобно разворачивать через CI/CD. Ниже пример конфигурации workflow для GitHub Actions, который собирает образ Docker, пушит его в GitHub Container Registry и затем применяет его на удалённом сервере через ssh и docker compose.

yaml
name: Deploy Claw‑Code Museum

on:
  push:
    branches: [ main ]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build Docker image
        run: |
          docker build -t ghcr.io/${{ github.repository }}/claw-code-museum:${{ github.sha }} .
          docker push ghcr.io/${{ github.repository }}/claw-code-museum:${{ github.sha }}

      - name: Deploy to server
        env:
          SERVER_HOST: ${{ secrets.SERVER_HOST }}
          SERVER_USER: ${{ secrets.SERVER_USER }}
          SSH_KEY: ${{ secrets.SSH_KEY }}
        run: |
          echo "$SSH_KEY" > /tmp/id_rsa
          chmod 600 /tmp/id_rsa
          ssh -i /tmp/id_rsa $SERVER_USER@$SERVER_HOST <<'EOF'
            set -e
            echo "🚀 Pulling new image..."
            docker pull ghcr.io/${{ github.repository }}/claw-code-museum:${{ github.sha }}
            echo "🛠️  Stopping old container..."
            docker compose -f /opt/claw-code-museum/docker-compose.yml down
            echo "📦 Deploying new container..."
            docker compose -f /opt/claw-code-museum/docker-compose.yml up -d --remove-orphans
          EOF

Файл docker-compose.yml для стенда выглядит так:

yaml
version: "3.9"

services:
  museum-agent:
    image: ghcr.io/your-org/claw-code-museum:latest
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      - RUST_LOG=info
      - DB_PATH=/data/museum.db
    volumes:
      - /opt/claw-code-museum/data:/data

Примечание: в примере использован docker compose (v2), поэтому на сервере должна быть установлена Docker Compose 2.x. Инструкцию по установке можно найти в официальной документации Docker.

С помощью этого пайплайна каждый push в ветку main автоматически собирает актуальный образ, публикует его в регистрари и без вмешательства человека разворачивает новый стенд. Таким образом достигается полная автономность – именно то, что требуется для museum‑стенда.

Операция и поддержка

Мониторинг и алерты

Когда мы запускаем автономную систему вроде claw-code, предсказуемость становится главным приоритетом. Поскольку агент управляет стендом самостоятельно, вы не можете полагаться на то, что заметите ошибку в консоли в момент её возникновения. Если агент уйдет в бесконечный цикл или начнет потреблять слишком много ресурсов, система должна сообщить об этом до того, как упадет весь узел.

С практической точки зрения, я рекомендую не пытаться мониторить всё подряд, а сфокусироваться на трех метриках: состоянии процесса Rust-бинарника, потреблении памяти и доступности API агента.

Для сбора метрик лучше всего подходит связка Prometheus и Grafana. Если вы разворачиваете claw-code через Docker Compose, добавьте в конфигурацию экспортер для контейнеров. Чтобы убедиться, что агент не «завис», настройте проверку liveness probe.

Пример базового конфига для мониторинга состояния сервиса через systemd, если вы запускаете агент напрямую на хосте:

ini
[Unit]
Description=Claw-Code Agent Service
After=network.target

[Service]
ExecStart=/usr/local/bin/claw-code --config /etc/claw-code/config.toml
Restart=always
# Перезапуск через 5 секунд, если процесс упал
RestartSec=5s
# Ограничение ресурсов, чтобы агент не «съел» всю память стенда
MemoryMax=2G
CPUWeight=50

[Install]
WantedBy=multi-user.target

Для настройки алертов в Alertmanager я советую использовать правило на основе rate для ошибок в логах. Если количество строк ERROR в journald превышает пороговое значение за 5 минут, вы должны получить уведомление.

Обновления без простоя

Обновление автономных систем — это всегда риск нарушить логику работы агента. В случае с claw-code, использующим LazyCodex, важно, чтобы процесс обновления не прерывал текущие задачи, которые агент выполняет на стенде.

Если вы используете контейнеризацию, самый надёжный способ — это стратегия Blue-Green. Мы не обновляем работающий контейнер «на лету», а поднимаем новую версию рядом, проверяем её работоспособность и только потом переключаем трафик.

Для реализации этого в домашней лаборатории проще всего использовать Docker Compose с небольшим скриптом автоматизации. Вместо того чтобы делать docker-compose pull && docker-compose up -d, что может вызвать кратковременный простой, используйте следующий подход:

  1. Разверните новую версию под другим именем сервиса.
  2. Проверьте статус через docker inspect.
  3. Переключите конфигурацию Nginx или Caddy на новый контейнер.
  4. Удалите старую версию.

Пример конфигурации Caddy для плавного переключения между версиями агента:

caddyfile
# Основной адрес стенда
claw-code.local {
    # Направляем трафик на текущую рабочую версию
    reverse_proxy localhost:8080
}

# Временный адрес для проверки новой версии перед переключением
claw-code-next.local {
    reverse_proxy localhost:8081
}

Если агент работает как системный сервис, используйте systemd-механизм ExecReload. Это позволит перечитать конфигурацию без полной остановки процесса, если архитектура claw-code это поддерживает. Если же требуется полный перезапуск, всегда делайте бэкап директории с состоянием (state directory) перед выполнением команд обновления. Это единственный способ гарантировать, что после перезапуска агент вернется к той же точке выполнения задачи, с которой он прервался.

Практические примеры

Интеграция с Plex и Nextcloud

Когда мы говорим об автономном агенте вроде claw-code, важно понимать, что он не должен существовать в вакууме. В моей домашней лаборатории он выполняет роль «умного диспетчера», который не просто хранит данные, а управляет их жизненным циклом.

С практической точки зрения, интеграция с Plex и Nextcloud сводится к тому, чтобы агент мог корректно манипулировать файловой структурой, не нарушая логику работы этих сервисов. Если агент решит переместить старый семейный архив в холодное хранилище, Plex должен об этом узнать, иначе мы получим «битые» ссылки в медиатеке.

Для реализации такой предсказуемости я использую связку через API и системные события. Например, чтобы Plex обновил базу после того, как claw-code закончил обработку медиафайлов, можно отправить запрос к Plex Media Scanner.

Если вы разворачиваете это в Docker, убедитесь, что агент находится в той же Docker-сети, что и ваши сервисы, либо имеет доступ к их API по внутренним IP. Пример конфигурации для взаимодействия через сетевой интерфейс в docker-compose.yml:

yaml
services:
  claw-code:
    image: ultraworkers/claw-code:latest
    networks:
      - media-network
    environment:
      - PLEX_API_URL=http://plex-server:32400
      - NEXTCLOUD_API_TOKEN=${NEXTCLOUD_TOKEN}

  plex:
    image: linuxserver/plex
    networks:
      - media-network
    # ... остальные настройки

С Nextcloud ситуация чуть сложнее. Вместо прямого изменения файлов в директории data, что может привести к рассинхронизации базы данных Nextcloud, я настраиваю агента на работу через WebDAV или встроенный API. Это гарантирует, что каждое действие агента будет зафиксировано в системе.

Взаимодействие с TrueNAS

Работа с хранилищем — это критический узел. В моей конфигурации за это отвечает TrueNAS, где на ZFS развернуты основные пулы. Для claw-code наиболее надёжным способом взаимодействия является использование протокола NFS или SMB, но с обязательным контролем прав доступа.

Чтобы избежать ситуации, когда агент создает файлы, которые потом невозможно удалить или переместить из-за конфликта прав (UID/GID), я всегда привожу конфигурацию прав к единому стандарту.

Если вы используете NFS для монтирования разделов TrueNAS на ноду, где запущен агент, проверьте параметры монтирования в /etc/fstab. Для предсказуемости работы лучше использовать явное указание прав:

bash
# Пример монтирования сетевого хранилища в /mnt/storage
<IP_адрес_TrueNAS>:/mnt/tank/media /mnt/storage nfs rw,hard,intr,noatime 0 0

С точки зрения логики агента, взаимодействие с TrueNAS можно разделить на три этапа:

  1. Проверка доступности пула: перед началом любой операции агент должен убедиться, что точка монтирования активна.
  2. Атомарная запись: сначала данные пишутся во временную директорию на том же пуле, а затем перемещаются в целевую папку. Это исключает появление «битых» файлов при сбое сети.
  3. Валидация: после завершения операции агент проверяет контрольную сумму (checksum) файла.

Если вы планируете использовать Gajae-Code/LazyCodex для автоматизации этих процессов, рекомендую сначала протестировать сценарии на отдельном пуле с небольшим объёмом данных. Это позволит убедиться, что логика перемещения файлов не конфликтует с политиками snapshot-ов в ZFS.

Часто задаваемые вопросы

Как обеспечить предсказуемость работы агента при сбоях?

Для обеспечения стабильности в архитектуре используется systemd с настроенным параметром WatchdogSec. Если процесс агента зависнет или перестанет отвечать на сигналы, система сама перезапустит его согласно политике Restart=on-failure. Это позволяет минимизировать время простоя и гарантирует, что управляющий процесс всегда будет активен.

Можно ли изменить логику поведения стенда без пересборки всего проекта?

Да, за это отвечает декларативный DSL LazyCodex, который считывает правила из YAML-файла при старте. Вы можете описать новые условия мониторинга или действия, такие как перезапуск сервисов или отправка алертов, просто отредактировав конфигурацию. С практической точки зрения, это позволяет быстро адаптировать стенд под новые требования, не прибегая к изменению исходного кода на Rust.

Какие инструменты используются для мониторинга состояния системы?

Агент собирает метрики напрямую из системы и передаёт их в стек мониторинга, где основную роль играют journald и Alertmanager. Все события, включая критические ошибки и срабатывания правил, фиксируются в системном журнале, что упрощает последующий аудит. Если порог нагрузки превышен, Alertmanager оперативно доставляет уведомление ответственному лицу.

Как агент понимает, что контейнер перестал отвечать на запросы?

В системе реализован механизм проверки метрик, где агент сопоставляет текущие показатели с заданными в правилах LazyCodex. Например, если значение метрики container_cpu_usage или таймер последнего перезапуска не соответствуют норме, срабатывает триггер. После этого агент выполняет предустановленное действие, такое как restart_container, восстанавливая работоспособность сервиса.

Поделиться:TelegramX / TwitterVK