プロジェクトリソース
型付きのポインター(Git リポジトリ、ローカルディレクトリ、今後さらに増える種類)をプロジェクトに添付し、エージェントが範囲を限定したコンテキストとして取り込めるようにします。
プロジェクトリソース(Project Resource) は型付きのポインターです — Git リポジトリの URL、自分のマシン上のパス、いずれは Notion ページまで — これをプロジェクトに添付します。エージェントがそのプロジェクト内のイシューに対して実行されると、デーモンはプロジェクトのリソース一覧をエージェントの作業ディレクトリとメタスキルプロンプトに自動的に書き込みます。
その結果、エージェントは、どのリポジトリをチェックアウトすべきか(またはどのローカルディレクトリで作業すべきか)、そしてこのプロジェクトの「主要な参照資料」が何かを、誰もコンテキストをイシュー本文にコピー&ペーストしなくても把握できます。
メンタルモデル
プロジェクトはもはや単なるラベルではありません。小さな リソースコンテナ です。
- プロジェクトは 0..N 個の リソース を持ちます。
- リソースは
resource_type(例:github_repo、local_directory)とresource_ref(resource_typeによって型が定まる JSON ペイロード)を持ちます。 - 新しいリソースタイプを追加するには、文字列1つ + ハンドラー1つを追加するだけです。スキーマのマイグレーションも、フロントエンドの書き直しも不要です。
この形は意図的なものです — Multica がエージェントプロバイダーですでに使っているのと同じパターンです: type の判別子1つと型付きのペイロード。スキーマを安定させるため、後で「Notion ページ」「Google Doc」「アップロードされたファイル」「外部 URL」を追加するのは、小さく追加的な変更で済みます。
現在、2つのリソースタイプが提供されています: 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
タスクごとに再クローンするのが現実的でないリポジトリ — 数ギガバイトのゲームのチェックアウト、大規模な monorepo、またはタスクごとのワークツリーモデルが煩わしいあらゆるプロジェクト — の場合、プロジェクトは代わりに 特定のデーモンのマシン上にある既存のディレクトリ を指すことができます。エージェントは、クローンもコピーもワークツリーもなしに そのフォルダ内で直接 実行されます。
{
"resource_type": "local_directory",
"resource_ref": {
"local_path": "/Users/me/code/big-game",
"daemon_id": "0001234e-…",
"label": "main checkout"
}
}github_repo と比べたトレードオフは意図的です。バインドされたデーモンだけがそのディレクトリに対するタスクを取得でき、同じディレクトリに対するタスクは並列ではなく 直列で 実行されます。その代わり、既存のチェックアウト、既存のブランチ、既存のダーティな状態をそのまま保てます — Multica は決して再クローンしません。
github_repo より local_directory を選ぶとき
| 検討事項 | github_repo(ワークツリー) | local_directory |
|---|---|---|
| タスクごとのチェックアウトコスト | 新規クローン + ワークツリー | なし — エージェントがその場で実行 |
| 同じリポジトリでの並行性 | 複数タスクを並列に | ディレクトリごとに一度に1つ |
| ブランチ / ダーティな状態 | タスクごとにデフォルトから新しいブランチを取得 | ディレクトリが現在持っているそのまま |
| 実行できる場所 | 任意のデーモン | ちょうど1つのデーモン(バインドされたもの) |
| ディスク使用量 | タスクごとにワークツリー1つ | オーバーヘッド0 — 既存のフォルダ |
次のいずれか 1つでも 当てはまる場合は local_directory を選んでください。
- 再クローンのコストが法外に大きい場合 — 数ギガバイトのゲームのチェックアウト、重い LFS アセットを持つ monorepo、またはタスクごとの
git cloneが実際の作業を圧倒するあらゆる場合。並行性をクローン不要の実行と引き換えにすることになります。 - 変更がきめ細かく、変更が起きるそばからローカルでレビューしたい場合 — 単一のコンポーネントを繰り返し磨いていて、数分ごとにエージェントの編集と自分のエディターを行き来したく、
~/multica_workspaces/から掘り出さなければならないタスクごとのワークツリーよりも、既存のチェックアウトを信頼できる情報源にしたい場合です。
どちらの場合でも受け入れるトレードオフは同じです: このバージョンはファイル単位の書き込みロックを提供しません。 ディレクトリごとの直列ゲート(同じフォルダで一度に1つのタスク)が、別々の2つのイシューのエージェントが同時に同じファイルを触るのを防ぐ唯一の保護手段です。2つのイシューのエージェントを同じ local_directory に向けると、それらのタスクは並列化されずにキューに入ります — これは意図された動作です。同じコードベースで本物の並列性が必要なら、github_repo を使い続けてください。
ローカルディレクトリを添付する
フォルダピッカーは Desktop アプリ にのみあります — Web アプリは OS のパスを読み取る方法がないため、「ローカルディレクトリを追加」ボタンはそこでは非表示になっています。Desktop では:
- プロジェクトを開く → Resources パネル。
- ローカルディレクトリを追加 をクリックします。ネイティブのフォルダピッカーが開きます。
- フォルダを選択します。そのパスは この Desktop インストールが現在登録しているデーモン にバインドされます — リソースレコードにはパスとそのデーモンの ID が一緒に保存されます。
Desktop では、このマシンのデーモンがオフラインのとき、またはプロジェクトにすでにこのデーモンへバインドされた local_directory があるとき、ボタンは表示されたまま ヒントとともに無効化 されます — そのため なぜ 使えないのかが分かります。(Web アプリではそもそもフォルダピッカーが一切ないため、ボタンは完全に非表示になります。)別のマシンのディレクトリをバインドするには、そのマシンに Desktop をインストールし、そこからリソースを追加してください。
CLI からも可能です(デーモン ID を自分で指定すれば、Web 専用環境でも動作します)。
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>' の脱出口も受け付けます。
パスのルール
添付するパスは、添付時の検証とタスクごとの検証の両方を通過しなければなりません。どちらもリソースを所有するデーモンが強制します — サーバーは JSON を保存するだけです。いずれかのルールに違反するパスは、型付きのエラーとともにタスクを失敗させ、あなたのディレクトリには手を付けずに残します。
- 必ず 絶対パス でなければなりません。
- 必ず 存在 し、ディレクトリ でなければなりません(ファイル、ファイルへの symlink、デバイスノードではなく)。
- デーモンプロセスが 読み書き可能 でなければなりません。
- システムルートやユーザープロファイル全体であってはいけません —
/、/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 がエイリアス処理するパスの正規形(canonical form)も同様です(例: macOS で
/private/tmpを入力するのは/tmpと同じように拒否されます)。
このブラックリストは意図的に攻撃的です — ホームディレクトリを選ぶと Multica のランタイムファイルがアカウントのルートに置かれることになりますが、これは決して望ましい結果ではありません。代わりにサブフォルダ(通常は実際のプロジェクトのチェックアウト)を選んでください。
(プロジェクト、デーモン)ごとに1つ
プロジェクトは デーモンごとに最大1つの local_directory しか持てません。同じデーモンに2つ目を追加しようとすると、API は 409 を返します。Desktop のボタンは上限にすでに達すると自動的に非表示になり、理由を説明するツールチップを表示します。
異なるデーモンは独立しています — 共有プロジェクトはチームメイトのマシンごとに1つずつ local_directory を持つことができ、それぞれが同じプロジェクトを別々のホストの別々のフォルダにバインドします。デーモンがタスクを取得するときは、自分の ID に一致する行を選び、残りは無視します。
リソースタイプの混在、および複数の local_directory リソース
実際に登場する2つの横断的なリソース構成があります。
- 同じプロジェクトに
github_repo+local_directory。 一致するlocal_directoryバインディングを持つデーモンでは、ローカルディレクトリが 優先 されます。エージェントはあなたのフォルダで実行され、デーモンはそのタスクのためにgithub_repoワークツリーを作成も使用もしません。(ワークスペースごとのリポジトリキャッシュは平常どおり同期される場合がありますが、これはこのタスクの作業ツリーとは無関係なバックグラウンドの動作です。)github_repoの URL は参照用として.multica/project/resources.jsonとエージェントの## Repositoriesセクションに依然として表示されますが、エージェントが編集する作業ツリーはワークツリーではなく、あなたのローカルなものです。このプロジェクトに対するlocal_directory行を 持たない デーモン(別のマシン、またはそのチームメイトが1つを添付する前)では、タスクは通常のgithub_repoワークツリーのフローにフォールバックします。実質的に、ローカルディレクトリはワークツリーパスに対するデーモンごとのオーバーライドです。 - 同じプロジェクトに2つの
local_directoryリソース。 各local_directoryはちょうど1つのデーモンにバインドされるため、これは別々の2つのマシンの間でのみ発生します(API は添付時に同じデーモンへの2つを拒否します。上記参照)。タスクは、どのデーモンがローカルディレクトリを持っているかではなく、エージェントのランタイム割り当てによってルーティングされます。タスクは受信するエージェントのランタイムを所有するデーモンに届き、そのデーモンは自分の ID に一致するlocal_directory行を選び、残りは無視します。ロードバランシングはありません — 特定のマシンにタスクを実行させたい場合は、そのマシンのランタイムにバインドされたエージェントをディスパッチしてください。
別の場所に1つがバインドされているプロジェクトに対して local_directory 行を持たないデーモンは ブロックされません — そのタスクは単に、プロジェクトの他のリソース(通常は github_repo のフォールバック)を通じて進みます。local_directory は、それがバインドされたデーモンに対してのみ意味があります。
ローカルディレクトリに対してタスクを実行する
プロジェクトが受信デーモンにバインドされた local_directory を持つイシューでタスクがディスパッチされると、デーモンは次のことを行います。
- パスを再検証します(上記のルール)。
- symlink を解決した実際のパスをキーとして、ディレクトリごとのロックを取得します — そのため、同じフォルダに向かう2つの経路(1つは symlink 経由、1つは直接)も依然として直列化されます。
- エージェントの
CLAUDE.md/AGENTS.md(および.multica/project/resources.json)を ユーザーのディレクトリ内に 書き込みます。エージェントは、あなたが自分でそのフォルダを開いたのとまったく同じように、そこで作業します。 - Multica のランタイム成果物(
output/、logs/、.gc_meta.json)は、ユーザーのディレクトリの 外側 の別の envRoot に置きます。
同じディレクトリに対する2つ目のタスクが、1つ目のタスクの実行中に届くと、ステータス ローカルディレクトリ待ち(Waiting for local directory) で待機します。このステータスは、タスクがあるあらゆる場所で見えます — チャットのタスクピル、エージェントのバナー、実行ログ、アクティビティインジケーター — そして待機中のタスクはエージェントの「キュー済み」のプレゼンスにカウントされます。待機中のタスクをキャンセルすると、そのスロットが即座に解放されます。実行中のタスクをキャンセルすると、次のタスクが昇格します。
この待機はタイムアウトではありません — 待機中のタスクは、ロックが解放されるか、ユーザー / エージェントがキャンセルするまで待機し続けます。
Multica があなたのディレクトリで触れるものと触れないもの
- 書き込みます:
CLAUDE.md/AGENTS.md(またはエージェントのプロバイダーに対応する同等物)と.multica/project/resources.jsonをディレクトリのルートに。そのためエージェントはメタスキルとリソース一覧を持ちます。コミットされたくない場合は、これらを.gitignoreに追加してください。 - 書き込みます: エージェントが行うと判断したあらゆるコード編集を — あなたが自分でローカルでエージェントを実行したのとまったく同じ方法で。
- 物理的に削除することは決してありません: ディレクトリやその中の何も。ガベージコレクションはパスを認識します:
local_directoryの envRoot の場合、workspacesRootの下にある自身のoutput/とlogs/だけをクリーンアップし、ユーザーのディレクトリは立ち入り禁止として扱います。
v1 の制限事項(後続作業で狭まる予定)
最初のリリースは意図的に github_repo より鋭い角を持って出荷されます。この一覧は時間とともに縮小していくと考えてください — ここに記載されているのは今日時点で事実の内容です。
- 自動ブランチ切り替えなし。 エージェントは、あなたがチェックアウトしているブランチで実行されます。重要なら、ディスパッチ前にブランチを切り替えてください。
- ダーティツリーの保護や自動コミットなし。 コミットされていない変更はエージェントから見え、その場で変更される可能性があり、stash されません。ディレクトリを実際の作業ツリーとして扱い、危険な実行の前にコミットしてください。
- 自動 PR なし。 タスクが終わると、変更は作られたブランチのまま残ります — 何も push されず、PR も開かれません。準備ができたら、自分で push して PR を開いてください。
waiting_local_directoryはステータスを示しますが、保有者は示しません。 バッジはタスクが待機していることを伝えます。どのタスクやどのファイルパスが現在ディレクトリを保有しているかは表示しません。
これらはローカルディレクトリ作業のエージェントタスクライフサイクルの後続項目として追跡されています。それが出荷されるまでは、local_directory を「エージェントがあなたのフォルダで、あなたがするのと同じ方法で実行する」ものとして扱ってください。
プロジェクト作成時にリポジトリを添付する
Web または Desktop アプリで 新規プロジェクト を開くと、ステータス / 優先度 / リードの横に Repos ピルが表示されるようになりました。ワークスペースにバインドされたリポジトリを選択する(またはアドホックな URL を貼り付ける)と、プロジェクトが作成される瞬間にそれらが github_repo リソースとして添付されます。
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 リソースとして添付されます。
ランタイムにエージェントが見るもの
デーモンがプロジェクト内のイシューのためにエージェントを生成すると、2つのことが起こります。
1. .multica/project/resources.json
API レスポンスの構造化されたパススルー(pass-through)で、エージェントの作業ディレクトリに書き込まれます。
{
"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"
}
}
]
}スキル、ヘルパースクリプト、またはエージェント自身が、この実行のための 正確な リソースの集合が必要なときに、このファイルをパースできます。
2. メタスキルプロンプトの「Project Context」セクション
エージェントの CLAUDE.md / AGENTS.md(プロバイダーによって異なる)には、人間が読める要約が含まれるようになりました。
## 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.このテキストは意図的に最小限です。完全なペイロードはディスク上にあり、プロンプトはエージェントがプロジェクトが存在することと何が添付されているかを把握できるように方向付けるだけです。
失敗モード
リソースの取得は best-effort です。API 呼び出しが失敗すると、プロンプトからプロジェクトセクションが省略され、ファイルも書き込まれませんが、タスクは依然として開始されます。エージェントは、欠落したプロジェクトコンテキストのために止まることは決してありません。
新しいリソースタイプを追加する
この抽象化の要点は、新しいタイプが安価だということです。完全な経路は:
- サーバーの検証器(
server/internal/handler/project_resource.go)—validateAndNormalizeResourceRefに、新しいペイロードをパースして正規化する case を追加します。 - デーモンのメタスキルフォーマッター(
server/internal/daemon/execenv/runtime_config.go)—formatProjectResourceに case を追加し、エージェントのプロンプトが新しいタイプを読みやすい箇条書きとしてレンダリングするようにします。 - TypeScript の型(
packages/core/types/project.ts)—ProjectResourceTypeを拡張し、ペイロードのインターフェースを追加します。 - UI レンダラー(
packages/views/projects/components/project-resources-section.tsx)—ResourceRowに新しいタイプのための case を追加します。
スキーマのマイグレーションも、新しい sqlc クエリも、新しいエンドポイントも、そして CLI の変更もありません — CLI の汎用的な --ref '<json>' フラグが、検証器が理解するあらゆるペイロードを受け付けるため、新しいタイプの初日サポートは純粋に上記の4ステップだけです。(後でタイプごとの CLI ショートカットを 任意で 追加できますが、必須ではありません。)
同じ project_resource テーブルと同じ3つの CRUD 呼び出しが、すべてのタイプを処理します。
ワークスペースのリポジトリ vs. プロジェクトのリポジトリ
エージェントに表示されるリポジトリ一覧(CLAUDE.md / AGENTS.md の ## Repositories ブロック)は、デーモンのクレームハンドラーが次の優先順位で選びます。
- プロジェクトが最低1つの
github_repoリソースを持つ → そのリポジトリだけがエージェントに出されます。ワークスペースにバインドされたリポジトリは、エージェントがこのイシューにどれが属するかを推測しなくて済むように、意図的に隠されます。 - プロジェクトが
github_repoリソースを持たない(またはイシューがプロジェクトに属さない) → 従来どおりワークスペースのリポジトリ一覧にフォールバックします。
これによりエージェントの作業セットが引き締まります: プロジェクトがリポジトリについて明示的であれば、それが権威ある答えです。.multica/project/resources.json の構造化されたリソース一覧は常に完全な集合を運ぶため、すべてを検査したいスキルは依然としてそうできます。
デーモンはチェックアウト側でもこれを反映します: プロジェクト範囲の github_repo URL を持つタスクが届くと、それらの URL はエージェントが生成される前に、ワークスペースごとの許可リストにマージされ 同時に ローカルのリポジトリキャッシュに同期されます。そのため、ワークスペースレベルでバインドされていないプロジェクトのリポジトリ URL も、依然として multica repo checkout の有効な引数になります — デーモンはそれを「構成されていない」として拒否しません。許可リストの分割は内部的なものです: ワークスペースにバインドされた URL とタスク範囲の URL は別々に追跡されるため、ワークスペースリポジトリの再読み込みが実行の途中でプロジェクト URL を誤って取り消すことはありません。
ここで意図的に範囲に 含めなかった もの
- プロジェクト間の共有。 今日時点で、各リソースはちょうど1つのプロジェクトにのみ存在します。
- スキルごとのリソース範囲指定。 すべてのリソースは、エージェント実行のすべてのスキルから見えます。タイプを認識したフィルタリングは後続作業です。
- キャッシュ / 同期。
github_repoは単なるメタデータです — チェックアウトは依然として必要に応じてmultica repo checkoutを通じて行われます。Notion / Google Docs のキャッシュされた文書テキストは、それらのタイプとともに提供される予定です。
これらは意図的な省略です — 最初のカットの目標は、可動部分を最小限にしてこの抽象化を検証することです。