Project Resources
Прикрепляйте типизированные указатели (Git-репозитории, локальные каталоги и др. позже) к project, чтобы agent получал их как scoped context.
Project Resource — типизированный указатель: URL Git-репозитория, путь на вашей машине, страница Notion завтра — прикреплённый к project. Когда agent выполняет task по issue внутри этого project, daemon автоматически записывает список ресурсов project в рабочий каталог agent и в его meta-skill prompt.
В результате agent знает, какой репозиторий checkout (или в каком локальном каталоге работать) и какие документы — «основные ссылки» для этого project, без копирования контекста в тело issue.
Ментальная модель
Project — уже не просто метка. Это небольшой контейнер ресурсов:
- У project есть 0..N resources.
- У resource есть
resource_type(напримерgithub_repo,local_directory) иresource_ref(JSON payload, типизированныйresource_type). - Новые типы resource добавляют строку и handler. Без миграции схемы. Без переписывания frontend.
Форма намеренная — тот же паттерн, что Multica уже использует для provider agent: дискриминатор type и типизированный payload. Схема остаётся стабильной, поэтому добавление «Notion page», «Google Doc», «uploaded file» или «external URL» позже — небольшое аддитивное изменение.
Сейчас доступны два типа resource: github_repo (clone-per-task в изолированный worktree) и local_directory (выполнение напрямую в папке на машине конкретного daemon).
Resource type: github_repo
Тип resource по умолчанию — checkout на каждый task в изолированный worktree:
{
"resource_type": "github_repo",
"resource_ref": {
"url": "https://github.com/owner/repo",
"default_branch_hint": "main"
}
}default_branch_hint необязателен — если указан, daemon показывает его в meta-skill, чтобы agent знал, на какую ветку опираться.
Resource type: local_directory
Для репозиториев, которые нельзя разумно переклонировать на каждый task — многогигабайтные game checkout, крупные monorepo или любой project, где модель worktree-per-task неудобна — project может указывать на существующий каталог на машине конкретного daemon. Agent работает напрямую в этой папке, без clone, копирования и worktree.
{
"resource_type": "local_directory",
"resource_ref": {
"local_path": "/Users/me/code/big-game",
"daemon_id": "0001234e-…",
"label": "main checkout"
}
}Компромисс относительно github_repo намеренный: только привязанный daemon может забирать task для этого каталога, и task на одном каталоге выполняются последовательно, а не параллельно. Взамен вы сохраняете текущий checkout, ветку и dirty state — Multica никогда не переклонирует каталог.
Когда выбрать local_directory вместо github_repo
| Аспект | github_repo (worktree) | local_directory |
|---|---|---|
| Стоимость checkout на task | Свежий clone + worktree | Нет — agent работает на месте |
| Параллелизм на одном repo | Много task параллельно | По одному на каталог |
| Ветка / dirty state | Каждый task получает свежую ветку от default | Что есть в каталоге сейчас |
| Где может выполняться | Любой daemon | Ровно один daemon (привязанный) |
| Диск | Один worktree на task | Нулевые накладные — ваша папка |
Выбирайте local_directory, если хотя бы одно из условий выполняется:
- Переклонирование слишком дорого — многогигабайтный game checkout, monorepo с тяжёлыми LFS-ассетами или всё, где
git cloneна task доминирует над самой работой. Вы жертвуете параллелизмом ради запуска без clone. - Изменения мелкие, и вы хотите review локально по ходу — вы итерируете один компонент, переключаетесь между правками agent и редактором каждые несколько минут и предпочитаете существующий checkout как source of truth, а не per-task worktree из
~/multica_workspaces/.
Компромисс в обоих случаях один: в этой версии нет file-level write lock. Единственная защита — последовательный gate на каталог (один task за раз на одну папку) от одновременного доступа agent из разных issue к одним файлам. Если направить agent двух issue на один local_directory, их task встают в очередь, а не параллелятся — так задумано. Нужен настоящий параллелизм на одной кодовой базе — оставайтесь на github_repo.
Прикрепление локального каталога
Folder picker есть только в Desktop app — веб-приложение не может читать пути ОС, поэтому кнопка «Add local directory» там скрыта. В Desktop:
- Откройте project → панель Resources.
- Нажмите Add local directory. Откроется нативный folder picker.
- Выберите папку. Путь привязывается к daemon, зарегистрированному этой установкой Desktop — в записи resource хранятся и путь, и ID этого daemon.
В Desktop кнопка видна, но отключена с подсказкой, когда daemon на этой машине offline или когда у project уже есть local_directory, привязанный к этому daemon — чтобы было видно, почему недоступно. (В веб-приложении кнопка скрыта полностью — folder picker там недоступен.) Чтобы привязать каталог другой машины, установите Desktop на ней и добавьте resource оттуда.
Из CLI (работает и в web-only средах, если вы сами укажете daemon ID):
multica project resource add <project-id> \
--type local_directory \
--local-path /Users/me/code/big-game \
--daemon-id <daemon-uuid> \
--ref-label "main checkout" # optional
multica project resource update <project-id> <resource-id> \
--local-path /Users/me/code/big-game-new--daemon-id берётся из multica daemon list. CLI также принимает универсальный --ref '<json>', если хотите передать payload напрямую.
Правила для путей
Прикрепляемый путь должен пройти проверку при attach и при каждом task. Обе проверки выполняет daemon, владеющий resource — сервер хранит только JSON. Путь, нарушающий любое правило, завершает task с типизированной ошибкой и не трогает ваш каталог:
- Должен быть абсолютным.
- Должен существовать и быть каталогом (не файлом, symlink на файл или device node).
- Должен быть readable и writable для процесса daemon.
- Нельзя указывать системный корень или весь профиль пользователя —
/,/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. - Symlink, разрешающийся в любой из перечисленных путей, отклоняется; то же для канонической формы OS-aliased path (например на macOS
/private/tmpотклоняется так же, как/tmp).
Blacklist намеренно жёсткий — выбор home directory поместил бы runtime-файлы Multica в корень аккаунта, чего вы не хотите. Указывайте подпапку (обычно ваш project checkout).
Один на (project, daemon)
У project может быть не более одного local_directory на daemon. Попытка добавить второй на том же daemon возвращает 409 от API; кнопка Desktop скрывается при достижении лимита и показывает tooltip с объяснением.
Разные daemon независимы — общий project может иметь по одному local_directory на машину каждого коллеги, привязывая один project к разным папкам на разных хостах. Когда daemon забирает task, он выбирает строку со своим ID и игнорирует остальные.
Смешение типов resource и несколько local_directory
На практике встречаются две кросс-resource конфигурации:
github_repo+local_directoryв одном project. На daemon с подходящей привязкойlocal_directoryлокальный каталог имеет приоритет: agent работает в вашей папке, daemon не создаёт и не использует worktreegithub_repoдля этого task. (Per-workspace repo cache может синхронизироваться как обычно — это фоновое поведение, не связанное с worktree этого task.) URLgithub_repoвсё равно появляется в.multica/project/resources.jsonи в секции## Repositoriesagent для справки — но worktree, который редактирует agent, ваш локальный, а не worktree. На daemon без строкиlocal_directoryдля этого project (другая машина или до attach коллегой) task идёт по обычному flow worktreegithub_repo. По сутиlocal_directory— per-daemon override пути worktree.- Два
local_directoryв одном project. Поскольку каждыйlocal_directoryпривязан ровно к одному daemon, это возможно только на двух разных машинах (API отклоняет два на одном daemon при attach, см. выше). Task маршрутизируются по runtime assignment agent, а не по тому, у какого daemon есть local directory: task попадает на daemon, владеющий runtime принимающего agent; этот daemon выбирает строкуlocal_directoryсо своим ID и игнорирует остальные. Load-balancing нет — нужна конкретная машина, отправьте agent, привязанный к runtime этой машины.
Daemon без строки local_directory для project, у которого она привязана на другой машине, не блокируется — его task идут через другие resource project (обычно fallback github_repo). local_directory важен только для привязанного daemon.
Выполнение task против local directory
Когда task отправлен по issue, чей project имеет local_directory, привязанный к принимающему daemon, daemon:
- Повторно проверяет путь (правила выше).
- Берёт per-directory lock по symlink-resolved real path — два маршрута к одной папке (через symlink и напрямую) всё равно сериализуются.
- Записывает
CLAUDE.md/AGENTS.mdagent (и.multica/project/resources.json) в каталог пользователя. Agent работает там, как если бы вы сами открыли папку. - Хранит runtime-артефакты Multica (
output/,logs/,.gc_meta.json) в отдельном envRoot вне каталога пользователя.
Если второй task для того же каталога приходит, пока первый выполняется, он паркуется со status Waiting for local directory. Status виден везде, где отображается task — task pill в чате, banner agent, execution log и activity indicator — и припаркованный task учитывается в «queued» presence agent. Отмена припаркованного task сразу освобождает слот; отмена выполняющегося — следующий продвигается.
Ожидание не по таймауту — припаркованный task остаётся припаркованным, пока lock не освободится или пользователь / agent не отменит его.
Что Multica трогает и не трогает в вашем каталоге
- Запишет
CLAUDE.md/AGENTS.md(или эквивалент для provider agent) и.multica/project/resources.jsonв корень каталога, чтобы у agent были meta-skill и список resource. Добавьте их в.gitignore, если не хотите коммитить. - Запишет любые правки кода, которые решит внести agent — так же, как если бы вы запустили agent локально сами.
- Никогда физически не удалит каталог или его содержимое. Garbage collection учитывает путь: для
local_directoryenvRoots очищаются только собственныеoutput/иlogs/подworkspacesRoot; каталог пользователя вне зоны доступа.
Ограничения v1 (будут ужесточены позже)
Первый релиз намеренно острее, чем github_repo. Список будет сокращаться — ниже то, что верно сегодня:
- Нет автоматического переключения веток. Agent работает в той ветке, что у вас checkout. Переключите ветку до dispatch, если это важно.
- Нет защиты dirty tree и auto-commit. Незакоммиченные изменения видны agent, могут меняться на месте и не stash'атся. Считайте каталог реальным working tree и коммитьте перед рискованными запусками.
- Нет автоматического PR. По завершении task изменения остаются на той ветке, где сделаны — ничего не push'ится и PR не открывается. Push и PR — сами, когда готовы.
waiting_local_directoryпоказывает status, а не holder. Badge говорит, что task припаркован; не показывает, какой task или путь сейчас держит каталог.
Это отслеживается как follow-up agent-task-lifecycle к local-directory; пока он не вышел, считайте local_directory как «agent работает в вашей папке так же, как вы».
Прикрепление repo при создании project
В Web или Desktop app при открытии New project появляется pill Repos рядом со Status / Priority / Lead. Выбор repo, привязанных к workspace (или вставка ad-hoc URL), прикрепляет их как github_repo resource в момент создания project.
Из CLI:
# Create + attach in one shot. The server attaches resources in the same
# transaction as the project create — invalid resources roll back the whole
# operation, so you never end up with a project that has half its resources.
multica project create \
--title "Agent UX 2026" \
--repo https://github.com/multica-ai/multica
# Manage resources later
multica project resource list <project-id>
multica project resource add <project-id> --type github_repo --url <url>
multica project resource remove <project-id> <resource-id>
# Generic escape hatch for any resource_type the server understands —
# no CLI change needed when a new type ships:
multica project resource add <project-id> \
--type notion_page \
--ref '{"page_id":"…","title":"…"}'--repo можно повторять; каждое значение прикрепляется как отдельный github_repo resource.
Что agent видит в runtime
Когда daemon запускает agent для issue внутри project, происходят две вещи:
1. .multica/project/resources.json
Структурированный pass-through ответа API, записанный в рабочий каталог agent:
{
"project_id": "…",
"project_title": "Agent UX 2026",
"resources": [
{
"id": "…",
"resource_type": "github_repo",
"resource_ref": {
"url": "https://github.com/multica-ai/multica",
"default_branch_hint": "main"
}
}
]
}Skill, helper scripts или сам agent могут парсить этот файл, когда нужен точный набор resource для запуска.
2. Секция «Project Context» в meta-skill prompt
CLAUDE.md / AGENTS.md agent (в зависимости от provider) теперь включает читаемое резюме:
## Project Context
This issue belongs to **Agent UX 2026**.
Project resources (also written to `.multica/project/resources.json`):
- **GitHub repo**: https://github.com/multica-ai/multica (default branch: `main`)
Resources are pointers — open them only when relevant to the task. For
`github_repo` resources, use `multica repo checkout <url>` to fetch the code.Текст намеренно минимален. Полный payload на диске; prompt лишь ориентирует agent, что project существует и что прикреплено.
Режим сбоя
Получение resource — best-effort. Если вызов API не удался, секция project опускается из prompt и файл не записывается, но task всё равно стартует. Agent никогда не блокируется из-за отсутствующего project context.
Добавление нового типа resource
Смысл абстракции — новые типы дешёвы. Полный путь:
- Server validator (
server/internal/handler/project_resource.go) — case вvalidateAndNormalizeResourceRef, который парсит и нормализует новый payload. - Daemon meta-skill formatter (
server/internal/daemon/execenv/runtime_config.go) — case вformatProjectResource, чтобы prompt agent рендерил новый тип читаемым bullet. - TypeScript types (
packages/core/types/project.ts) — расширитьProjectResourceTypeи добавить payload interface. - UI renderer (
packages/views/projects/components/project-resources-section.tsx) — case вResourceRowдля нового типа.
Нет миграции схемы, нового sqlc query, нового endpoint и изменения CLI — универсальный флаг --ref '<json>' CLI принимает любой payload, который понимает validator, поэтому day-one поддержка нового типа — только четыре шага выше. (Опционально можно добавить per-type CLI shortcut позже; не обязательно.)
Та же таблица project_resource и те же три CRUD-вызова обрабатывают каждый тип.
Workspace repo vs. project repo
Список repo для agent (блок ## Repositories в CLAUDE.md / AGENTS.md) выбирается claim handler daemon с таким приоритетом:
- У project есть хотя бы один
github_reporesource → agent видит только эти repo. Repo, привязанные к workspace, намеренно скрыты, чтобы agent не угадывал, какой относится к этому issue. - У project нет
github_reporesource (или issue не в project) → fallback на список repo workspace, как раньше.
Так working set agent остаётся узким: когда project явно указывает repo, это авторитетный ответ. Структурированный список в .multica/project/resources.json всегда несёт полный набор — skill, которому нужно всё, всё равно может прочитать.
Daemon зеркалит это на стороне checkout: когда task приходит с project-scoped github_repo URL, эти URL объединяются в per-workspace allowlist и синхронизируются в локальный repo cache до spawn agent. URL project repo, не привязанный на уровне workspace, всё равно валиден для multica repo checkout — daemon не отклонит его как «not configured». Разделение allowlist внутреннее: workspace-bound URL и task-scoped URL отслеживаются отдельно, поэтому refresh workspace repo не отзовёт project URL mid-run.
Что намеренно вне scope
- Cross-project sharing. Каждый resource сегодня живёт ровно в одном project.
- Per-skill resource scoping. Все resource видны каждому skill при запуске agent; type-aware filtering — follow-up.
- Caching / sync.
github_repo— только metadata; checkout по-прежнему черезmultica repo checkoutпо требованию. Кэшированный текст документов для Notion / Google Docs придёт с этими типами.
Это намеренные упущения — цель первого среза: проверить абстракцию с минимальным набором движущихся частей.
Комментарии и упоминания
Совместная работа под issue — комментарии, ответы, упоминания `@`, реакции и запуск agent из комментария.
Agents
Agent — полноценный member workspace Multica: ему можно назначать issue, оставлять комментарии и упоминать через `@`. Главное отличие от человека — он начинает работу сам и не получает уведомлений.