Быстрый старт
Короткий путь — на примере RouterAI, российского OpenAI-совместимого провайдера.
- Зарегистрируйся на routerai.ru и создай API-ключ.
-
Поставь Skein:
npm install -g skein-swe(или запускай без установки —npx -p skein-swe skein). Нужны Node.js 22 или новее иbash; если глобальная установка требует root — см. «Установку». -
Сохрани ключ и проверь, что он и модель отвечают:
skein auth login routerai skein doctor -
Запусти агента в каталоге проекта:
skein --dir ~/project
Вместо интерактивного входа можно задать ROUTERAI_API_KEY в окружении.
auth login показывает бесплатные и локальные варианты первыми и печатает
ссылку на ключ выбранного провайдера.
Введение
Skein — терминальный агент разработки. «Терминальный» здесь означает, что агент работает в терминале: пользователь вводит команды в панели чата, видит, что агент делает, в панели наблюдений и следит за ходом работы в панели задач. «Агент разработки» — потому что он помогает писать программный код: читает проект, вносит изменения, запускает сборку и тесты.
Skein устроен иначе, чем традиционные агенты разработки. Чтобы понять, в чём разница, сначала посмотрим, как обычно работают агенты разработки и где у этой схемы слабые места.
Как обычно работает агент разработки
Обычный агент разработки работает по циклу ReAct: модель рассуждает, выбирает действие, исполнитель запускает инструмент и возвращает результат, после чего модель рассуждает снова. Модель получает системный промпт и задачу пользователя, а на каждом шаге выбирает очередное действие: прочитать файл, найти строку, изменить код, выполнить команду. Результат дописывается в историю, и цикл повторяется, пока модель не скажет «готово» или не закончится бюджет.
Инструментов у такого агента обычно немного: прочитать файл, найти файл или строку по
шаблону, отредактировать файл, создать файл. Главный из них — оболочка (shell
или bash): она позволяет выполнить в терминале любую команду — собрать
проект, прогнать тесты, сделать коммит, запустить скрипт. Часто оболочки хватает почти на
всё, а отдельные инструменты нужны лишь для удобства и безопасности типовых действий. У
Skein к обычному набору добавлены два инструмента, которых у других агентов обычно нет, —
recall и search; они позволяют доставать из журнала то, что
ушло с ленты. Подробнее о них ниже.
Контекст модели — это не только история действий. В нём лежат системный промпт, задача, все рассуждения и выводы инструментов; для модели это единственная память. Отдельного состояния у агента нет — цель живёт в тексте этой истории. Когда история перестаёт помещаться в окно модели, её обрезают или сжимают.
Провайдеры моделей не запускают модель заново на уже прочитанном тексте: они хранят её внутреннее состояние у себя и находят его по префиксу промпта — это и есть кэш промпта. Поэтому входные токены, которые уже были в предыдущем вызове, обычно стоят на порядки дешевле новых. Длинная история перестаёт быть дорогой, и цена с задержкой отходят на второй план. Остаются две другие проблемы: внимание и управляемость.
Внимание. Цель конкурирует с килобайтами старых выводов инструментов. Модель переоткрывает уже известное, возвращается к пройденному и постепенно теряет исходную задачу.
Управляемость. У шага нет явной границы, а история при сжатии переписывается. По истории трудно сказать, что модель «знала» в момент решения, и ещё труднее воспроизвести это позже.
Почему сравниваем с opencode
opencode — открытый терминальный агент разработки, который работает по этой же схеме. Он
подходит для сравнения не потому, что «плохой», а потому что его можно поставить в те же
условия: тот же провайдер и модель, тот же режим рассуждений, те же задачи и контейнеры,
запуск без интерфейса (opencode run, --continue). В нашем
прогоне fix-ocaml-gc он решил задачу за 54 шага, а его контекст вырос
примерно с 3k до 300k символов. Кэш сделал это недорогим, но история осталась историей.
Чем Skein отличается
Skein построен вокруг другой идеи: история — это данные, а не промпт.
Оговоримся о слове «лента». Дальше так называется то, что видит модель на входе: у обычного агента это растущая история, у Skein — проекция журнала. Это один и тот же видимый контекст модели, просто устроен он по-разному.
- История хранится, а не переписывается. Вместо растущей ленты у Skein типизированный журнал, в который только дописывают. Узлы журнала не переписываются, поэтому история остаётся полной и адресуемой.
-
Промпт собирается заново. На каждом ходу контекст модели строится из
журнала заново и детерминированно: одни и те же события дают одну и ту же ленту. Лента
немонотонна: когда фокус меняется, закрытые состояния уходят с экрана, но остаются в
журнале и доступны через
recallиsearch. -
Явные состояния. Шаг работы — это состояние с целью
(
what), условием завершения (Done when) и своим набором инструментов. Переходы между состояниями явные. Запрос пользователя — это ориентир, а не активная цель: активная цель у состояния. - Модель предлагает, исполнитель записывает. У модели нет скрытой памяти; отказы и ошибки инструментов — единственные факты, которые добавляет движок.
- Сессия поверх отдельных задач. Весь диалог пользователя с агентом (сессия) состоит из отдельных единиц работы, у каждой свой журнал. Единицы изолированы, и наружу виден только краткий итог каждой. Непрерывность держится на переформулировке запроса и этих итогах.
recall и search — особые инструменты Skein.
recall возвращает конкретный ход или фрагмент прошлой работы,
search ищет по журналу. В обычном агенте история либо целиком лежит в
контексте, либо её уже сжали, и достать оттуда точный факт нечем.
Что это даёт: цель остаётся заметной в точке решения, у каждого шага есть явная граница, а журнал можно воспроизвести и проверить.
Чего это не даёт: это не оптимизация стоимости. Изоляция может стоить дороже из-за повторного чтения проекта. Критерий проверяется текстом модели, а не движком, поэтому возможна преждевременная остановка.
Одна задача целиком: fix-ocaml-gc
Разберём одну реальную задачу целиком — от первой реплики пользователя до финального ответа. Это иллюстративный пример: он нужен, чтобы показать, как Skein ведёт работу и чем его ход отличается от обычного агента вроде opencode на той же задаче.
Пользователь пишет, что сломал сборщик мусора OCaml, пытаясь сжать свободное место в major heap, и компилятор падает при bootstrap. Он просит разобраться и убедиться, что базовый testsuite проходит.
Движок записывает запрос, осматривает рабочую область и просит модель выбрать стартовое состояние. Вот как выглядит первый ход, схематично:
[system] базовый промпт: роль и как работать
[human] запрос
[system] факты о рабочей области: корень, VCS нет, сеть выключена, есть make/gcc/perl
[human] выбери стартовое состояние: Patch / Construction / Research
Patch
Модель выбирает Patch и формулирует предмет работы: сломанный
run-length-compressed sweep в major GC. Проекция состояния выглядит так:
[system] Start state Patch
[system] факты о рабочей области
[human] Goal: найти дефект в существующем артефакте и внести нужную правку
Done when: план выполнен — ошибка найдена и исправлена
Plan: 1) найти файл и причину 2) исправить и остановиться с отчётом
Дальше идёт работа внутри состояния. Схематично:
| Действие | Что дало |
|---|---|
list /app | структура проекта |
cat HACKING.adoc | как собирать компилятор |
find -newermt | недавно изменённые файлы |
grep по shared_heap.c |
подозрительные циклы обхода пула |
edit |
p += Whsize_hd(hd) → p += wh |
После 18 ходов модель отвечает текстом — движок записывает
Finish state Patch с результатом: причина в pool_sweep, размер
свободного блока хранится в заголовке, шаг должен идти на ширину size-class.
Переход
Проекция схлопывается. На ленту попадают только базовый промпт, запрос,
Start state Patch, Finish state Patch и вопрос о следующем
состоянии:
[system] Choose exactly one next state:
Verification — изменение внесено и строки прочитаны обратно
Research — это ситуация, а не дефект, который надо найти и исправить
На пике Patch контекст был около 116k символов, на переходе — около 4.5k. Это не удаление: журнал цел, на ленту попадает только то, что нужно для решения о следующем шаге.
Verification
Модель переходит в состояние проверки.
[system] Start state Verification
[human] Goal: проверить изменённый артефакт против acceptance
Done when: acceptance проходит, результат выведен из материала
Plan: выполнить acceptance-команду и прочитать вывод;
нулевой exit code — не доказательство; артефакт здесь не менять
| Действие | Что дало |
|---|---|
./configure | подготовка сборки |
make -j16 |
компилятор собрался, bootstrap прошёл |
make -C testsuite one DIR=tests/basic |
40 tests passed |
Модель отвечает текстом — Finish state Verification.
End
[system] Start state End
[system] This is End. Прочитай ленту — запрос, пройденные состояния,
что каждое сделало, какие файлы изменены, как проверено, —
и напиши финальный отчёт.
Финальный ответ: дефект в pool_sweep
(runtime/shared_heap.c), исправлен на p += wh, сборка проходит,
базовый testsuite — 40 tests passed.
Что здесь важно
- Контекст — не транскрипт. У каждого состояния своя проекция, и она пересобирается заново.
- Запрос остаётся ориентиром; активная цель — у состояния.
- Текст модели — граница состояния (
stop). - Закрытое состояние уходит с ленты, но остаётся в журнале.
- Контекст всё равно растёт, но кэш делает его дешёвым. Смысл не в экономии, а в том, что модель видит цель, а не всю историю.
Механика
Состояния и переходы
Задача проходит через явные состояния. Состояние — это этап работы, у которого есть цель (что именно нужно сделать), условие завершения (как понять, что этап закончен) и свой набор инструментов. У состояния есть короткий список ходов, и после каждого хода модель видит его заново, а не всю историю задачи.
Состояний пять:
| Состояние | Что делает | Куда может перейти |
|---|---|---|
| Research | разбирается в ситуации и добывает нужный результат из материала | End, Patch |
| Patch | находит дефект в существующем артефакте и исправляет его | Verification, Research |
| Construction | строит новый артефакт по спецификации | End, Research |
| Verification | проверяет изменение против условия задачи | End (прошло), Patch (не прошло) |
| End | завершает запрос финальным отчётом | — |
Обычный маршрут — Research → Patch → Verification → End. Если проверка не
прошла, работа возвращается в Patch и правит дальше. Переход выбирает
модель, но список допустимых переходов задаёт движок: из Patch можно в
Verification или Research, но не сразу в End.
Состояние закрывается, когда модель отвечает текстом. Движок записывает этот ответ как
stop и переносит результат в журнал. Отдельной проверки «достигнута ли цель»
нет: условие записано в состоянии, но движок его не исполняет. Поэтому возможна
преждевременная остановка — это известное ограничение.
Агенты и единицы работы
Реплики пользователя обрабатывает отдельный агент — агент сессии. Он не работает с
файлами напрямую: инструменты рабочей области ему недоступны. Вместо этого на каждую
реплику он выбирает одну из шести операций: respond, general,
revision, task, plan, write_document.
Операция открывает единицу работы — отдельную задачу со своим журналом событий. Внутри единицы агент читает файлы, правит код и запускает команды, но наружу эти шаги не выходят: агент сессии видит только краткий итог единицы. Поэтому единицы не мешают друг другу, а сессия остаётся связной за счёт переформулировки запроса и этих итогов.
task— цикл состояний, описанный выше;general— разбор рабочей области без изменений;revision— изменение, уже описанное в запросе (правки и команды);plan— план работ без изменений;write_document— большой Markdown-документ по секциям;respond— ответ из диалога и прошлой работы.
Лента
Лента — это то, что видит модель на входе. Она собирается из журнала заново на каждом ходу, и порядок блоков всегда один:
- базовый промпт — роль агента и общие правила;
- запрос пользователя — как ориентир, а не как активная цель;
Start state— с какого состояния начали;- краткая справка о рабочей области;
- ходы состояния — действия и наблюдения;
- рабочий промпт — цель, условие завершения и план именно этого состояния;
Finish state— результат, когда состояние закрыто.
Порядок и содержимое определяет только журнал. Одни и те же события всегда дают одну и ту
же ленту — в этом смысле сборка детерминирована. Но она немонотонна: когда фокус переходит
в другое состояние, закрытое состояние уходит с ленты. Это не потеря — журнал цел, и
вернуть нужное можно через recall и search.
Сессия и изоляция
Сессия — это весь диалог пользователя с агентом. Каждая реплика превращается в отдельную единицу работы: у неё свой журнал, свой набор состояний и свой итог. Единицы изолированы друг от друга: внутри следующей единицы не видно пошаговой истории предыдущей, только её краткий итог. Поэтому единицы не раздувают друг друга и не тянут за собой чужие выводы инструментов.
Цена изоляции — повторное чтение рабочей области. Если новая задача требует тех же фактов, что и прошлая, агенту придётся прочитать их снова: в ленте новой единицы их нет. Непрерывность сессии держится на двух вещах: переформулировке запроса с учётом прошлых реплик и кратких итогах уже выполненных единиц.
Журнал
Журнал — это история работы в виде типизированных записей: запрос, ходы, действия, наблюдения, переходы между состояниями, остановки. В него только дописывают: узлы не переписываются и не удаляются. Поэтому по журналу можно восстановить, что делал агент, в каком порядке и с каким результатом.
Лента строится из журнала, а не наоборот. Если что-то ушло с ленты при смене фокуса, оно
остаётся в журнале. Инструменты recall и search достают оттуда
конкретный ход или находят нужное по журналу — так модель возвращает факт, не перечитывая
всё заново.
Оценка и ограничения
Мы сравнили Skein с opencode на тринадцати задачах. Каждую задачу решали пять раз, с сетью
и без, обоими агентами — всего 250 прогонов, доступных для оценки. Решено 246 (98,4%). По
группам: Skein с сетью — 63 из 65, Skein без сети — 60 из 60, opencode с сетью — 65 из 65,
opencode без сети — 58 из 60. Вся серия шла на одном провайдере и одной модели —
deepseek-v4-flash с низким уровнем рассуждений; это не заявление о передовом
результате.
Замеры по токенам (только решённые прогоны, по 123 на агента):
| Skein | opencode | |
|---|---|---|
| вход | 31,38 млн | 47,63 млн |
| из кэша | 26,88 млн | 45,22 млн |
| новых входных | 4,50 млн | 2,41 млн |
| выход | 1,24 млн | 0,94 млн |
| попадание в кэш | 85,7% | 94,9% |
| ходов | 2447 | 1800 |
Картина такая: opencode тратит больше токенов, но почти всё это попадания в кэш, поэтому по деньгам он дешевле. Skein компактнее по общему объёму, но у него больше новых входных токенов и выхода: единицы не делят один растущий промпт, поэтому чаще читают рабочую область заново.
Отсюда главный вывод: разница не в цене. Кэш делает длинную ленту дешёвой, поэтому сравнивать по деньгам бессмысленно. Смысл в другом — держать цель заметной в точке решения и делать шаг воспроизводимым. Эти свойства сложнее измерить, и автоматически мы их не измеряли.
Ограничения:
- движок не проверяет условие завершения состояния, поэтому возможна преждевременная остановка;
- изоляция меняет дрейф на повторную работу и может стоить дороже;
- вся серия — один провайдер, одна модель и низкий уровень рассуждений;
-
инструмент оболочки требует
/bin/bash; на Windows подойдут WSL2, Git Bash/MSYS2 или Docker.
Протокол, все прогоны, токены и стоимость по состояниям лежат в
bench/results/campaign-k5/; сырые данные публикуются с релизом.
Установка
Нужен Node.js 22 или новее и bash.
npm install -g skein-swe
skein --version
Если глобальный префикс npm — системный каталог (например, /usr/local),
обычный npm install -g упадёт с EACCES. Ставь с
--prefix "$HOME/.local" и добавь ~/.local/bin в
PATH: sudo не нужен. Если у тебя nvm или volta, глобальная
установка и так идёт в домашний каталог. Без установки можно запускать
npx -p skein-swe skein.
Из исходников
git clone https://github.com/merfill/skein.git
cd skein
npm install
npm run build
npm pack
npm install -g --prefix "$HOME/.local" ./skein-swe-*.tgz
export PATH="$HOME/.local/bin:$PATH"
skein --version
Дальше нужно указать провайдера, ключ и модель — интерактивно или переменными окружения:
skein auth login
skein doctor
skein doctor проверяет, что ключ и модель отвечают. Если всё в порядке,
запускается интерфейс:
skein --dir ~/project
Windows
Агенту нужен /bin/bash, поэтому на Windows надёжный путь — WSL2 или Docker.
Нативные PowerShell и cmd без bash не подойдут.
WSL2 (рекомендуется):
-
В PowerShell от администратора выполни
wsl --install -d Ubuntuи перезагрузись. -
Внутри Ubuntu поставь Node.js 22:
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt-get install -y nodejs -
Проекты держи в домашнем каталоге WSL (
~/project), а не в/mnt/c: так быстрее и не ломаются права. - Дальше повтори шаги установки для Linux внутри WSL.
Docker Desktop: запусти Linux-образ из блока ниже — Node внутри не нужен.
Git Bash / MSYS2: может сработать, только если /bin/bash
доступен из запускающей оболочки, но на практике нативный Windows-Node этот путь часто не
находит. Надёжнее WSL2 или Docker.
Docker
Готовый образ можно взять с Docker Hub:
docker pull mefrill/skein-swe:0.1.0
docker run --rm -it \
-v "$PWD:/workspace" \
-e ROUTERAI_API_KEY=... \
-e SKEIN_MODEL=~deepseek/deepseek-v4-flash-latest \
mefrill/skein-swe:0.1.0
Провайдер задаётся переменными окружения; модель в образ не встроена. Тег
latest указывает на последнюю версию. В Windows PowerShell для пути
используйте ${PWD}, в cmd — %cd%;
--env-file не убирает кавычки из значений.
Собрать из исходников: docker build -t skein:0.1.0 . в корне репозитория.
Ссылки
- Исходный код (GitHub)
- Документация
- npm-пакет (skein-swe)
- Docker-образ (Docker Hub)
- DOI на Zenodo после релиза