Predictor X

Ресурсы проекта

Привязывайте типизированные указатели (Git-репозитории, локальные директории и другие в будущем) к проекту, чтобы агенты могли использовать их в качестве контекста с ограниченной областью видимости.

Ресурс проекта (Project Resource) — это типизированный указатель (URL Git-репозитория, путь на вашем компьютере, а в будущем — страница Notion), привязанный к проекту. Когда агент запускается для решения задачи внутри этого проекта, демон автоматически записывает список ресурсов проекта в рабочую директорию агента и в его промпт мета-навыка.

В результате агент знает, какой репозиторий нужно клонировать (или в какой локальной директории работать) и какие документы являются «основными источниками» для этого проекта, без необходимости вручную копировать контекст в описание задачи.

Ментальная модель

Проект теперь — это не просто метка. Это небольшой контейнер ресурсов:

  • Проект содержит от 0 до N ресурсов.
  • Ресурс имеет тип resource_type (например, github_repo, local_directory) и ссылку resource_ref (полезную нагрузку JSON, типизированную в соответствии с resource_type).
  • Добавление новых типов ресурсов требует лишь указания строки и обработчика. Никаких миграций схемы БД. Никакого переписывания фронтенда.

Такая структура выбрана намеренно — это тот же паттерн, который Предиктор Икс уже использует для провайдеров агентов: дискриминатор type и типизированная полезная нагрузка. Это сохраняет стабильность схемы, поэтому добавление поддержки «страниц Notion», «Google Документов», «загруженных файлов» или «внешних URL» в будущем станет простым аддитивным изменением.

На сегодняшний день поставляются два типа ресурсов: github_repo (клонирование под каждую задачу в изолированное рабочее дерево) и local_directory (запуск непосредственно внутри папки на машине конкретного демона).

Тип ресурса: github_repo

Тип ресурса по умолчанию — клонируется для каждой задачи в изолированное рабочее дерево:

{
  "resource_type": "github_repo",
  "resource_ref": {
    "url": "https://github.com/owner/repo",
    "default_branch_hint": "main"
  }
}

Параметр default_branch_hint необязателен — если он присутствует, демон передает его в мета-навык, чтобы агент знал, на какой ветке основывать свою работу.

Тип ресурса: local_directory

Для репозиториев, которые нецелесообразно повторно клонировать для каждой задачи (многогигабайтные сборки игр, огромные монорепозитории или любые проекты, где модель создания рабочего дерева под каждую задачу неэффективна), проект может указывать на существующую директорию на машине конкретного демона. Агент запускается непосредственно внутри этой папки, без клонирования, копирования и создания рабочих деревьев.

{
  "resource_type": "local_directory",
  "resource_ref": {
    "local_path": "/Users/me/code/big-game",
    "daemon_id": "0001234e-…",
    "label": "main checkout"
  }
}

Компромисс по сравнению с github_repo очевиден: только привязанный демон может брать задачи, связанные с этой директорией, и задачи в одной и той же директории выполняются последовательно, а не параллельно. Взамен вы сохраняете текущую рабочую копию, ветку и незафиксированные изменения — Предиктор Икс никогда не клонирует проект заново.

Когда выбирать local_directory вместо github_repo

Критерийgithub_repo (рабочее дерево)local_directory
Затраты на получение кода для задачиСвежий клон + рабочее деревоОтсутствуют — агент работает на месте
Параллелизм на одном репозиторииМного задач параллельноПо одной задаче на директорию
Ветка / состояние измененийКаждая задача получает новую ветку от дефолтнойТекущее состояние директории
Где может запускатьсяЛюбой демонРовно один демон (привязанный)
Занимаемый объем на дискеОдно рабочее дерево на задачуНоль дополнительных затрат — ваша папка

Выбирайте local_directory, если верно хотя бы одно из следующих утверждений:

  1. Повторное клонирование обходится слишком дорого — многогигабайтная сборка игры, монорепозиторий с тяжелыми LFS-файлами или любой проект, где операция git clone для каждой задачи занимала бы больше времени, чем сама работа. Вы жертвуете параллелизмом ради запуска без клонирования.
  2. Ваши изменения минимальны, и вы хотите проверять их локально по мере выполнения — вы итерируете над одним компонентом, хотите переключаться между правками агента и вашим редактором каждые несколько минут и предпочитаете, чтобы источником истины была ваша текущая рабочая копия, а не временное рабочее дерево задачи в недрах ~/predictorx_workspaces/.

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

Привязка локальной директории

