docs: README follows the beaver_agent layout, MODELS.md moves to the vault

This commit is contained in:
hh
2026-09-02 00:25:20 +02:00
parent ac4a8d1fae
commit 583ffc474e
2 changed files with 50 additions and 88 deletions
-65
View File
@@ -1,65 +0,0 @@
# Модели: как вводить новую (чеклист)
Единственное место с процедурой. Проверено 2026-09-01 боевым тестом на dell.
## Главный инвариант
**API отбрасывает новые модели по версии клиента.** `claude` CLI 2.1.248 с
`--model claude-fable-5-1` получает от API
`400: version 2.1.251 or newer is required` — id проходит насквозь, но сервер
режет по минимальной версии Claude Code для этой модели. Поэтому порядок
строго такой: **сначала CLI, потом id в конфигах.**
CLI живёт в двух местах:
- **гейтвей (контейнер на dell)** — забандлен в питоновский пакет
`claude-agent-sdk` (`_bundled/claude`), замораживается при сборке образа.
Версия CLI = версия пакета, соответствие в
[CHANGELOG SDK](https://github.com/anthropics/claude-agent-sdk-python/blob/main/CHANGELOG.md)
(например 0.2.146 → CLI 2.1.248, 0.2.150 → 2.1.257).
- **t3code на машинах (mac, dell-хост)** — обычный `claude` пользователя
(`~/.local/share/claude/versions/…`, `/usr/local/bin/claude`), сам
автообновляется; вручную — `claude update`.
## Чеклист «вышла новая модель X»
1. **beaver-gateway**: поднять SDK до версии с достаточно новым CLI:
`pyproject.toml` (`claude-agent-sdk>=…`) + `uv lock -P claude-agent-sdk`,
закоммитить, запушить `main`.
2. **beaver-agent/config.py** (строки ~383–399, список агентов): поменять id
моделей у `deep`/`dispatcher`/… Effort там же.
3. **beaver-agent/t3code.toml** (дефолты t3code-mcp per-machine,
`model = "claudeAgent/…"`): поменять id. Внимание: t3code для незнакомого
ему слага теряет опции `effort`/`contextWindow` (см. ниже) — id должен
быть в каталоге t3code, т.е. t3code-приложение должно быть обновлено.
4. Деплой: `make deploy` (push `main:stable`; образ гейтвея собирается из
`beaver-gateway#main` при деплое, поэтому шаг 1 — раньше).
5. **t3code на машинах**: `claude --version` ≥ минимума модели (обычно уже
сам обновился); само приложение t3code (alpha) обновляется nightly и
привозит новую модель в каталог.
Проверить, какие id вообще существуют:
```bash
TOK=$(security find-generic-password -s "Claude Code-credentials" -w | jq -r .claudeAiOauth.accessToken)
curl -s https://api.anthropic.com/v1/models -H "Authorization: Bearer $TOK" \
-H "anthropic-version: 2023-06-01" -H "anthropic-beta: oauth-2025-04-20" | jq -r '.data[].id'
```
## Алиасы `fable` / `opus` / `sonnet`
CLI принимает голые алиасы и резолвит их в **новейшую модель, которую знает
установленный CLI** (проверено: CLI 2.1.248 резолвит `fable`
`claude-fable-5`, не 5.1). Свойства:
- никогда не дают 400 «слишком старый клиент» — деградируют до старой модели;
- «всегда новейшая» они дают только при свежем CLI, так что шаг 1 чеклиста
они не отменяют, но убирают шаги 2–3 (id в конфигах менять не надо);
- **в t3code** кастомный слаг (`fable`, `opus`, как и любой id вне каталога)
имеет пустые capabilities → t3 не передаёт `--effort` и суффикс `[1m]`
(`ClaudeAdapter.ts`: `resolveClaudeEffort(caps,…)` → undefined). Модель
работает, но на дефолтном effort и дефолтном окне CLI.
Рекомендация: в `config.py` и `t3code.toml` можно перейти на алиасы, если
устраивает «новейшее из того, что знает CLI»; explicit id — когда нужен
точный контроль (и тогда обязательно проверять минимум версии CLI).
+50 -23
View File
@@ -2,7 +2,7 @@
My real beaver-gateway setup (paired with the protocol from beaver.kotikot.com). My real beaver-gateway setup (paired with the protocol from beaver.kotikot.com).
Uses Claude Code and Raycast subscriptions for agents, has some MCPs set up. You can use this as-is or modify to match your needs (config.py). Uses Claude Code and Raycast subscriptions for agents, has some MCPs set up. You can use this as-is or modify to match your needs: `config.py` assembles the gateway from the `beaver_agent/` package.
## Requirements ## Requirements
@@ -60,12 +60,14 @@ regular Claude Code; rotate it by running `claude setup-token` again.
Claude agents run on the Claude Agent SDK. Prompts are granules under Claude agents run on the Claude Agent SDK. Prompts are granules under
`мета/бобер/промпты/` in the vault - plain markdown, the `<tag>` wrappers `мета/бобер/промпты/` in the vault - plain markdown, the `<tag>` wrappers
and the order live in `config.py`; skills are the folders under and the order live in `beaver_agent/prompts.py`; skills are the folders under
`мета/бобер/скиллы/` (each becomes a plugin, keep `name:` in SKILL.md `мета/бобер/скиллы/` (each becomes a plugin, keep `name:` in SKILL.md
latin). The vault must be synced before the gateway can start. The model process runs as `beaver-runner` latin), which window loads which set is `beaver_agent/skills.py`. The vault
with a whitelisted environment; the vault is mounted read-write (it is the must be synced before the gateway can start. The model process runs as
dispatcher's home), and `policy.py` keeps it out of `.obsidian`, `мета` `beaver-runner` with a whitelisted environment; the vault is mounted
outside `мета/бобер`, and from deleting anything but its own files. read-write (it is the dispatcher's home), and `beaver_agent/policy.py` keeps
it out of `.obsidian`, `мета` outside `мета/бобер`, and from deleting
anything but its own files.
### 4. Mint a token ### 4. Mint a token
@@ -131,30 +133,55 @@ Needs `KOMODO_URL` / `KOMODO_KEY` / `KOMODO_SECRET` in `.env` (and
inject. Jobs, the queue and the subscription window are on the admin **Jobs** page. inject. Jobs, the queue and the subscription window are on the admin **Jobs** page.
The same key backs the `komodo` tool the dispatcher and deep chats get The same key backs the `komodo` tool the dispatcher and deep chats get
(`mcps/komodo.py`, архитектура §4.4): one MCP tool with an enumerated (`beaver_agent/hands/komodo.py`): one MCP tool with an enumerated
`action` - `status`, `stacks`, `containers`, `logs`, `search_logs`, `updates`, `action` - `status`, `stacks`, `containers`, `logs`, `search_logs`, `updates`,
`update`, `deploy`, `restart`, `exec`. `exec` is `docker exec` into any `update`, `deploy`, `restart`, `exec`. `exec` is `docker exec` into any
container of the fleet except infrastructure ones (`exec_deny`, periphery by container of the fleet except infrastructure ones (`exec_deny`, periphery by
default); prune, destroy and a host terminal do not exist in the enumeration, default); prune, destroy and a host terminal do not exist in the enumeration,
so they cannot be asked for. The key never reaches the model process. so they cannot be asked for. The key never reaches the model process.
## Policy (`policy.py`) ## Layout: `config.py` + `beaver_agent/`
`bypassPermissions` everywhere; the boundary is the read-only vault mount `config.py` is a page: it imports the pieces and calls `Gateway(...)`. The
plus `PreToolUse` rules declared per agent (`ClaudeAgent.policy`, архитектура pieces live in `beaver_agent/`, one concern per module:
§3.7): writes only under `мета/бобер/`, new files only under `💬 чаты/`,
`rm`/`mv`/`cp`/`tee`/`sed -i`/redirects into the vault outside those zones
are refused with a reason, and `mcp__firefly__store_*`/`update_*` need the
`firefly` skill opened first in the same session. Every tool call lands in
the admin **Audit** page as `tool_call`. Run `make check` - it includes the
policy and komodo tests.
## Editing config.py on the mac - `vault.py` - paths and the agent's zone, `TZ`
- `prompts.py` - how each role's system prompt is assembled from granules
- `skills.py` - which window loads which skill set
- `policy.py` - `PreToolUse` rules and vault zones (`ZONES`, `VAULT_POLICY`)
- `hands/` - every MCP the setup has and which agent gets which one; the
connectors (komodo, home assistant, vibegram) live here too
- `agents.py` - the roles (dispatcher, deep, distiller, curator, triage,
raycast) and the list of instances with models and effort
- `frontends.py` - the windows: Telegram for master and branches, vault
files for deep chats, `/api`, `/admin`, `/anthropic`, `/mcp`
- `texts.py` - everything the gateway says to the model or to the user,
in Russian (the gateway's own defaults are English)
- `memory/` - the recall block under a message, the reply log, handouts
and seeds, the vault watcher, the curator briefing
- `jobs/` - crons and webhooks, one file per job
## Policy (`beaver_agent/policy.py`)
`bypassPermissions` everywhere; the boundary is `PreToolUse` rules declared
per agent (`ClaudeAgent.policy`): the vault is the dispatcher's home, so it
may create, edit and move anywhere except `.obsidian` and `мета` outside
`мета/бобер`, and may delete only its own files; the distiller and curator
stay in `мета/бобер`; `rm`/`mv`/`cp`/`tee`/`sed -i`/redirects into the vault
outside those zones are refused with a reason; `mcp__firefly__store_*` and
`update_*` need the `firefly` skill opened first in the same session, and the
master cannot open the `vault/` skills at all (a branch can). Every tool call
lands in the admin **Audit** page as `tool_call`. Run `make check`.
## Editing the setup on the mac
`make sync` installs `../beaver-gateway` editable (extra `local`), so `make sync` installs `../beaver-gateway` editable (extra `local`), so
imports in `config.py` resolve against the checkout you are working on; imports resolve against the checkout you are working on; `uv sync --extra
`uv sync --extra prod` pulls the gateway from git instead. Neither is used prod` pulls the gateway from git instead. Neither is used by the image - the
by the image - the container builds the gateway itself. container builds the gateway itself. To assemble the config against your
local vault: `BEAVER_VAULT=~/path/to/vault uv run python -c
'from beaver_gateway import config; from pathlib import Path;
config.load(Path("config.py"))'` with a `.env` next to it.
## Useful commands ## Useful commands
@@ -175,13 +202,13 @@ docker compose logs -f obsidian-headless
# pull the latest beaver-gateway (when GATEWAY_REF=main) # pull the latest beaver-gateway (when GATEWAY_REF=main)
docker compose build gateway && docker compose up -d gateway docker compose build gateway && docker compose up -d gateway
# reload config.py without a full rebuild # reload config.py / beaver_agent without a full rebuild
docker compose restart gateway docker compose restart gateway
``` ```
## Gotchas ## Gotchas
- **claude in the container doesn't see the vault** - `cwd=VAULT` in `config.py` resolves to `/vault` *inside* the container, not on the host. Don't change it. - **claude in the container doesn't see the vault** - `VAULT` in `beaver_agent/vault.py` is `/vault` *inside* the container, not on the host. Don't change it; `BEAVER_VAULT` is for assembling the config on the mac only.
- **a claude turn fails immediately** - check `docker logs beaver-gateway` for the `claude[<agent>]:` stderr lines. Usually auth: redo step 3. - **a claude turn fails immediately** - check `docker logs beaver-gateway` for the `claude[<agent>]:` stderr lines. Usually auth: redo step 3.
- **gateway restarts in a loop right after first `up`** - `config.py` reads prompt granules from `/vault/мета/бобер/промпты`; until Obsidian Sync has pulled the vault they are missing. Finish step 2, it settles. - **gateway restarts in a loop right after first `up`** - `beaver_agent/prompts.py` reads prompt granules from `/vault/мета/бобер/промпты`; until Obsidian Sync has pulled the vault they are missing. Finish step 2, it settles.
- **the model cannot write into `мета/бобер`** - the entrypoint grants `beaver-runner` an ACL on the two rw sub-mounts once at start; files that Sync creates later inherit it through the default ACL. If `setfacl` is unsupported on the volume it falls back to `chown`, and then files Sync writes afterwards as root stay read-only for the model until the next restart. - **the model cannot write into `мета/бобер`** - the entrypoint grants `beaver-runner` an ACL on the two rw sub-mounts once at start; files that Sync creates later inherit it through the default ACL. If `setfacl` is unsupported on the volume it falls back to `chown`, and then files Sync writes afterwards as root stay read-only for the model until the next restart.