# НОДА1 — Deploy Humanized Stepan v3

**Дата підготовки:** 2026-02-25  
**Статус:** ready-to-deploy  
**LLM:** DeepSeek (primary) або OpenAI (fallback)

---

## Передумови

- SSH доступ до НОДА1 (root@144.76.224.179 або root@2a01:4f8:201:2a6::2)
- `DEEPSEEK_API_KEY` або `OPENAI_API_KEY` (хоча б один)
- Telegram user_id оператора для `AGX_OPERATOR_IDS`

---

## Крок 1 — Скопіювати файли на НОДА1

З локальної машини (де є репо):

```bash
cd /path/to/microdao-daarion

# Всі Stepan v3 модулі
scp -6 \
  crews/agromatrix_crew/llm_factory.py \
  crews/agromatrix_crew/depth_classifier.py \
  crews/agromatrix_crew/memory_manager.py \
  crews/agromatrix_crew/light_reply.py \
  crews/agromatrix_crew/telemetry.py \
  crews/agromatrix_crew/reflection_engine.py \
  crews/agromatrix_crew/style_adapter.py \
  crews/agromatrix_crew/session_context.py \
  crews/agromatrix_crew/proactivity.py \
  crews/agromatrix_crew/run.py \
  crews/agromatrix_crew/stepan_system_prompt_v2.txt \
  crews/agromatrix_crew/stepan_system_prompt_v2.7.txt \
  "root@[2a01:4f8:201:2a6::2]:/opt/microdao-daarion/crews/agromatrix_crew/"

# Agents з DeepSeek LLM
scp -6 \
  crews/agromatrix_crew/agents/stepan_orchestrator.py \
  crews/agromatrix_crew/agents/operations_agent.py \
  crews/agromatrix_crew/agents/iot_agent.py \
  crews/agromatrix_crew/agents/platform_agent.py \
  crews/agromatrix_crew/agents/spreadsheet_agent.py \
  crews/agromatrix_crew/agents/sustainability_agent.py \
  "root@[2a01:4f8:201:2a6::2]:/opt/microdao-daarion/crews/agromatrix_crew/agents/"

# gateway-bot http_api.py (з оновленим sys.path та stepan_enabled)
scp -6 \
  gateway-bot/http_api.py \
  "root@[2a01:4f8:201:2a6::2]:/opt/microdao-daarion/gateway-bot/"
```

---

## Крок 2 — Скопіювати crews у gateway-bot volume (на НОДА1)

```bash
# НА НОДА1:
# Синхронізуємо crews у gateway-bot volume
rsync -av /opt/microdao-daarion/crews/ /opt/microdao-daarion/gateway-bot/crews/
rsync -av /opt/microdao-daarion/packages/agromatrix-tools/ /opt/microdao-daarion/gateway-bot/agromatrix-tools/ 2>/dev/null || true

# Перевірити що файли є в контейнері
docker exec dagi-gateway-node1 ls /app/gateway-bot/crews/agromatrix_crew/ | head -20
```

---

## Крок 3 — Налаштувати env (секрети)

```bash
# НА НОДА1 — створити/оновити env файл
cat > /opt/microdao-daarion/.env.stepan.node1 << 'EOF'
DEEPSEEK_API_KEY=sk-ВАШИЙ_КЛЮЧ_DEEPSEEK
AGX_STEPAN_MODE=inproc
AGX_OPERATOR_IDS=ВАШ_TELEGRAM_USER_ID
TZ=Europe/Kyiv
EOF

chmod 600 /opt/microdao-daarion/.env.stepan.node1
```

Потім переконайтесь що `docker-compose.node1.yml` підключає цей файл у секції `gateway → env_file`:

```yaml
# У docker-compose.node1.yml, секція gateway/environment або після volumes:
    env_file:
      - .env.stepan.node1
```

> **Якщо env_file не хочете чіпати** — можна додати змінні прямо в секцію `environment:` compose файлу як `DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}` і export їх у shell перед `docker compose up`.

---

## Крок 4 — Перезапустити gateway