Выбор папки доступен только в Desktop-приложении — веб-приложение не имеет возможности читать пути ОС, поэтому кнопка «Добавить локальную директорию» (Add local directory) там скрыта. В Desktop-приложении:

  1. Откройте проект → панель Resources (Ресурсы).
  2. Нажмите Add local directory. Откроется системный диалог выбора папки.
  3. Выберите папку. Путь привязывается к демону, зарегистрированному текущей установкой Desktop-приложения — запись ресурса сохраняет как путь, так и ID этого демона.

В Desktop-приложении кнопка остается видимой, но блокируется с подсказкой, если демон на этой машине оффлайн или если у проекта уже есть local_directory, привязанная к этому демону (чтобы было понятно, почему она недоступна). В веб-приложении эта кнопка скрыта полностью, так как инструмент выбора папок там недоступен. Чтобы привязать директорию на другой машине, установите Desktop на ту машину и добавьте ресурс оттуда.

Через CLI (работает и в окружениях без графического интерфейса, если вы вручную укажете ID демона):

predictorx project resource add <project-id> \
  --type local_directory \
  --local-path /Users/me/code/big-game \
  --daemon-id <daemon-uuid> \
  --ref-label "main checkout"        # опционально

predictorx project resource update <project-id> <resource-id> \
  --local-path /Users/me/code/big-game-new

ID демона (--daemon-id) можно узнать с помощью команды predictorx daemon list. CLI также поддерживает универсальный флаг --ref '<json>' на случай, если вы хотите передать полезную нагрузку напрямую.

Правила валидации путей

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

  • Путь должен быть абсолютным.
  • Путь должен существовать и вести к директории (не к файлу, символьной ссылке на файл или системному устройству).
  • Директория должна быть доступна для чтения и записи процессу демона.
  • Путь не может быть корневой директорией системы или профилем пользователя — запрещены /, /Users, /home, /root, /etc, /tmp, /var, /usr, /opt, /Users/Shared, ваш домашний каталог $HOME, корень любого диска Windows (C:\, D:\, …), а также C:\Users, C:\ProgramData, C:\Program Files, C:\Program Files (x86) и C:\Windows.
  • Символьные ссылки, разрешающиеся в любой из указанных путей, также отклоняются, равно как и канонический вид путей-псевдонимов ОС (например, в macOS указание /private/tmp будет отклонено так же, как и /tmp).

Список исключений намеренно строг — выбор домашней директории привел бы к сохранению рабочих файлов Предиктор Икс в корне вашей учетной записи, чего точно следует избегать. Используйте конкретную подпапку (как правило, ваш рабочий проект).

Один ресурс на связку (проект, демон)

Проект может содержать не более одной local_directory на одного демона. Попытка добавить вторую директорию для того же демона вернет ошибку 409 от API; кнопка в Desktop-приложении скрывается при достижении лимита, отображая подсказку с объяснением причины.

Разные демоны независимы — общий проект может иметь по одной local_directory на машинах разных участников команды, связывая один и тот же проект с разными папками на разных хостах. Когда демон берет задачу в работу, он выбирает запись, соответствующую его собственному ID, и игнорирует остальные.

Совмещение типов ресурсов и несколько ресурсов local_directory

На практике встречаются две конфигурации с разными ресурсами:

  • github_repo + local_directory в одном проекте. На демоне с совпадающей привязкой local_directory локальная директория имеет приоритет: агент запускается в вашей папке, и демон не создает рабочее дерево github_repo для этой задачи. (Кэш репозитория на уровне воркспейса все еще может синхронизироваться в фоновом режиме — это системное поведение, не связанное с рабочим деревом текущей задачи). URL github_repo по-прежнему записывается в .predictorx/project/resources.json и в секцию агента ## Repositories для справки, но рабочее дерево, которое правит агент — это ваша локальная папка. На демоне, у которого нет привязки local_directory для этого проекта (другой компьютер или до того, как коллега привязал папку), задача будет выполняться по обычному сценарию с рабочим деревом github_repo. Фактически, локальная директория работает как переопределение пути рабочего дерева для конкретного демона.
  • Две local_directory в одном проекте. Поскольку каждая local_directory привязана строго к одному демону, это возможно только на двух разных машинах (API отклоняет добавление двух директорий для одного демона, см. выше). Задачи распределяются на основе назначения рантайма агента, а не по наличию локальной директории: задача поступает на демона, который владеет рантаймом принимающего агента, этот демон выбирает строку local_directory со своим ID и игнорирует остальные. Балансировка нагрузки отсутствует — если вы хотите, чтобы задачу выполнила конкретная машина, отправьте ее агенту, привязанному к рантайму этой машины.

Демон, у которого нет строки local_directory для проекта, привязанного на другой машине, не блокируется — его задачи выполняются через другие ресурсы проекта (обычно с откатом к github_repo). Ресурс local_directory важен только для того демона, к которому он привязан.

