# priiisk

[English version](./README.md)

Управляемый лагерь долгоживущих worker-агентов. Оркестратор нанимает воркеров,
дает им задания и держит управление; человек наблюдает через кабину и
вмешивается только когда нужно.

Воркер — не одноразовый процесс, а живая session: у него есть роль, модель,
уровень мышления, свой набор инструментов и transcript, который переживает
перезапуск.

**Идет активная разработка.** Команды, конфигурация и сохраненное состояние
меняются между выпусками, иногда без переходного пути: лагерь, поднятый прежней
сборкой, может отказаться восстанавливаться, а вчерашний конфиг — быть
отклоненным целиком. Ломаться будет; читайте тот выпуск, который ставите.

## Установка

```sh
npm install -g priiisk
priiisk --version
```

Отдельный рантайм ставить не нужно: лагерь целиком лежит внутри исполняемого
файла. Поддержаны linux и macOS, x64 и arm64.

## После установки

`priiisk` без аргументов — то же, что `priiisk status` — это состояние лагеря:
поднят ли он, кто в ростере, какие вопросы и просьбы о повышении ждут ответа.
`priiisk survey` — карта команд и обычный порядок работы. Если лагеря нет,
его поднимают `camp up`.

Команды, отвечающие состоянием, понимают `--json`. Лагерь опрашивается
запросом, а не чтением экрана. `priiisk --help` перечисляет остальные команды,
`priiisk <команда> --help` — аргументы каждой.

## Быстрый старт

`camp up` поднимает лагерь отсоединенным процессом и, если терминал вызова
умеет рисовать, открывает в нем кабину. Закрытие кабины лагеря не касается,
вернуть вид — `camp open`. Для найма в конфиге нужна хотя бы одна модель; см.
[Настройка](#настройка).

```sh
priiisk camp up
priiisk hire "Разбери падение тестов" --role prospector
priiisk status prospector-quiet-harbor
priiisk asks
priiisk answer prospector-quiet-harbor
priiisk camp down
```

Hire сам генерирует алиас (`<роль>-<прилагательное>-<существительное>`), если не
передан `--alias`. Дальше используйте имя, которое напечатал hire —
`prospector-quiet-harbor` здесь только пример. Первое задание необязательно:
без него воркер ждет в `idle` команды `priiisk send`.

Лагерь привязан к каноническому корню репозитория: один проект — один лагерь,
один сокет, один управляющий оркестратор.

## Режимы доступа

Режим доступа — множество классов операций, которые воркер может получить. Он
задается при найме и на живом воркере не меняется. `equip` сужает выдачу
внутри потолка режима и никогда его не поднимает.

| режим | классы | на практике |
| --- | --- | --- |
| `read-only` | чтение | файлы, поиск, читающие бинари каталога; оболочки нет |
| `execute` | чтение, исполнение | плюс оболочка для проверок; `edit` и `write` не выданы |
| `read-write` | чтение, запись | правка файлов инструментами; оболочки нет |
| `all` | все три | полный набор |

Класс объявляет сам инструмент. Встроенные роли: `prospector` — `read-only`,
`assayer` — `execute`, `wright` — `all`.

`execute` не запрещает запись. Запущенная команда пишет все, что доступно
пользователю процесса. Это дисциплина роли, а не изоляция.

## Повышение полномочий

Разовый выход за нанятый режим — это просьба о повышении, а не вопрос. Воркер
называет недостающий класс (`read`, `write` или `execute`) и обоснование.
Оркестратор отвечает `priiisk grant <id>` или `priiisk grant <id> --deny`.
Разрешение открывает окно до конца хода, пока воркер не вернет результат;
прерывание, ошибка и повтор окно не закрывают. Следующая надобность — новая
просьба. Нанятый режим при этом не меняется.

## Рабочее пространство воркера

`priiisk hire --workspace worktree` создает именованное пространство с
собственным деревом и веткой. Второго воркера сажают туда по имени:
`priiisk hire --workspace <name>`. Так проверяющий читает работу пишущего до
слияния. Это не песочница: object database, refs, конфигурация репозитория,
hooks и права пользователя того же репозитория остаются общими. Закрытие
кооперативное. Готовую работу забирают обычным `git merge`.

`priiisk workspace list` показывает, кто в каком пространстве живет.
`priiisk workspace forget <name>` убирает пустое именованное пространство.
`priiisk workspace sweep` показывает осиротевшие деревья после сбоя: пустое
именованное пространство сиротой не считается. `--confirm` удаляет только
чистые деревья, чья ветка уже достижима из другой ссылки. Грязное дерево и
дерево с невлитой веткой команда оставляет на месте.

## Настройка

Лагерь читает один пользовательский TOML-файл:
`$XDG_CONFIG_HOME/priiisk/config.toml`, а если `XDG_CONFIG_HOME` не задан —
`~/.config/priiisk/config.toml`.

Файл проходит строгую проверку целиком. Неизвестное поле отклоняется.
Молчаливо игнорируемых настроек нет.

### Перед первым лагерем: сначала агент-рантайм

priiisk исполняет воркеров рантаймом pi и **наследует его провайдеров, модели и
авторизацию**. Своих токенов он не хранит и чужой реестр моделей не копирует:
модель существует для лагеря только если она уже существует там.

Отсюда жесткий порядок, который легко нарушить:

1. Войти в pi и подключить провайдеров, которыми собираетесь пользоваться.
   Добавление провайдера и продление авторизации делаются средствами pi, а не
   отсюда.
2. Узнать у pi, какие ссылки `provider/model` вам действительно доступны.
   Лагерь принимает точную ссылку, а не семейство и не отображаемое имя.
3. Связать эти ссылки короткими алиасами в конфиге ниже и пользоваться в ролях
   и пресетах алиасами.
4. Выполнить `priiisk doctor`. Он подтверждает, что каждый алиас резолвится в
   каталоге pi и что авторизация для него есть, — чтением каталога, без отправки
   запроса и без трат.

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

Минимальный файл. Перед `camp up` подставьте оба `id`; плейсхолдеры ниже — только обязательная форма `provider/model`:

```toml
schemaVersion = 2

[defaults]
model = "strong"
thinking = "medium"

[models.strong]
id = "provider/model"

[models.fast]
id = "provider/model"

[roles.assayer]
description = "Review worker"
model = "strong"
thinking = "high"
access = "execute"

[hirePresets.safe-review]
description = "Review without a shell"
role = "assayer"
access = "read-only"
```

Подставьте в оба `id` модели из своего агент-рантайма. `defaults.model` и
`defaults.thinking` обязательны. Пресет найма может назвать встроенную роль
(`wright`, `assayer`, `prospector`) и сузить доступ.

Репозиторий может держать `.priiisk/config.toml` и переопределять им политику
из пользовательского файла: модели, роли, пресеты найма, группы навыков,
defaults и workspace. Определения MCP-серверов и каталог внешних бинарей из
репозитория не читаются: эти поля задают то, что лагерь запустит, и чтение их
из клона означало бы исполнение чужого кода при первом же `hire`.