```bash
cd /opt/microdao-daarion

# Варіант А — простий restart (якщо volume і env вже на місці, без rebuild)
docker compose -f docker-compose.node1.yml restart dagi-gateway-node1
sleep 15

# Варіант Б — повний rebuild (якщо змінився Dockerfile або requirements)
docker compose -f docker-compose.node1.yml up -d --build gateway
sleep 30

# Health check
curl -s http://127.0.0.1:9300/health
```

---

## Крок 5 — Перевірити старт

```bash
# Лог старту (20 сек після restart)
docker logs dagi-gateway-node1 --since 3m 2>&1 | grep -E "Stepan|STEPAN|ImportError|ModuleNotFoundError|LLM:" | tail -20

# Env у контейнері (маскований)
docker exec dagi-gateway-node1 env | grep -E "DEEPSEEK|OPENAI|AGX_" | sed 's/=.*/=***/'

# Тест імпортів
docker exec dagi-gateway-node1 python3 -c "
import sys; sys.path.insert(0, '/app/gateway-bot'); sys.path.insert(0, '/app/gateway-bot/agromatrix-tools')
from crews.agromatrix_crew.session_context import load_session
from crews.agromatrix_crew.depth_classifier import classify_depth
from crews.agromatrix_crew.llm_factory import make_llm
print('imports OK')
llm = make_llm()
print('LLM:', type(llm).__name__ if llm else 'None - NO API KEY!')
"
```

---

## Крок 6 — 5 Smoketests (Telegram, оператор)

| # | Повідомлення | Очікування | Grep |
|---|---|---|---|
| 1 | `Привіт` | ≤80 символів, без "чим допомогти" | `depth=light, crew_launch=false` |
| 2 | `/whoami` | Показує user_id та is_operator=True | — |
| 3 | `Зроби план на завтра по полю 12` | Deep, crew запущений | `depth=deep, crew_launch=true` |
| 4 | `а на після завтра?` | Light (stability guard або follow-up) | `depth=light` |
| 5 | `Дякую` | ≤40 символів | `crew_launch=false` |

---

## Крок 7 — Telemetry моніторинг (перші 30 хв)

```bash
# Всі AGX_STEPAN_METRIC події
docker logs dagi-gateway-node1 --since 30m 2>&1 | grep "AGX_STEPAN_METRIC" | tail -80

# Depth розподіл
docker logs dagi-gateway-node1 --since 30m 2>&1 | grep "AGX_STEPAN_METRIC depth" | \
  awk '{for(i=1;i<=NF;i++) if($i~/^depth=/) print $i}' | sort | uniq -c

# Session layer
docker logs dagi-gateway-node1 --since 30m 2>&1 | grep "AGX_STEPAN_METRIC session_"

# LLM (DeepSeek) active
docker logs dagi-gateway-node1 --since 30m 2>&1 | grep "LLM:" | tail -5
```

---

## Rollback (якщо щось пішло не так)

```bash
cd /opt/microdao-daarion

# Відновити попередній http_api.py
git checkout HEAD -- gateway-bot/http_api.py

# Видалити скопійовані crews з volume
rm -rf /opt/microdao-daarion/gateway-bot/crews
rm -rf /opt/microdao-daarion/gateway-bot/agromatrix-tools

# Restart без Stepan
docker compose -f docker-compose.node1.yml restart dagi-gateway-node1
```

---

## Важливі примітки

1. **Volume mount `:ro`** — `gateway-bot` монтується як read-only. Тому `crews/` і `agromatrix-tools/` скопійовані прямо в `/opt/microdao-daarion/gateway-bot/` (і відповідно видимі в контейнері як `/app/gateway-bot/crews/`).

2. **fail2ban** — при частих SSH-підключеннях сервер тимчасово блокує IP на ~5–10 хвилин. Якщо SSH відмовляє — почекайте 10 хв і пробуйте через IPv6.

3. **DeepSeek модель** — за замовчуванням `deepseek-chat`. Можна змінити через `DEEPSEEK_MODEL=deepseek-reasoner`.

4. **`AGX_OPERATOR_IDS`** — це числові Telegram user_id. Дізнатись свій: написати @userinfobot у Telegram.