Выполнение задач в локальной директории

При запуске задачи по обращению (issue), проект которого имеет привязанную к данному демону local_directory, демон:

  1. Повторно валидирует путь (правила описаны выше).
  2. Запрашивает блокировку директории по реальному пути, полученному после разрешения символьных ссылок — так два пути к одной папке (через ссылку и напрямую) все равно будут обрабатываться последовательно.
  3. Записывает файлы агента CLAUDE.md / AGENTS.md.predictorx/project/resources.json) в директорию пользователя. Агент работает прямо там, как если бы вы сами открыли эту папку.
  4. Сохраняет системные артефакты Предиктор Икс (output/, logs/, .gc_meta.json) в отдельном каталоге envRoot за пределами пользовательской директории.

Если во время выполнения первой задачи поступает вторая задача для той же директории, она переходит в режим ожидания со статусом Ожидание освобождения локальной директории (等待本地目录释放). Этот статус отображается везде, где видна задача: в плашке чата, баннере агента, логе выполнения и индикаторе активности. Припаркованная задача учитывается в очереди агента. Отмена припаркованной задачи мгновенно освобождает ее слот; отмена выполняющейся задачи позволяет запустить следующую в очереди.

Ожидание не ограничено по времени — припаркованная задача ждет, пока блокировка не будет снята либо пока пользователь или агент не отменят ее.

Что Предиктор Икс будет и не будет изменять в вашей директории

  • Будет записывать файлы CLAUDE.md / AGENTS.md (или их аналоги для провайдера вашего агента) и .predictorx/project/resources.json в корень директории, чтобы у агента был доступ к мета-навыку и списку ресурсов. Добавьте их в ваш .gitignore, если не хотите отправлять их в коммит.
  • Будет записывать любые изменения кода, которые решит внести агент — точно так же, как если бы вы запустили агента локально сами.
  • Никогда физически не удалит директорию или файлы в ней. Процесс очистки мусора (garbage collection) учитывает пути: для local_directory он удаляет только собственные папки output/ и logs/ в workspacesRoot, не затрагивая директорию пользователя.

Ограничения версии v1 (будут устранены в следующих обновлениях)

Первый релиз намеренно содержит больше ограничений по сравнению с github_repo. Ожидается, что этот список со временем сократится; на сегодняшний день актуально следующее:

  • Нет автоматического переключения веток. Агент работает в той ветке, которая у вас сейчас открыта. Переключите ветку перед запуском задачи, если это важно.
  • Нет защиты нефиксированных изменений (dirty tree) или автокоммитов. Незакоммиченные изменения видны агенту, могут быть изменены им на месте и не будут сохранены во временный индекс (stash). Относитесь к директории как к реальной рабочей копии и делайте коммиты перед запуском сложных задач.
  • Нет автоматического создания PR. По окончании задачи изменения остаются на той ветке, где они были сделаны — ничего автоматически не отправляется в удаленный репозиторий и PR не создается. Отправьте изменения и откройте PR самостоятельно, когда будете готовы.
  • Статус waiting_local_directory не показывает, кто занял директорию. Индикатор сообщает, что задача припаркована, но не показывает, какая именно задача или путь к файлу удерживают директорию в данный момент.

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

Привязка репозиториев при создании проекта

В Web и Desktop приложениях при создании нового проекта теперь отображается кнопка выбора репозиториев (Repos) рядом с полями Status, Priority и Lead. Выбор репозиториев воркспейса (или вставка произвольного URL) привязывает их в качестве ресурсов github_repo в момент создания проекта.

Через CLI:

# Создание проекта и привязка репозитория за один шаг. Сервер привязывает
# ресурсы в рамках той же транзакции, что и создание проекта — некорректные
# ресурсы отменят всю операцию целиком, предотвращая создание полупустых проектов.
predictorx project create \
  --title "Agent UX 2026" \
  --repo https://github.com/predictorx-ai/predictorx

# Управление ресурсами в дальнейшем
predictorx project resource list <project-id>
predictorx project resource add  <project-id> --type github_repo --url <url>
predictorx project resource remove <project-id> <resource-id>

# Универсальный способ добавления любого типа ресурса, который поддерживает сервер —
# изменения CLI не требуются при выходе новых типов:
predictorx project resource add <project-id> \
  --type notion_page \
  --ref '{"page_id":"…","title":"…"}'

Параметр --repo можно указывать несколько раз; каждое значение будет добавлено как отдельный ресурс github_repo.

Что агент видит во время выполнения

Когда демон запускает агента для работы над задачей внутри проекта, происходят две вещи:

1. .predictorx/project/resources.json

Структурированные данные из ответа API записываются в рабочую директорию агента:

