| harness | ||
| .gitignore | ||
| architecture.html | ||
| cli.py | ||
| README.md | ||
Simbiot Harness
Ритмичный агент: живёт тактами, как человек. CQRS + Event Sourcing на спине, Strands Harness SDK как исполнительное ядро, модели через 9router.
Лестница (v0.1)
| Уровень | Интервал | Контекст | Модель | Задачи |
|---|---|---|---|---|
| sec | 1 с | 0 (без LLM) | — | рефлекс: телеметрия, алерты |
| min | 1 мин | ~4K | auto→flash | S-триаж: входящие, быстрые фиксы |
| hour | 1 ч | ~32K | auto | S/M-задачи |
| day | 1 д | ~128K | auto | M/L-задачи, манифест дня |
Принципы: тик идемпотентен (UNIQUE(level, seq)); занятый уровень поглощает
тик (TickAbsorbed + детерминированная заглушка дайджеста, без LLM);
запущенная задача не прерывается; наверх идут только дайджесты.
События (ES-спина)
CycleTicked, TickAbsorbed, ReflexObserved, DigestWritten,
TaskSubmitted, TaskClaimed, TaskCompleted, TaskFailed, TaskPromoted,
EscalationRaised, EscalationAcknowledged,
BudgetSpent, CycleError, HarnessInit, PolicySet — append-only,
проекции пересобираются replay'ем, стейт = производное от событий.
Структура
harness/es.py— event store + проекции (checkpoint + replay)harness/levels.py— конфигурация уровнейharness/scheduler.py— демон лестницыharness/isolated_runner.py+_llm_worker.py— LLM-тик в сабпроцессе (глобальный asyncio-рантайм Strands не переживает 2+create_harness)harness/commands.py— command sidecli.py— init/task/tasks/status/events/requeue
CLI
./venv/bin/python cli.py init --identity "…"
./venv/bin/python cli.py task "…" -m 240 # -m minutes-to-live estimate: S/M/L
./venv/bin/python cli.py tasks
./venv/bin/python cli.py status
./venv/bin/python cli.py events -n 50
./venv/bin/python cli.py requeue <task-id> -r "причина"
./venv/bin/python cli.py promote <task-id> -r "вне класса уровня" # S→M→L
./venv/bin/python cli.py escalate "причина" -f min -c "контекст" -s critical
./venv/bin/python cli.py escalations --open # открытые эскалации
./venv/bin/python cli.py escalation-ack <esc-id> -n "что сделал" # закрыть
./venv/bin/python cli.py tg-reply <msg-id> "текст" # ответ на входящее TG
Эскалации
Важное с нижних уровней поднимается наверх событием EscalationRaised
(min→hour→day; day — вершина, эскалировать некуда). Открытые эскалации
инжектятся в контекст верхних уровней (build_context) в приоритетной секции
— нижний уровень не тонет в чужих проблемах, верхний видит выжимку, а не сырь.
Уровень-адресат закрывает эскалацию escalation-ack (событие
EscalationAcknowledged). Падение LLM-тика (CycleError) эскалируется
автоматически — scheduler поднимает warn-эскалацию на уровень выше.
Запуск
systemctl enable --now simbiot-harness
journalctl -u simbiot-harness -f
Telegram-инбокс
Бот @juno42bot → long polling (simbiot-harness-tg.service) →
MessageReceived в стор → минутный уровень видит входящие в контексте →
отвечает cli.py tg-reply (Telegram-отправка + ReplySent закрывает входящее).
Белый список чатов в .env (SIMBIOT_TG_ALLOWED), чужие → MessageIgnored.
Дашборд задач
Веб-страница со всеми задачами (статусы/размеры/уровни) + лестница циклов +
эскалации + свежие дайджесты, автообновление каждые 5с (JSON-API /api/state).
systemctl status simbiot-dashboard # порт 8765, healthcheck 8766
TOKEN=$(grep -oP '(?<=SIMBIOT_DASH_TOKEN=).*' /etc/simbiot/dashboard.env)
xdg-open "http://<host>:8765/?token=$TOKEN" # токен пишется в cookie
curl "http://127.0.0.1:8765/api/state?token=$TOKEN" | jq . # машиночитаемо
Реализация: harness/dashboard.py (stdlib-only http.server, read-only из
event store через run_projections() — консистентно с scheduler/CLI) +
harness/dashboard.html. Авторизация: SIMBIOT_DASH_TOKEN из
/etc/simbiot/dashboard.env (env-файл юнита, режим 600); без токена — 401.
UFW: порт 8765/tcp открыт (токен-защищён).
Модели
9router (router.cil.by), отдельный ключ sk-simbiot в .env, комбо auto:
glm-5.3 → kimi-k3 → deepseek-v4-pro → v4.1-flash → flash. Бюджет виден
в событиях BudgetSpent (по уровням) и в дашборде 9router по ключу.
v0.2 (roadmap)
- прерывание срочной реакцией / пауза (сейчас absorbed детерминирован)
- уровни week/month/quarter/year
- инбокс из Telegram/портала