{
  "project_id": "…",
  "project_title": "Agent UX 2026",
  "resources": [
    {
      "id": "…",
      "resource_type": "github_repo",
      "resource_ref": {
        "url": "https://github.com/predictorx-ai/predictorx",
        "default_branch_hint": "main"
      }
    }
  ]
}

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

2. Раздел «Project Context» в промпте мета-навыка

Файлы агента CLAUDE.md / AGENTS.md (в зависимости от провайдера) теперь включают понятное человеку описание:

## Project Context

This issue belongs to **Agent UX 2026**.

Project resources (also written to `.predictorx/project/resources.json`):

- **GitHub repo**: https://github.com/predictorx-ai/predictorx (default branch: `main`)

Resources are pointers — open them only when relevant to the task. For
`github_repo` resources, use `predictorx repo checkout <url>` to fetch the code.

Текст намеренно сделан лаконичным. Полные данные находятся на диске; промпт лишь ориентирует агента, сообщая о существовании проекта и привязанных к нему ресурсах.

Поведение при сбоях

Получение ресурсов работает по принципу best-effort (с максимальными усилиями). Если запрос к API завершается ошибкой, раздел проекта исключается из промпта и файл на диск не записывается, но задача все равно запускается. Агенты никогда не блокируют работу из-за отсутствия контекста проекта.

Добавление нового типа ресурса

Главная цель этой абстракции — сделать добавление новых типов дешевым. Полный путь внедрения:

  1. Валидатор на сервере (server/internal/handler/project_resource.go) — добавьте условие в метод validateAndNormalizeResourceRef, которое парсит и нормализует новую полезную нагрузку.
  2. Форматирование мета-навыка на демоне (server/internal/daemon/execenv/runtime_config.go) — добавьте ветку в formatProjectResource, чтобы промпт агента отображал новый тип в виде читаемого списка.
  3. Типы TypeScript (packages/core/types/project.ts) — расширьте ProjectResourceType и добавьте интерфейс полезной нагрузки.
  4. Рендеринг в интерфейсе (packages/views/projects/components/project-resources-section.tsx) — добавьте вариант отображения в ResourceRow для нового типа.

При этом не требуются миграции БД, новые запросы sqlc, новые эндпоинты и изменения CLI — универсальный флаг CLI --ref '<json>' принимает любую полезную нагрузку, которую понимает валидатор, поэтому поддержка нового типа с первого дня сводится исключительно к четырем шагам выше (позже вы можете по желанию добавить короткую команду CLI, но это необязательно).

Таблица project_resource и те же три CRUD-запроса работают со всеми типами ресурсов.

Репозитории воркспейса против репозиториев проекта

Список репозиториев, показываемый агенту (блок ## Repositories в файле CLAUDE.md / AGENTS.md), выбирается обработчиком демона в следующем порядке приоритета:

  • У проекта есть хотя бы один ресурс github_repo → агенту показываются только эти репозитории. Репозитории воркспейса намеренно скрываются, чтобы агенту не приходилось гадать, какой из них относится к задаче.
  • У проекта нет ресурсов github_repo (или задача создана вне проекта) → демон возвращает список репозиториев воркспейса, как и раньше.

Это позволяет держать рабочее окружение агента в чистоте: если в проекте явно указаны его репозитории, этот список считается единственно верным. Структурированный список в .predictorx/project/resources.json всегда содержит полный набор ресурсов, поэтому скрипты, которым нужно проверить всё, по-прежнему могут это сделать.

Демон дублирует это поведение на этапе получения кода: когда поступает задача с URL-адресами github_repo из проекта, эти URL добавляются во внутренний разрешенный список воркспейса и синхронизируются в локальный кэш до запуска агента. Таким образом, URL репозитория проекта, не привязанный к воркспейсу, все равно остается корректным аргументом для команды predictorx repo checkout — демон не отклонит его как «ненастроенный». Разделение списков происходит внутри системы: адреса воркспейса и адреса задач отслеживаются отдельно, поэтому обновление репозиториев воркспейса не приведет к случайному отзыву прав на URL проекта во время работы.

Что намеренно не входит в рамки текущей реализации

  • Общий доступ между проектами. Каждый ресурс на сегодняшний день жестко принадлежит только одному проекту.
  • Ограничение ресурсов для конкретных навыков. Все ресурсы видны каждому навыку при запуске агента; фильтрация с учетом типов будет реализована позже.
  • Кэширование и синхронизация. Ресурс github_repo — это просто метаданные; получение кода по-прежнему происходит по команде predictorx repo checkout по требованию. Кэширование текста документов для Notion / Google Docs появится вместе с реализацией соответствующих типов ресурсов.

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