i18n: add japanese locale (MUL-2893) (#3538)

* i18n: add japanese locale

* fix: spacing issues

* refactor

* fix(desktop): set <html lang> before paint to avoid JA Kanji font flash

Switch the documentElement.lang sync from useEffect to useLayoutEffect so
lang is committed before the first paint. Otherwise Japanese desktop users
saw one frame of Kanji rendered with the Chinese-first fallback stack before
the html[lang|="ja"] CJK override applied. Also fix the stale selector in the
HTML_LANG comment (html[lang^="ja"] -> html[lang|="ja"]).

Addresses review nits on MUL-2893.

Co-authored-by: multica-agent <github@multica.ai>

* fix(docs): tokenize the ideographic iteration mark in JA search

Add U+3005 (々) to the Japanese search tokenizer character class. It sits just
below the kana blocks, so words like 様々 / 日々 / 個々 previously dropped the
mark and split awkwardly, hurting recall.

Addresses a review nit on MUL-2893.

Co-authored-by: multica-agent <github@multica.ai>

* fix(i18n): restore ja locale parity after merging main

Merging main brought new EN strings into agents/chat/onboarding/settings/
squads that the ja bundle (authored against an older snapshot) lacked, breaking
the locales parity test. Add the Japanese translations for the new keys
(workspace logo upload, agents runtime filter, chat session-history stop
dialog, onboarding social_github, squad archived status) and drop the two
renamed chat window keys (active_group / archived_group) that EN removed in
favour of history_group.

Fixes the failing @multica/views parity.test.ts on the FE CI for MUL-2893.

Co-authored-by: multica-agent <github@multica.ai>

---------

Co-authored-by: J <j@multica.ai>
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
Anderson Shindy Oki
2026-06-02 15:29:29 +09:00
committed by GitHub
parent baf8b215cb
commit 1aa742053b
105 changed files with 9667 additions and 64 deletions

View File

@@ -1,7 +1,7 @@
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { CoreProvider } from "@multica/core/platform";
import { pickLocale } from "@multica/core/i18n";
import { pickLocale, type SupportedLocale } from "@multica/core/i18n";
import { useAuthStore } from "@multica/core/auth";
import { useWelcomeStore } from "@multica/core/onboarding";
import { workspaceKeys, workspaceListOptions } from "@multica/core/workspace/queries";
@@ -21,6 +21,18 @@ import { useDaemonIPCBridge } from "./platform/daemon-ipc-bridge";
import { createDesktopLocaleAdapter } from "./platform/i18n-adapter";
import { RESOURCES } from "@multica/views/locales";
// BCP-47 region tags for the <html lang> attribute, mirroring
// apps/web/app/layout.tsx HTML_LANG. index.html ships a static lang="en";
// we sync it to the resolved locale at boot so screen readers announce the
// right language AND the Japanese-scoped CJK font override in globals.css
// (`html[lang|="ja"]`) can take effect.
const HTML_LANG: Record<SupportedLocale, string> = {
en: "en",
"zh-Hans": "zh-CN",
ko: "ko-KR",
ja: "ja-JP",
};
function AppContent() {
const user = useAuthStore((s) => s.user);
@@ -303,6 +315,15 @@ export default function App() {
[locale],
);
// Keep <html lang> in sync with the resolved locale (index.html hardcodes
// "en"). Drives the lang-scoped Japanese CJK font override and a11y.
// useLayoutEffect (not useEffect) so lang is committed before the first
// paint — otherwise Japanese users would see one frame of Kanji rendered
// with the Chinese-first fallback stack before the override kicks in.
useLayoutEffect(() => {
document.documentElement.lang = HTML_LANG[locale];
}, [locale]);
// React to OS-level language changes detected by main on focus regain.
// Only act when the user is following the system signal (no explicit
// Settings choice) — otherwise their preference wins. Cross-device sync

View File

@@ -4,6 +4,7 @@ import { describe, expect, it } from "vitest";
const chineseFonts = ["PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC"];
const koreanFonts = ["Apple SD Gothic Neo", "Malgun Gothic", "Noto Sans CJK KR"];
const japaneseFonts = ["Hiragino Sans", "Yu Gothic", "Noto Sans CJK JP"];
function expectChineseFontsBeforeKoreanFonts(source: string) {
const chineseIndexes = chineseFonts.map((font) => source.indexOf(font));
@@ -19,6 +20,23 @@ function expectChineseFontsBeforeKoreanFonts(source: string) {
}
}
// Japanese Kanji share the Han Unicode block with Chinese, so the global
// Chinese-first stack must stay Chinese-first (no zh regression) while a
// Japanese-first CJK stack is scoped to html[lang|="ja"]. App.tsx syncs
// document.documentElement.lang so the selector matches at runtime.
function expectJapaneseScopedOverride(source: string) {
expect(source).toContain('html[lang|="ja"]');
const japaneseIndexes = japaneseFonts.map((font) => source.indexOf(font));
expect(japaneseIndexes).not.toContain(-1);
const firstJapanese = Math.min(...japaneseIndexes);
const lastChinese = Math.max(
...chineseFonts.map((font) => source.lastIndexOf(font)),
);
expect(firstJapanese).toBeLessThan(lastChinese);
}
describe("CJK font fallback order", () => {
it("keeps desktop Chinese font fallbacks before Korean font fallbacks", () => {
const desktopCss = readFileSync(
@@ -28,4 +46,13 @@ describe("CJK font fallback order", () => {
expectChineseFontsBeforeKoreanFonts(desktopCss);
});
it("scopes the Japanese-first CJK stack to html[lang|='ja']", () => {
const desktopCss = readFileSync(
resolve(process.cwd(), "src/renderer/src/globals.css"),
"utf8",
);
expectJapaneseScopedOverride(desktopCss);
});
});

View File

@@ -31,6 +31,26 @@
monospace;
}
/* Japanese-scoped CJK override. Japanese Kanji share the Han Unicode block
with Chinese, and CSS font-fallback order is not changed by <html lang> —
so the global Chinese-first stack above would give Japanese users Chinese
glyph shapes for shared ideographs. We keep the global stack Chinese-first
(no regression for zh users) and promote Japanese fonts ahead of the
Chinese/Korean families only when the locale is Japanese. App.tsx syncs
document.documentElement.lang to the active locale so this selector
matches. Mirrors the lang-scoped override in apps/web/app/layout.tsx.
`[lang|="ja"]` is the BCP-47 language-range selector: it matches exactly
`ja` or `ja-<region>` (App.tsx sets `ja-JP`), never unrelated subtags
such as `jam`. */
html[lang|="ja"] {
--font-sans: "Inter Variable", "Inter", "Hiragino Sans",
"Hiragino Kaku Gothic ProN", "Yu Gothic", "YuGothic", "Meiryo",
"Noto Sans CJK JP", "Noto Sans JP", -apple-system,
BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei",
"Noto Sans CJK SC", "Apple SD Gothic Neo", "Malgun Gothic",
"Noto Sans CJK KR", sans-serif;
}
@source "../../../../../packages/ui/**/*.tsx";
@source "../../../../../packages/core/**/*.{ts,tsx}";
@source "../../../../../packages/views/**/*.{ts,tsx}";

View File

@@ -11,21 +11,13 @@ import { i18n, type Lang } from "@/lib/i18n";
import { uiTranslations, localeLabels } from "@/lib/translations";
import { DocsSettings } from "@/components/docs-settings";
// Inter (Latin UI face) is exposed under `--font-inter`. The full `--font-sans`
// stack — Inter + the per-locale CJK fallback chain, including the Japanese-first
// override scoped to `<html lang="ja">` — is composed in static CSS in
// ./global.css (CSP-safe, no inline <style>). Mirrors apps/web/app/layout.tsx.
const inter = Inter({
subsets: ["latin"],
variable: "--font-sans",
fallback: [
"-apple-system",
"BlinkMacSystemFont",
"Segoe UI",
"PingFang SC",
"Microsoft YaHei",
"Noto Sans CJK SC",
"Apple SD Gothic Neo",
"Malgun Gothic",
"Noto Sans CJK KR",
"sans-serif",
],
variable: "--font-inter",
});
const geistMono = Geist_Mono({

View File

@@ -17,6 +17,24 @@ function tokenizeCJK(raw: string): string[] {
return tokens;
}
// Japanese mixes Hiragana, Katakana and Kanji; the English regex strips them
// all, and the zh tokenizer only keeps Han (Kanji), dropping kana entirely.
// Tokenize each kana/Kanji codepoint on its own and keep Latin/digit runs
// whole — same character-level recall strategy as tokenizeCJK, extended to
// the Hiragana (\u3040-\u309f) and Katakana (\u30a0-\u30ff) blocks, plus the
// ideographic iteration mark \u3005 which sits just below the kana blocks and
// recurs in common words (e.g. the JP for "various", "daily", "individual").
function tokenizeJapanese(raw: string): string[] {
const tokens: string[] = [];
const regex = /[\u3005\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff]|[A-Za-z0-9]+/g;
const lower = raw.toLowerCase();
let match: RegExpExecArray | null;
while ((match = regex.exec(lower)) !== null) {
tokens.push(match[0]);
}
return tokens;
}
export const { GET } = createFromSource(source, {
localeMap: {
ko: {
@@ -26,6 +44,15 @@ export const { GET } = createFromSource(source, {
},
},
},
ja: {
components: {
tokenizer: {
language: "english",
normalizationCache: new Map(),
tokenize: tokenizeJapanese,
},
},
},
zh: {
components: {
tokenizer: {

View File

@@ -4,6 +4,7 @@ import { describe, expect, it } from "vitest";
const chineseFonts = ["PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC"];
const koreanFonts = ["Apple SD Gothic Neo", "Malgun Gothic", "Noto Sans CJK KR"];
const japaneseFonts = ["Hiragino Sans", "Yu Gothic", "Noto Sans CJK JP"];
function expectChineseFontsBeforeKoreanFonts(source: string) {
const chineseIndexes = chineseFonts.map((font) => source.indexOf(font));
@@ -19,13 +20,38 @@ function expectChineseFontsBeforeKoreanFonts(source: string) {
}
}
// Japanese Kanji share the Han Unicode block with Chinese, so the docs
// Japanese-first CJK stack must be scoped to html[lang|="ja"] (zh/en keep
// Chinese-first) and order Japanese fonts before the Chinese families.
function expectJapaneseScopedOverride(source: string) {
expect(source).toContain('html[lang|="ja"]');
const japaneseIndexes = japaneseFonts.map((font) => source.indexOf(font));
expect(japaneseIndexes).not.toContain(-1);
const firstJapanese = Math.min(...japaneseIndexes);
const lastChinese = Math.max(
...chineseFonts.map((font) => source.lastIndexOf(font)),
);
expect(firstJapanese).toBeLessThan(lastChinese);
}
describe("CJK font fallback order", () => {
it("keeps docs Chinese font fallbacks before Korean font fallbacks", () => {
const layoutSource = readFileSync(
resolve(process.cwd(), "app/[lang]/layout.tsx"),
const cssSource = readFileSync(
resolve(process.cwd(), "app/global.css"),
"utf8",
);
expectChineseFontsBeforeKoreanFonts(layoutSource);
expectChineseFontsBeforeKoreanFonts(cssSource);
});
it("scopes the Japanese-first CJK stack to html[lang|='ja']", () => {
const cssSource = readFileSync(
resolve(process.cwd(), "app/global.css"),
"utf8",
);
expectJapaneseScopedOverride(cssSource);
});
});

View File

@@ -6,6 +6,36 @@
@source "../../../packages/ui/**/*.{ts,tsx}";
/* ---------------------------------------------------------------------------
* Font stack. `--font-inter` is the next/font Inter family (+ synthetic
* size-adjusted fallback), set on <html> by inter.variable in app/[lang]/layout.tsx.
* `--font-sans` is composed here in static CSS so it can be overridden per
* `<html lang>` and stays CSP-safe (no inline <style>). Tailwind's `font-sans`
* utility resolves `var(--font-sans)`. Mirrors apps/web/app/globals.css.
*
* Default (en / zh / ko): Latin → Inter, CJK → Chinese then Korean. Chinese MUST
* stay before Korean so zh users don't get Korean Hanja glyph shapes.
* ------------------------------------------------------------------------- */
:root {
--font-sans: var(--font-inter), -apple-system, BlinkMacSystemFont, "Segoe UI",
"PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", "Apple SD Gothic Neo",
"Malgun Gothic", "Noto Sans CJK KR", sans-serif;
}
/* Japanese: Kanji share the Han Unicode block with Chinese and CSS fallback
order is not affected by `<html lang>`, so promote a Japanese-first CJK chain
only for Japanese docs (`<html lang="ja">`). `[lang|="ja"]` is the BCP-47
language-range selector — matches exactly `ja` or `ja-<region>`, never
unrelated subtags like `jam`. Inter still leads for Latin. */
html[lang|="ja"] {
--font-sans: var(--font-inter), "Hiragino Sans", "Hiragino Kaku Gothic ProN",
"Yu Gothic", "YuGothic", "Meiryo", "Noto Sans CJK JP", "Noto Sans JP",
-apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
"Microsoft YaHei", "Noto Sans CJK SC", "Apple SD Gothic Neo", "Malgun Gothic",
"Noto Sans CJK KR", sans-serif;
}
/* ---------------------------------------------------------------------------
* Multica Docs — editorial visual identity (v2)
*

View File

@@ -0,0 +1,127 @@
---
title: エージェントの作成と構成
description: エージェントを作成するために必要な最小限のフィールドと、すべての任意設定 — システム指示、環境変数、公開範囲、同時実行制限、アーカイブ。
---
import { Callout } from "fumadocs-ui/components/callout";
[エージェント](/agents)を作成するのに必要なのは 2 つだけです。**名前**と **[AI コーディングツール](/providers)の選択**です。それ以外はすべて任意です — システム指示、モデル、環境変数、CLI 引数、公開範囲、同時実行制限 — デフォルト値でも問題なく動作します。まず動かしてから後で調整しましょう。すべてのフィールドはいつでも変更できます。
## エージェントを作成する
前提条件: 使用中のマシンにサポートされている [AI コーディングツール](/providers)が少なくとも 1 つインストールされておりClaude Code、Codex など)、[デーモン](/daemon-runtimes)が実行中であること。まだそこまで準備できていない場合は、[Cloud クイックスタート](/cloud-quickstart)または[セルフホストクイックスタート](/self-host-quickstart)から始めてください。
準備が整ったら、ワークスペースの **Agents** ページに移動して **+ New** をクリックするか、CLI を使用します。
```bash
multica agent create
```
このフォームには必須フィールドが 2 つだけあります。**name**(ワークスペース内で一意であること)と **runtime**= AI コーディングツールの選択)です。それ以外のすべてのフィールドは、以下でセクションごとに扱います。
## AI コーディングツールを選ぶ
各ランタイムは特定の AI コーディングツールを基盤としています。Multica はそのうち 12 個をサポートします。最も一般的な選択肢は次のとおりです。
| ツール | 適している場合 |
|---|---|
| **Claude Code** | Anthropic の公式ツールで、最も完成度の高い機能セットを提供します。**最初の選択として最適です** |
| **Codex** | OpenAI 製で、主流の代替手段です |
| **Cursor** | Cursor エディターのエコシステムを使うユーザー |
| **Copilot** | GitHub アカウントの権限を活用するチーム |
| **Gemini** | Google エコシステムのユーザー |
残りの 7 個Antigravity、Hermes、Kimi、Kiro CLI、OpenCode、Pi、OpenClawと、各ツールの完全な機能比較表セッション再開、MCP、スキル注入パス、モデル選択は、[AI コーディングツール比較](/providers)で扱います。
## システム指示を書く
**システム指示**`instructions`)はすべてのタスクの先頭に追加され、エージェントがどんな役割を担い、どんなルールに従うべきかを伝えます。
```text
You're a frontend code-review agent. When an issue comes in, read the diff first. Focus only on:
- Styling issues (tailwind class names, box model)
- Accessibility (a11y)
Don't change code — leave suggestions in a comment.
```
空のままにすると(デフォルト)、エージェントは追加の制約なしに、基盤となる AI コーディングツールのネイティブな動作を使用します。
## モデルを選ぶ
ほとんどの AI コーディングツールはモデル選択をサポートしています(例えば Claude Code では Sonnet と Opus のどちらかを選べます)。空のままにするとツール自体のデフォルト値が使われ、明示的に 1 つを選ぶとそのモデルが実行されます。各ツールがサポートするモデルは、[AI コーディングツール比較](/providers)にまとめられています。
モデルの変更は**新しいタスクにのみ適用されます**。すでにディスパッチされたタスクは、ディスパッチ時点で固定されたモデルで実行を続けます。
## カスタム環境変数 (custom_env)
**カスタム環境変数**`custom_env`)を使うと、タスク実行時に追加の環境変数を注入できます。代表的な用途は API キーの設定やアップストリームエンドポイントの切り替えです。
```
ANTHROPIC_API_KEY = sk-...
ANTHROPIC_BASE_URL = https://my-proxy.example.com
```
システムにとって重要な変数は上書きできません。`PATH`、`HOME`、`USER`、`SHELL`、`TERM`、`CODEX_HOME`、そして `MULTICA_*` で始まるすべてのキーは、デーモンが静かに無視します(警告ログは残しますが、エラーは発生しません)。
<Callout type="warning">
**`custom_env` の値は Multica サーバーのデータベースに平文で保存されます。** エージェントの list/get レスポンスには環境変数の値がまったく含まれなくなり、不透明な個数だけが返されます。実際の値を読み取るには、ワークスペースの owner または admin が、専用で監査される `GET /api/agents/{id}/env` エンドポイントCLI: `multica agent env get <id>`)を呼び出す必要があります。タスクを実行中のエージェントは、ホストの owner 資格情報を使って他のエージェントの環境変数を明らかにすることはできません。このエンドポイントはエージェントアクターのセッションを拒否します。
**価値の高いシークレットは `custom_env` に入れないでください**本番データベースのパスワード、root レベルのトークンなど)。エージェントには**権限範囲が限定された専用の資格情報**(読み取り専用 API キー、単一スコープの PATを使用し、定期的にローテーションしてください。データベースのバックアップと DB 監査は、依然として意味のある露出面として残ります。
</Callout>
## カスタム CLI 引数 (custom_args)
**カスタム CLI 引数**`custom_args`は、AI コーディングツールのコマンドラインに 1 つずつ順に付け足される文字列配列です。
```json
["--max-turns", "100", "--append-system-prompt", "always respond in Chinese"]
```
最終的なコマンドは次のように生成されます。
```bash
claude --model <model> --max-turns 100 --append-system-prompt "always respond in Chinese" [...]
```
引数はシェルを介さずそのまま渡されるため(注入リスクなし)、特定のフラグが認識されるかどうかは AI コーディングツール自体に依存します。この部分はツールによって大きな差があります。
<Callout type="tip">
`custom_env` と `custom_args` には厳格な上限はありませんが、実際には**それぞれ 10 個以内に抑えてください**。多すぎるとコマンドラインが長くなり、起動が遅くなり、メンテナンスも難しくなります。
</Callout>
## 公開範囲
- **ワークスペース**`workspace` — ワークスペースのすべてのメンバーが割り当てできます
- **非公開**`private` — ワークスペースの owner、admin、またはエージェントの作成者だけが割り当てできます
新しいエージェントはデフォルトで `private` です。
**非公開だからといって隠されるわけではありません** — すべてのメンバーが一覧で非公開エージェントの名前と説明を見ることができ、ただし機微な構成は読み取れません(環境変数の値はエージェントの list/get レスポンスに決して現れず、MCP 構成は owner 以外のユーザーにはマスキングされます)。詳しい意味は[エージェント → 誰がエージェントを割り当てられるか](/agents#who-can-assign-an-agent)を参照してください。
## 同時実行制限
**同時実行制限**`max_concurrent_tasks`)は、このエージェントが一度に並列で実行できるタスク数を制御します。デフォルト値は **6** です。上限に達した新しいタスクは拒否されず、キューで待機します。
これは 2 段階の制限のうち「エージェント層」にすぎません。デーモン自体がより広い上限(デフォルト値 20を適用し、2 つのうちより厳しい方が優先されます。詳しくは[デーモンとランタイム → 並列で何個のタスクを実行できるか](/daemon-runtimes#how-many-tasks-can-run-in-parallel)にあります。
この値を変更しても**すでに実行中のタスクはキャンセルされず**、次に処理されるタスクからのみ適用されます。
## ドメインの専門性をつなぐ: スキル
作成したエージェントには**スキル**をアタッチできます — タスク実行時に AI コーディングツールへ自動的に届けられる**ナレッジパック**`SKILL.md` + 補助ファイルです。新しいスキルを作成したり、GitHub または ClawHub からインポートしたり、マシン上の既存のスキルディレクトリからスキャンしたりできます。[スキル](/skills)を参照してください。
## アーカイブと復元
もう使わないエージェントは**アーカイブ**できます — 日常的な画面からは消えますが、履歴データ(実行したタスク、投稿したコメント)はすべてそのまま保持されます。いつでも**復元**して再び作業に投入できます。
<Callout type="warning">
**アーカイブは、そのエージェントに属する未完了のすべてのタスクを即座にキャンセルします** — 実行中、ディスパッチ済み、キュー待ちのタスクがすべて `cancelled` としてマークされ、続行されません。進行中の重要なタスクがある場合は、アーカイブする前に最後まで完了させてください。
</Callout>
アーカイブ済みのエージェントには新しいタスクを割り当てられません。
## 次のステップ
- [スキル](/skills) — エージェントにナレッジパックをアタッチする
- [AI コーディングツール比較](/providers) — 12 個のツール全体の機能比較表
- [エージェントへのイシューの割り当て](/assigning-issues) — 新しく作ったエージェントを作業に投入する

View File

@@ -0,0 +1,49 @@
---
title: エージェント
description: "エージェントは Multica ワークスペースの一級メンバーです — イシューを割り当てられ、コメントを投稿し、@ でメンションされることができます。人間との核心的な違いは、エージェントは自分から作業を始め、通知を受け取らない点です。"
---
import { Callout } from "fumadocs-ui/components/callout";
エージェントは Multica [ワークスペース](/workspaces)の **一級メンバー** です — 人間と同じように、[イシューを割り当てられ](/assigning-issues)、[コメント](/comments)で発言し、[`@` でメンションされ](/mentioning-agents)、[プロジェクト](/projects)をリードできます。核心的な違いはこれです。すべてのエージェントの背後には、あなたのマシンで動作する [AI コーディングツール](/providers)があります。エージェントにタスクを割り当てると、特に促さなくても **数秒以内に自分から作業を始めます** — 急かす必要も、オフラインになることもなく、24時間いつでも利用できます。
## エージェントができること
エージェントは人間と同じ「メンバー」の表面を使っており、UI ではほとんど区別されません。
- **[イシューを割り当てられる](/assigning-issues)** — 担当者に設定された瞬間、自動的に作業を始めます
- **[`@` でメンションされる](/mentioning-agents)** — コメントに `@agent-name` と書くと、目覚めてそのコメントを読みます
- **[コメント](/comments)を投稿する** — イシューの下で進捗を報告し、人々に返信します
- **[プロジェクト](/projects)をリードする** — 人間と同じように、プロジェクトリードに設定できます
- **自分で[イシュー](/issues)を開く** — タスクを実行している間に関連する問題を見つけると、直接新しいイシューを作成できます
協業ビューから見ると、エージェントはただのワークスペースのメンバーです — 人間と同じメンバー一覧に名前が並び、通常はその前に小さなロボットアイコンが付きます。
## 人間との違い
いくつかの重要な違いは、実際にエージェントを使い始めて初めて見えてきます。
- **自分から始めます** — イシューを割り当てたり `@` でメンションしたりすると、Multica が即座にそのタスクをエージェントのランタイムにディスパッチします。人間のようにメッセージを見て応答するまで待つことはありません。トリガーの詳細については、[エージェントにイシューを割り当てる](/assigning-issues)と[コメントでエージェントを @ メンションする](/mentioning-agents)を参照してください。
- **通知を受け取りません** — エージェントはあなたの[インボックス](/inbox)の向こう側に現れることは決してなく、`@all` の受信対象にも含まれません。エージェントは「メッセージを読む受信者」ではなく「タスクを実行するためにトリガーされる作業の単位」です。
- **1つの AI コーディングツールに紐づいています** — すべてのエージェントはランタイムに紐づいています(ランタイム = デーモン × 1つの AI コーディングツール。[デーモンとランタイム](/daemon-runtimes)を参照)。ツールがオフラインだとエージェントは作業できず、新しいタスクはランタイムが戻るまで待機します。
- **アーカイブできます** — もう使わないエージェントをアーカイブすると日常的なビューから消えます。いつでも好きなときに復元できます。アーカイブすると、現在実行中のタスクはすべてキャンセルされます。
## 誰がエージェントを割り当てられるか
エージェントを作成するとき、誰がそのエージェントをイシューに割り当てたりプロジェクトリードに設定したりできるかを制御する **可視性visibility** を選択します。
- **Workspace** — ワークスペースの任意のメンバーが割り当てられます
- **Private** — ワークスペースの owner、admin、またはエージェントの作成者だけが割り当てられます
新しいエージェントはデフォルトで **private** です。ワークスペース全体で利用できるようにするには、作成時に可視性を `workspace` に設定するか、後でエージェントの設定で変更してください。役割と権限の完全なマトリクスについては、[メンバーと役割](/members-roles)を参照してください。
<Callout type="info">
**private は「誰が割り当てられるかを制限する」という意味であって、「他の全員から隠す」という意味ではありません。** ワークスペースのすべてのメンバーは、エージェント一覧で private エージェントの名前と説明を見ることができます — 見えないのは設定の詳細だけですカスタム環境変数、MCP 設定、その他の機密フィールドはマスクされます。「1人だけに見える」ようにしたい場合、現時点では実現できません。
</Callout>
## 次のステップ
- [エージェントの作成と構成](/agents-create) — エージェントを作る方法
- [スキル](/skills) — エージェントに知識パックを添付する
- [スクワッド](/squads) — 適切なエージェントが適切なイシューを担当するよう、リーダーの下にエージェントをグループ化する
- [デーモンとランタイム](/daemon-runtimes) — エージェントが実際に動作するために必要なもの

View File

@@ -0,0 +1,83 @@
---
title: エージェントにイシューを割り当てる
description: イシューをエージェントに渡すと、作業が終わるまで公式の担当者として引き継ぎます — 完全なコンテキストを持ち、イシューのステータスやフィールドを変更できます。
---
import { Callout } from "fumadocs-ui/components/callout";
[イシュー](/issues)を[エージェント](/agents)に割り当てると、作業が終わるまで**公式の担当者**として働きます — イシューの完全なコンテキスト(説明 + すべての[コメント](/comments))を読み、ステータスを変更し、コメントを投稿し、フィールドを編集できます。これは Multica の 4 つのトリガー経路の中で**最も一般的で、最も重い**方式です。同じフローは[スクワッド](/squads)を担当者として受け付けることもできます — その場合、Multica は代わりにスクワッドの**リーダーエージェント**をトリガーします。
| 経路 | 使う場面 | イシューの変更 | コンテキスト | 優先度 | 自動リトライ |
|---|---|---|---|---|---|
| **割り当て** | エージェントに所有権を渡す | 担当者を変更 | イシュー + すべてのコメント | イシューから継承 | ✓ |
| [**@メンション**](/mentioning-agents) | ちょっと見てもらうために呼び込む | 変更なし | イシュー + トリガーコメント | イシューから継承 | ✓ |
| [**チャット**](/chat) | イシューと無関係な 1 対 1 の会話 | イシューは関与しない | 現在の会話履歴 | 固定で medium | ✓ |
| [**オートパイロット**](/autopilots) | スケジュールまたは手動の自動化 | モードによる | モードによる | オートパイロットが設定 | ✗ |
「自動リトライ」とは、インフラ障害(ランタイムのオフライン、タイムアウト)後のリトライを指します。エージェント側のビジネスエラー(たとえばモデルがエラーを報告する場合)はリトライされません。詳しくは [**タスク**](/tasks)を参照してください。
## UI から割り当てる
イシュー詳細ページで、**担当者**ピッカーをクリックしてください。ワークスペースのすべてのメンバー、アーカイブされていないすべてのエージェント、アーカイブされていないすべての[スクワッド](/squads)が一覧表示されます。エージェント(またはスクワッド)を選ぶと、イシューはすぐに割り当てられます。
いくつかのルールがあります。
- **ワークスペースエージェント**はどのメンバーでも割り当てられます。**プライベートエージェント**はその owner またはワークスペースの admin のみが割り当てられます。
- **オンラインのランタイムを持つ**エージェントにのみ割り当てられます — 誰も実行していないエージェントはピッカーで利用不可と表示されます。
- イシューのステータスが **Backlog** のとき、割り当てても**エージェントはトリガーされません** — Backlog は一時保管所であり、イシューを Todo または In Progress に移して初めてエージェントがキューに入ります。
## CLI から割り当てる
コマンドラインでの同等の操作です。
```bash
multica issue assign MUL-42 --to alice
multica issue assign MUL-42 --to-id 5fb87ac7-23b5-4a7a-81fa-ed295a54545d
```
`--to` はメンバーのユーザー名またはエージェント名(あいまい一致)を受け付けます。名前が重複するとき — たとえばエージェント `J` の隣に `Cursor - J` がある場合 — は、代わりに `--to-id <uuid>` を渡してください。このとき `multica workspace member list --output json` の `user_id`(メンバー)または `multica agent list --output json` の `id`エージェントを使います。UUID 一致は厳密かつ曖昧さがないため、スクリプトや CLI を駆動するエージェントに適しています。`--to` と `--to-id` は同時に使えません。
割り当て解除:
```bash
multica issue assign MUL-42 --unassign
```
## 割り当て後に起こること
Backlog ではないイシューがエージェントに割り当てられると、Multica はすぐにバックグラウンドで次のことを行います。
1. イシューから継承した優先度で `queued` 状態の `task` をキューに入れ、エージェントが存在するランタイムへルーティングします。
2. エージェントのデーモンが次のポーリング時に `task` を取得し、`dispatched` に遷移させます。
3. エージェントが作業を開始すると `task` が `running` に移ります。完了すると `completed` または `failed` になります。
4. 実行中、エージェントはイシューのステータスを変更し、コメントを投稿し、フィールドを編集できます — これらの操作はエージェントの ID で表示されます。
**エージェントがオフラインの場合**、`task` はキューで待機します — **5 分後に `runtime_offline` の理由でタイムアウトして失敗します**。リトライ可能なソース(割り当て、@メンション、チャットについては、Multica が自動的に再度キューに入れます。完全なリトライルールは [**タスク**](/tasks)を参照してください。
割り当てると、エージェントはイシューに自動的に購読されます — ただし Multica では**エージェントはインボックス通知を受け取りません**(メンバーのみ受け取ります)。この購読は内部的な記録管理にすぎず、ユーザーに見える副作用はありません。
## 再割り当てまたは割り当て解除
担当者をエージェント A からエージェント B に変更すると、
1. **A が進行中だったものはすべてキャンセルされます** — `queued`、`dispatched`、`running` 状態のすべての `task` が `cancelled` と表示されます。
2. **B にはすぐに新しい `task` がキューに入ります**(イシューが Backlog でなく、B にオンラインのランタイムがある場合)。
<Callout type="warning">
**再割り当てはこのイシューのすべてのアクティブな `task` をキャンセルします — 以前の担当者のものだけではありません。** 別のエージェントが @メンションによってこのイシューで作業中の場合、その `task` も一緒にキャンセルされます。現在のところ、単一のエージェントの `task` だけを個別にキャンセルする UI 操作はありません。
</Callout>
割り当て解除(`--unassign` またはピッカーで「none」を選択は、すべてのアクティブな `task` 項目を `cancelled` と表示し、**新しい項目をキューに入れません**。既存の購読は自動的にクリアされません — 以前の担当者は購読リストに残ります(ただし依然としてインボックス通知は受け取りません)。
## イシューごとエージェントごとにアクティブな `task` が 1 つだけの理由
**単一のエージェントは、同じイシューで任意の時点に最大 1 つの `queued` または `dispatched` の `task` しか持てません。** データベースレベルの一意インデックスとクレームロジックがこれを強制します — 重複したキュー登録と、同時実行が互いを上書きすることを防ぎます。
しかし**異なるエージェントは同じイシューで並列に作業できます** — たとえばエージェント A が担当者で、エージェント B が @メンションされた場合、2 つの `task` 項目がそれぞれ自分のランタイムで実行されながら共存できます。完全な直列・並列ルールは [**タスク**](/tasks)を参照してください。
## 次へ
- [**コメントでエージェントを @メンションする**](/mentioning-agents) — 担当者とステータスを変えない、より軽いトリガー
- [**スクワッド**](/squads) — エージェントのグループに割り当て、リーダーに誰が引き受けるかを決めさせる
- [**チャット**](/chat) — イシューと無関係な 1 対 1 の会話
- [**オートパイロット**](/autopilots) — エージェントがスケジュールに沿って自動的に作業を開始するようにする

View File

@@ -0,0 +1,166 @@
---
title: ログインとサインアップの構成
description: メール + 認証コードログイン、Google OAuth、サインアップ許可リスト、ローカルテストコードを構成します。
---
import { Callout } from "fumadocs-ui/components/callout";
import { Mermaid } from "@/components/mermaid";
Multica は 2 つのログイン方式をサポートしています。**メール + 認証コード**(デフォルト)と **Google OAuth**(オプション)です。ログインに成功すると、サーバーは 30 日間有効な JWT クッキーを発行します。このページでは、各方式の構成方法、誰がサインアップできるかを制限する方法、そしてセルフホストのデプロイで最も陥りやすい落とし穴を 1 つ取り上げます。
以下で参照する環境変数の一覧は[環境変数](/environment-variables)を参照してください。トークンの使い方とライフサイクルの詳細は[認証とトークン](/auth-tokens)を参照してください。
## メール + 認証コードログインの仕組み
ユーザーがログインページでメールを入力します → サーバーが 6 桁のコードを送信します → ユーザーがコードを入力します → サーバーがコードを検証します → JWT クッキーが発行されます。標準的なフローです。2 つの送信バックエンドがサポートされているので、デプロイ環境に合うほうを選んでください。
### オプション A: Resendクラウド / 公開インターネットのデプロイに推奨)
1. [Resend](https://resend.com/) アカウントを作成し、ドメインを認証します
2. API キーを作成します
3. 環境変数を設定します:
```bash
RESEND_API_KEY=re_xxxxxxxxxxxxxxxx
RESEND_FROM_EMAIL=noreply@yourdomain.com # must be a domain verified in Resend
```
4. サーバーを再起動します
### オプション B: SMTP relayセルフホスト / オンプレミスのデプロイ用)
デプロイ環境から `api.resend.com` に到達できない場合や、すでに内部メール relayMicrosoft Exchange、Postfix、オンプレミスの SendGrid など)がある場合に使用してください。両方が設定されている場合は `SMTP_HOST` が `RESEND_API_KEY` より優先されます。`SMTP_HOST` が空でなければ、`RESEND_API_KEY` も併せて構成されていても、サーバーは常に SMTP を経由するため、認証メールと招待メールが内部ネットワークの外に出ることは決してありません。
SMTP 経路は、ほとんどのオンプレミスメールサーバー(特に Microsoft Exchange の receive connectorが公開する 3 つの relay モードをサポートします。
| モード | ポート | 認証 | TLS |
|---|---|---|---|
| 匿名内部 relay | `25` | なし — IP / サブネットで送信を信頼 | 伝送経路上はなし(内部セグメント専用) |
| 認証付き送信submission | `587` | `SMTP_USERNAME` + `SMTP_PASSWORD` | STARTTLS、自動アップグレード |
| 暗黙的 TLSSMTPS | `465` | — | **まだサポートされていません** — ポート 25 または 587 を使用してください |
**ポート 25 の匿名 Exchange relay** — 認証情報なしで信頼されたサブネットからのメールを受け入れる、典型的な「internal SMTP relay」/ Exchange 匿名 receive connector:
```bash
SMTP_HOST=exchange.internal.example.com
SMTP_PORT=25
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_TLS_INSECURE=false
RESEND_FROM_EMAIL=noreply@yourdomain.com # reused as the From: header
```
**ポート 587 の認証付き送信** — サービスアカウントを必要とする relay 用。サーバーが STARTTLS のサポートを通知すると自動的にアップグレードされます:
```bash
SMTP_HOST=smtp.internal.example.com
SMTP_PORT=587
SMTP_USERNAME=multica
SMTP_PASSWORD=...
SMTP_TLS_INSECURE=false # set true only for self-signed / private CA
RESEND_FROM_EMAIL=noreply@yourdomain.com
```
起動時に、サーバーは選択したプロバイダーを出力します。例えば `EmailService: SMTP relay exchange.internal.example.com:25 from=noreply@example.com`(または `Resend API` / `DEV mode`)のように表示されます。パスワードがログに記録されることは決してありません。再起動後に SMTP の行が見えない場合は `SMTP_HOST` がプロセスに届いていないので、コンテナ環境(`docker compose -f docker-compose.selfhost.yml exec backend env | grep SMTP`)を確認してください。
**どちらも設定しない場合**: サーバーはエラーを出しませんが、**送信されるはずだったすべてのメールがサーバーの stdout にのみ書き出されます**。ローカル開発には便利ですが(ログからコードをコピーできます)、プロダクションではブラックホールになります。
## 固定ローカルテストコード
<Callout type="warning">
**公開アクセス可能なインスタンスでは固定の認証コードを有効にしないでください。**
非プロダクションのインスタンスがデフォルトで `888888` を受け入れていた従来の動作は削除されました。明示的に構成しない限り、`888888` の入力は他の誤ったコードと同じように扱われます。
メールバックエンドをまったく構成していないResend も SMTP もない)ローカル開発では、サーバーログに出力される生成されたコードを使用してください。決定論的なローカル / プライベートの自動化が必要な場合は、`MULTICA_DEV_VERIFICATION_CODE` を `888888` のような 6 桁の値に設定し、`APP_ENV` を非プロダクションに保ってください:
```bash
APP_ENV=development
MULTICA_DEV_VERIFICATION_CODE=888888
```
このショートカットは `APP_ENV=production` のときは無視されます。
</Callout>
プロダクションのデプロイでは `MULTICA_DEV_VERIFICATION_CODE` を空のままにし、`APP_ENV=production` に設定してください。`make selfhost` / `docker-compose.selfhost.yml` でデプロイする場合、`APP_ENV` はデフォルトで `production` です。
## Google OAuth の構成
オプションです。構成しないとメール + 認証コードのみが利用可能で、構成するとログインページに「Sign in with Google」ボタンが追加されます。
1. [Google Cloud Console](https://console.cloud.google.com/) で OAuth 2.0 クライアントを作成します
2. **Authorized redirect URIs** を Multica フロントエンドのアドレスに `/auth/callback` を加えた値に設定します。例:
```text
https://multica.yourdomain.com/auth/callback
```
3. クライアント ID とクライアント secret を取得したら、3 つの環境変数を設定します:
```bash
GOOGLE_CLIENT_ID=xxxxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxxxx
GOOGLE_REDIRECT_URI=https://multica.yourdomain.com/auth/callback
```
4. サーバーを再起動します。
**ランタイムで反映されます**: フロントエンドは `/api/config` を通じてランタイムにこれらの設定を読み込みます — 変更後にサーバーを再起動すると、フロントエンドはリビルドや再デプロイなしで新しい値を取得します。
<Callout type="warning">
**リダイレクト URI は Google Console と `GOOGLE_REDIRECT_URI` の両方で完全に一致している必要があります** — プロトコル(`http` と `https`)、末尾のスラッシュ、ポートを含みます。少しでも一致しないと Google は OAuth フロー全体を拒否し、ユーザーに表示されるエラーは `redirect_uri_mismatch` です。
</Callout>
## 誰がサインアップできるかを制限する
3 つの環境変数が優先順位に従って組み合わされます。
<Mermaid chart={`
graph TD
Start[New user first sign-in] --> A{Email in<br/>ALLOWED_EMAILS?}
A -- Yes --> Allow[Allow signup]
A -- No --> B{Domain in<br/>ALLOWED_EMAIL_DOMAINS?}
B -- Yes --> Allow
B -- No --> C{Any allowlist<br/>non-empty?}
C -- Yes --> Block[Reject]
C -- No --> D{ALLOW_SIGNUP<br/>= true?}
D -- Yes --> Allow
D -- No --> Block
`} />
**既存のユーザーはいつでも再ログインできます** — サインアップ許可リストは**初回サインアップ**にのみ適用され、戻ってくるユーザーは妨げられません。
- **`ALLOWED_EMAILS`**(最高優先度) — 明示的なメール許可リスト、カンマ区切り。**空でない場合、リストにあるメールのみがサインアップできます。**
- **`ALLOWED_EMAIL_DOMAINS`** — ドメイン許可リスト、カンマ区切り(例: `company.io,partner.com`)。
- **`ALLOW_SIGNUP`** — マスタースイッチ、デフォルト `true`。`false` に設定するとサインアップが完全に無効になります。
<Callout type="warning">
**3 つの層は OR ではなく AND のセマンティクスです。** よくある誤った直感は、`ALLOWED_EMAIL_DOMAINS=company.io` + `ALLOW_SIGNUP=true` が「company.io に加えて他の全員を許可する」という意味だと考えることです。そうでは**ありません**。いずれかの層に空でない値があると、**それに一致しないメールはただちに拒否され**、`ALLOW_SIGNUP=true` はそれを無効にできません。
実際に「全員を許可」するには、3 つの変数をすべて空のままにしてください(または `ALLOW_SIGNUP=true` を維持してください)。
</Callout>
**典型的な構成**:
| 目的 | 構成 |
|---|---|
| 内部専用、`company.io` の従業員のみ | `ALLOWED_EMAIL_DOMAINS=company.io` |
| 内部 + 少数の外部コラボレーター | `ALLOWED_EMAIL_DOMAINS=company.io` + コラボレーターのアドレスを `ALLOWED_EMAILS` に追加 |
| セルフサービスのサインアップを完全に無効化、招待のみ | `ALLOW_SIGNUP=false` |
| 開放型サインアップ(プロダクションには非推奨) | 3 つすべて空 |
## サインアップを無効にしても人を招待できますか?
**すでに Multica アカウントを持っている人のみ可能です。** 招待の受諾はサインアップ許可リストをチェックしません — 招待された人がすでにサインアップ済み(例えば別のワークスペースで)であれば、招待リンクをクリックしてログインすれば受諾できます。
**しかし一度もサインアップしていない人は招待で救うことはできません。** 受諾する前にまずログインする必要があり、ログインの最初のステップ(認証コードの要求)はサインアップ許可リストのチェックを通過します。`ALLOW_SIGNUP=false` であるか、そのメールが `ALLOWED_EMAILS` / `ALLOWED_EMAIL_DOMAINS` にない場合、**サインアップを完了できず**、したがって招待を受諾することもできません。
まだサインアップしていない外部コラボレーターを招待するには: そのメールを `ALLOWED_EMAILS` に一時的に追加し、その人がサインアップして招待を受諾するのを待ってから、エントリを削除してください。
招待の作成と使用方法については[メンバーとロール](/members-roles)を参照してください。
## 次に
- [環境変数](/environment-variables) — このページで使用するすべての変数の完全な定義
- [認証とトークン](/auth-tokens) — JWT / PAT / デーモントークンの分類と使い方
- [トラブルシューティング](/troubleshooting) — 認証コードが届かない、OAuth `redirect_uri_mismatch`、サインアップ拒否

View File

@@ -0,0 +1,80 @@
---
title: 認証とトークン
description: Multica には 3 種類のトークンがあります — ブラウザ、CLI、デーモンにそれぞれ 1 つずつ。どの場面でどれを使うかを解説します。
---
import { Callout } from "fumadocs-ui/components/callout";
Multica には 3 種類のトークンがあり、それぞれが 1 つのコンテキストに対応します。ブラウザの Web UI、コマンドラインとスクリプト、そしてデーモンです。3 つとも同じあなたを表しますが、スコープと有効期間が異なります。
## 3 つのトークン
| トークン | 形式 | 使われる場所 | 有効期間 |
|---|---|---|---|
| **JWT クッキー** | `multica_auth` クッキー (HttpOnly) | Web ブラウザ | 30 日 |
| **個人アクセストークン (PAT)** | `mul_` プレフィックス | CLI、スクリプト、直接の API 呼び出し | デフォルトでは期限なし。API で作成する際に `expires_in_days` を渡せます |
| **デーモントークン** | `mdt_` プレフィックス | デーモンとサーバー間の通信 | デーモン自体が管理 |
日常的な利用では、最初の 2 つだけを直接扱うことになります。**[デーモン](/daemon-runtimes)トークン**は `multica daemon login` が自動的に作成・更新するため、気にする必要はありません。
## 各トークンがアクセスできるもの
| API ルート | JWT クッキー | PAT | デーモントークン |
|---|---|---|---|
| `/api/user/*` (ユーザーレベルの操作) | ✓ | ✓ | ✗ |
| `/api/workspaces/:id/*` (ワークスペースレベル) | ✓ | ✓ | ✗ |
| `/api/daemon/*` (デーモン専用) | ✗ | ✓ | ✓ |
| WebSocket `/ws` (リアルタイムプッシュ) | ✓ (クッキー) | ✓ (最初のメッセージで認証) | ✗ |
**PAT はほぼすべてにアクセスできます** — これは「完全なあなた」を表します。デーモントークンはデーモンに必要なこと、つまりタスクを取得して結果を報告することしかできません。
**どちらも `/api/daemon/*` にアクセスできますが、スコープが異なります。** PAT は**ユーザー全体**を表し、一度認証されると、あなたが所属するすべてのワークスペースを見ることができます。デーモントークンは作成時点で単一のワークスペースに固定され、そのワークスペースのリソースにしかアクセスできません。本番環境では、デーモンはデーモントークンで実行してください。手軽さのために PAT を使う近道を選ばないでください。そうしないと、デーモンに必要な以上にはるかに大きな権限を与えてしまいます。
## ログイン
### メール + 認証コード
1. メールアドレスを入力すると、サーバーが 6 桁のコードを送信します。
2. コードを入力すると、サーバーが JWT クッキーを発行ブラウザするか、PAT に交換CLIします。
<Callout type="warning">
**セルフホストの運用者は注意してください**: 公開デプロイでは `MULTICA_DEV_VERIFICATION_CODE` を空のままにしておいてください。固定のローカルテストコードを有効にすると、`APP_ENV` が production 以外の間は、コードをリクエストできる人なら誰でもその値でサインインできてしまいます。[セルフホスト認証の構成](/auth-setup)を参照してください。
</Callout>
### Google OAuth
**Sign in with Google** をクリックして、標準の OAuth コールバックを通過してください。セルフホストには `GOOGLE_CLIENT_ID`、`GOOGLE_CLIENT_SECRET`、そしてリダイレクト URI を構成する必要があります — [セルフホスト認証の構成](/auth-setup)を参照してください。
## PAT の作成、表示、失効
PAT の**作成**は 2 つの方法で行えます。
- **Web UI**: 設定 → 個人アクセストークン → 新しいトークン
- **CLI**: `multica login` は、まだローカル PAT がない場合に自動的に 1 つ作成します
<Callout type="warning">
**完全な PAT は作成時に正確に 1 回だけ表示されます。** 更新したりダイアログを閉じたりした後は、二度と見ることができません。
Multica はデータベースに PAT のハッシュだけを保存します — サーバーでさえ元の値を取得できません。すぐにコピーして保存してください。紛失した場合の唯一の手段は、失効させて新しく作り直すことです。
</Callout>
既存の PAT の**表示**(名前、作成時刻、最終使用時刻 — 完全なトークンは**含みません**)は、設定 → 個人アクセストークンにあります。
PAT の**失効**: 一覧で Revoke をクリックしてください。失効はすぐに反映されます — その PAT で送られる次のリクエストは 401 で拒否されます。
## ログアウトはローカルトークンを削除するだけ
`multica auth logout` を実行するか、Web UI でログアウトをクリックすると、
- **ローカルトークンが消去されます** — CLI は `~/.multica/config.json` から PAT を削除し、ブラウザはクッキーを削除します。
- **PAT はサーバー上では依然として有効です** — ログアウトする前に誰かがあなたの PAT を入手していた場合(たとえば別のマシンにコピーしていた場合)、その人は**依然としてそれを使用できます**。
<Callout type="warning">
**PAT が漏洩したと疑われる場合は、単にログアウトするだけにしないでください。** 設定 → 個人アクセストークンに進み、そのトークンを**失効**させてください。失効だけが、漏洩したトークンを即座に無効化します。
</Callout>
## 次のステップ
- [CLI コマンドリファレンス](/cli) — すべての CLI コマンドの認証は自動です
- [セルフホスト認証の構成](/auth-setup) — セルフホスト時にメール、OAuth、サインアップ許可リストを構成する方法
- [デーモンとランタイム](/daemon-runtimes) — デーモントークンがどこから来るのか

View File

@@ -0,0 +1,239 @@
---
title: オートパイロット
description: エージェントが cron スケジュールやインバウンド webhook で作業を開始したり、UI や CLI で一度だけ手動でトリガーしたりできるようにします。
---
import { Callout } from "fumadocs-ui/components/callout";
オートパイロットは、[エージェント](/agents)が**スケジュールに従って自動的に作業を開始**できるようにします — cron 式とタイムゾーンを設定すると、あなたが何もトリガーしなくても Multica が自ら [`task`](/tasks) をディスパッチします。定期点検、繰り返しのレポート、夜間のクリーンアップ作業など、「常設指示standing order」の形の作業に適しています。残りの 3 つのトリガー経路([割り当て](/assigning-issues)、[@-メンション](/mentioning-agents)、[チャット](/chat) — いずれもあなた自身が起点となる方式)と比べたとき、オートパイロットの核心的な違いは**時間駆動**であることです。
## オートパイロットを構成する
ワークスペースの**オートパイロット**ページで新しいオートパイロットを作成します。次の項目を設定します。
- **名前Name** — 表示名
- **エージェントAgent** — 実行をディスパッチする対象
- **優先度Priority** — 生成される `task` に継承されます(イシューの優先度と同じ意味)
- **説明 / プロンプトDescription / prompt** — 実行のたびにエージェントが受け取る作業説明
- **実行モードExecution mode** — 以下を参照
- **トリガーTriggers** — `schedule`cron + タイムゾーン)または `webhook` のうち少なくとも 1 つ
## 実行モードを選ぶ
オートパイロットには 2 つの実行モードがあります。**「イシュー作成」モードから始めてください。**
- **イシュー作成モードCreate issue mode**`create_issue` — デフォルトであり、**推奨**されます。各トリガーはまずワークスペースにイシューを作成し(タイトルには現在、単一のプレースホルダー `{{date}}` のみがサポートされ、これは `YYYY-MM-DD` 形式の UTC 日付に補間されます。それ以外の `{{...}}` トークンは作成時点で拒否されるため、タイプミスがイシュータイトルにリテラル文字列として静かに紛れ込むことを防ぎます)、通常の割り当てフローを通じてそのイシューをエージェントに割り当てます。すべての作業は、手動で割り当てたイシューと同じ履歴、コメント、ステータスを持った状態でイシューボードに上がります。
- **実行専用モードRun-only mode**`run_only` — イシュー作成をスキップし、`task` を直接キューに入れます。この実行はボードには表示されません — オートパイロットの実行履歴でのみ確認できます。
## スケジュールに従って実行する
すべてのオートパイロットには少なくとも 1 つの `schedule` トリガーが必要です。Cron は**標準の 5 フィールド形式**(分 時 日 月 曜日)を使用し、最小単位は **1 分**です(秒単位はありません)。タイムゾーンは IANA 形式(例: `Asia/Shanghai`で、cron 式がどのタイムゾーンで解釈されるかを決定します。
いくつかの例:
- `0 9 * * 1-5`, `Asia/Shanghai` — 平日の北京時間午前 9 時
- `*/30 * * * *`, `UTC` — 30 分ごと
- `0 3 * * *`, `UTC` — 毎日 UTC 午前 3 時
Multica サーバーは**30 秒**ごとに期限が来たトリガーをスキャンします — **実際の発火時刻は最大 30 秒まで遅れる可能性があり**、秒単位で正確ではありません。発火時刻のあたりでサーバーが再起動された場合、起動時に逃したトリガーを追いつきます(何も失われませんが、すぐに発火します)。
## 一度だけ手動でトリガーする
オートパイロットのデバッグ中に cron を待たないためには、手動でトリガーしてください。
- UI: オートパイロット詳細ページで「Run now」をクリック
- CLI:
```bash
multica autopilot trigger <autopilot-id>
```
手動トリガーは `schedule` トリガーとまったく同じ実行フローを通り — 実行レコードの `source` フィールドのみが `manual` とマークされます。
## webhook からトリガーする
オートパイロットはインバウンドの HTTP webhook でも発火できます。オートパイロット詳細ページで **Webhook** トリガーを追加すると、Multica は次のような形の一意の URL を生成します。
```
https://<your-multica-host>/api/webhooks/autopilots/awt_…
```
その URL に任意の JSON を POST してください — Multica は `source = webhook` で実行を記録し、本文を実行の `trigger_payload` として保存し、schedule トリガーとまったく同じ方法でエージェントをディスパッチします。
```bash
curl -X POST "$MULTICA_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{"event":"demo.received","eventPayload":{"message":"hello"}}'
```
**イシュー作成モード**では、インバウンドの payload が新しいイシューの説明に追記され、エージェントがインラインで読めるようになります。**実行専用モード**では、payload はデーモンがエージェントに渡す実行コンテキストの一部になります。
### Payload の形
独自のエンベロープenvelopeを送れます。
```json
{ "event": "github.pull_request.opened", "eventPayload": { } }
```
…または任意の JSON オブジェクト / 配列を送ることもできます。Multica はこれを内部エンベロープに正規化します。
```json
{
"event": "<inferred>",
"eventPayload": <your body>,
"request": { "receivedAt": "<rfc3339>", "contentType": "application/json" }
}
```
`event` フィールドを指定しない場合、Multica は一般的なヘッダーと本文フィールドからこれを推論します(`X-GitHub-Event` + 本文 `action`、`X-Gitlab-Event`、`X-Event-Type`、本文の `event`/`type`/`action`)。どれも一致しない場合、イベントは `webhook.received` になります。
GitHub のようなソースを構成するときは、content type を `application/json` に設定してください — フォームエンコードされた webhook payload は受け付けられません。
### イベントフィルター
新しい webhook トリガーはインバウンドの POST ごとに発火します。単一用途の URL には問題ありませんが、多数のイベントタイプをファンアウトするソースGitHub が代表的です — 単一のリポジトリ webhook 一つが `push`、`pull_request`、`workflow_run`、`check_suite` などを配信できますにはイズになります。webhook トリガーの**イベントフィルターEvent filters**セクションを使うと、実際に実行をディスパッチするイベントを制限でき、それ以外のすべては `status = ignored`、`reason = event_filtered` で配信履歴に記録され、実行もイシューも作成されません。
各行は 1 つのルールです。**イベント名event name**と、任意でカンマ区切りの **action** リストで構成されます。Multica は**いずれか 1 つ**の行でも一致すれば webhook を許可します。セクションを空のままにすると、すべてを受け付けます(フィルタリング以前の動作)。
例:
| イベント名 | Actions | 一致対象 |
| -------------- | ------------------- | ------------------------------------------------------------------------ |
| `workflow_run` | `completed, failed` | `action: completed` または `action: failed` の `workflow_run` イベントのみ |
| `workflow_run` | _(空)_ | action に関係なくすべての `workflow_run` イベント |
| `push` | _(空)_ | すべての `push` イベント |
#### イベント名と action の出所
Multica は次の順序でインバウンドリクエストから `event` 名と `action` を導き出します — **最初に一致したものが優先されます**。
**1. 本文エンベロープBody envelope。** 本文が文字列の `event` フィールドを持つ JSON オブジェクトであれば、その値がそのままイベント名になります。任意の `eventPayload` オブジェクトは、自身の `action` / `state` / `conclusion` / `status` フィールドから action 候補を提供します。
```bash
curl -X POST "$MULTICA_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d '{"event":"trigger","eventPayload":{"action":"true"}}'
# inferred: event = trigger, action candidate = true
```
**2. ヘッダーHeaders。** 本文エンベロープがない場合、Multica は次のよく知られたプロバイダーヘッダーを読みます。
- `X-GitHub-Event: <event>` — (存在する場合)最上位の本文 `action` フィールドと組み合わされて `github.<event>.<action>` を形成します。
- `X-Gitlab-Event: <event>` — `gitlab.<event>` になります。
- `X-Event-Type: <event>` — そのまま通過します。
```bash
# GitHub-style: header gives the event name, body gives the action.
curl -X POST "$MULTICA_WEBHOOK_URL" \
-H 'X-GitHub-Event: workflow_run' \
-H 'Content-Type: application/json' \
-d '{"action":"completed"}'
# inferred: event = github.workflow_run.completed
# → matches a filter row of workflow_run / completed
# Generic event-type header — no body fields needed.
curl -X POST "$MULTICA_WEBHOOK_URL" \
-H 'X-Event-Type: trigger.true' \
-H 'Content-Type: application/json' \
-d '{}'
# inferred: event = trigger.true → matches trigger / true
```
**3. 本文フォールバックBody fallback。** 本文エンベロープも既知のヘッダーもない場合、Multica は次の順序で最上位の本文文字列フィールドにフォールバックします: `event` → `type` → `action`。
```bash
curl -X POST "$MULTICA_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d '{"type":"trigger","action":"true"}'
# inferred: event = trigger (from `type`), action candidate = true
```
**4. デフォルトDefault。** 上記のいずれも一致しない場合、イベントは `webhook.received` で、action 候補はありません。
**action 候補、全リスト。** イベントが決定されると、Multica は以下のすべての値を可能な action 一致対象として考慮します。
- イベントが `provider.event.<action>` の形のときのイベント名のサフィックス(例: `github.workflow_run.completed` → `completed`)。
- 本文フィールド `action`、`state`、`conclusion`、`status` — **JSON 文字列のときのみ該当します**。ブール値(`{"action": true}`)や数値は資格がないため、`event=trigger, action=true` を期待するフィルターは `{"trigger": true}` の本文とは決して一致しません。`true` は文字列ではなく bool だからです。
**よくある落とし穴。** `Event name: trigger` / `Actions: true` のようなフィルター行は、「本文に `trigger: true` があれば発火せよ」という意味では**ありません** — イベントフィルターは任意の本文フィールドではなく、*推論されたイベントと action* に一致させます。これにヒットさせるには、`X-Event-Type` で `trigger.true` を送るか(または上に示した本文エンベロープを使ってください)。保存されたフィルター行の周囲の空白(`" workflow_run "`)はそのまま保存され、決して一致しないため — 保存する前に trim してください。
#### クイックテスト
フィルターを構成したら、`curl` で両方の分岐を確認できます。
```bash
# Allowed — header drives event=workflow_run, body drives action=completed
curl -X POST "$MULTICA_WEBHOOK_URL" \
-H 'X-GitHub-Event: workflow_run' \
-H 'Content-Type: application/json' \
-d '{"action":"completed"}'
# → 200 {"status":"accepted", ...}
# Filtered — same event, action not in allowlist
curl -X POST "$MULTICA_WEBHOOK_URL" \
-H 'X-GitHub-Event: workflow_run' \
-H 'Content-Type: application/json' \
-d '{"action":"in_progress"}'
# → 200 {"status":"ignored","reason":"event_filtered"}
```
### URL は bearer secret です
生成された URL **そのものが**認証情報です。それを持っている人は誰でもオートパイロットを発火できます。トークンのように扱ってください。
- **公開のイシュースレッド、スクリーンショット、チャット履歴に貼り付けないでください。**
- **漏洩したら交換してください** — トリガー行で「Rotate URL」をクリックするか、`multica autopilot trigger-rotate-url <autopilot-id> <trigger-id>` を実行してください。古い URL はただちに動作を停止します。
- 強力なソース認証が必要なソースの場合は、トリガーごとの HMAC 署名検証を待ってください。この v1 URL は bearer 方式のみをサポートします。
- 現時点では、オートパイロットを閲覧できるワークスペースメンバーであればその webhook URL を読めます — 役割ごとのより厳格な secret の可視性は後続作業です。
### ステータスコードの意味
Multica は正常な no-op の結果に対して `status` フィールド付きで `200 OK` を返すため、プロバイダーの webhook 再試行メカニズムが URL を叩き続けることはありません。
- `{"status":"accepted","run_id":"…","autopilot_id":"…","trigger_id":"…"}` — 実行がディスパッチされました。
- `{"status":"skipped","run_id":"…","reason":"agent runtime is offline at dispatch time"}` — 割り当て先のランタイムがオフラインで、`skipped` の実行として記録されます。
- `{"status":"ignored","reason":"trigger_disabled"}` — トリガーが無効になっています。
- `{"status":"ignored","reason":"autopilot_paused"}` — オートパイロットが一時停止しています。
- `{"status":"ignored","reason":"autopilot_archived"}` — オートパイロットがアーカイブされています。
2xx 以外の応答は実際の失敗を扱います。
- `400` — 無効な JSON、スカラー本文、空の本文。
- `404` — 不明なトークン(`{"error":"webhook not found"}`)。
- `413` — payload が 256 KiB を超えました。
- `429` — トークンごとのレート制限超過(デフォルトは 60 req/min
### セルフホスト: 公開 URL を構成する
サーバーに `MULTICA_PUBLIC_URL` が設定されている場合(例: `https://multica.example.com`)、トリガー応答に絶対パスの `webhook_url` が含まれ、UI にはすぐにコピーできる URL が表示されます。設定しない場合、UI はクライアントの API origin から URL を構成します — デスクトップと同一オリジンの Web には問題ありませんが、カスタムのセルフホストリバースプロキシには適しません。Multica は、誤って構成されたリバースプロキシが攻撃者の制御するホストを指す webhook URL をサーバーに発行させて欺くことができないよう、`Host` / `X-Forwarded-Host` ヘッダーから公開ホストを導出しないよう意図的に設計されています。
## 実行履歴を見る
すべてのトリガーは**実行レコードrun record**を生成し、オートパイロット詳細ページの「History」タブで確認できます。
- トリガーソース(`schedule` / `manual` / `webhook`
- 開始時刻、完了時刻
- ステータス(`issue_created` / `running` / `completed` / `failed` / `skipped`
- 連携したイシュー(イシュー作成モード)または `task`(実行専用モード)
- 失敗理由(失敗またはスキップした場合)
## オートパイロットが失敗したらどうなるか
<Callout type="warning">
**オートパイロットの失敗は自動的に再試行されず、インボックス通知も送られません。** 失敗は実行履歴に `failed` のエントリを残すだけで — 割り当てや @-メンションのようなシステムレベルの再キューイングもなく、誰にも通知が行きません。オートパイロットが定期的な場合、**次の cron 発火が新しい実行をトリガー**しますが、失敗した作業が自動的に再実行されることはありません。
オートパイロットが重要な場合は、独自のモニタリングを設計してください — 例えば、エージェントに成功時にコメントを残させ、コメントの欠落に気づくことで失敗を検出する、といった具合です。
</Callout>
自動再試行がない理由: オートパイロットはすでに定期的であるため、システムレベルの再試行を追加すると次の予定実行の上に重なり、重複した実行を生み出します。スケジューリングを完全に cron に任せることで、すっきりと保てます。
## まだ提供されていない機能
**API 種類のトリガーはまだ接続されていません。** トリガースキーマは `api` 種類を予約していますが、それを発火させるイングレスルートはありません。UI は既存の行に Deprecated バッジを表示し、コピー / 交換の操作は提供しません。トリガーごとの HMAC 署名検証、IP 許可リスト、プロバイダー固有のイベントプリセットは後続作業として追跡されており、v1 URL は bearer 方式のみをサポートします。
## 次へ
- [**エージェントにイシューを割り当てる**](/assigning-issues) — イシューをエージェントに一回限りで引き渡す
- [**コメントでエージェントを @-メンションする**](/mentioning-agents) — コメントからエージェントを呼んで一度見てもらう
- [**チャット**](/chat) — イシューの外での一対一の会話

View File

@@ -0,0 +1,63 @@
---
title: チャット
description: どのイシューにも属さない、エージェントとの一対一の会話 — 完全にサンドボックス化されています。エージェントはイシューを見たり変更したりできず、他の誰もこの会話を見ることはできません。
---
import { Callout } from "fumadocs-ui/components/callout";
**チャットはあなたと[エージェント](/agents)との一対一の会話です** — [イシュー](/issues)ボードから外に出るものです。エージェントはどのイシューも見られず、どのイシューも変更できず、会話全体は**完全に非公開**です([ワークスペース](/workspaces)内の他の誰も、admin を含めて、この会話を見ることはできません)。エージェントとアプローチを議論したり、ブレインストーミングをしたり、どのイシューにも属さない質問をしたりするのに適しています。
## エージェントを @-メンションするだけではだめなのですか?
[@-メンション](/mentioning-agents)はエージェントをイシューのコンテキスト**の中へ引き入れます** — エージェントはイシューの説明とすべての過去のコメントを読み、イシューを変更できます。チャットはこれを逆転させます。**あなたをイシューの外へ引き出します** — エージェントはこの単一の会話のみを見られ、どのイシューの存在も認識せず、イシューを変更する入口もありません。
2 つの判断基準:
- 特定のイシューのコンテキストに基づくフィードバックがほしいとき → [@-メンション](/mentioning-agents)
- どのイシューとも無関係なトピックを議論したいとき(または他の誰にも議論を見られたくないとき) → チャット
## 会話を始める
サイドバーから**チャット**を開き、エージェントを選んで、新しい会話を始めてください。インターフェースはどのメッセージングアプリとも似ています。メッセージを送るとエージェントが返信します。各メッセージはバックグラウンドで実行をトリガーするため(キューに入れられた `task`)、返信には数秒かかることがあります。
## チャットでエージェントができることとできないこと
エージェントは会話の中で**完全にサンドボックス化された**モードで実行されます。
**できること:**
- 現在のメッセージに含まれる質問に答える
- 構成された[スキル](/skills)と MCP を使う
- 自身の作業ディレクトリでファイルを読み書きする
- イシューコンテキストを必要としない `multica` CLI コマンドを呼び出す(例: 基本的なワークスペース情報の照会)
**できないこと:**
- **どのイシューも見ること** — エージェントが受け取るプロンプトにはイシュー ID がなく、`multica issue list` のようなコマンドは空の結果を返します
- **どのイシューも変更すること** — イシューコンテキストがなければ、権限チェックによって API 呼び出しがブロックされます
- **他の会話を見ること** — 会話は完全に隔離されています
- **誰かや任意のエージェントを @-メンションすること** — チャットは他者に通知する経路のない非公開の空間です
## 複数ターンのコンテキストが保持される仕組み
チャットは**プロバイダーセッションの再開**を通じて複数ターンのコンテキストを維持します — エージェントは最初の返信でプロバイダーセッションを確立し(例: Claude セッション)、そのセッション ID が保存されます。次のメッセージでは、タスクのディスパッチがその ID を渡し直すため、エージェントは毎回履歴を読み直すことなく**中断したところから再開**します。
もし**1 つのターンが失敗した**場合、Multica はセッション ID を確立していた以前のタスク(そのタスクが成功したか失敗したかにかかわらず)を探し、再開を試みます — 途中で一度失敗したからといって、会話全体の記憶が失われることはありません。
注: すべてのプロバイダーが実際にセッション再開を実装しているわけではありません — サポート状況は[**プロバイダーマトリックス**](/providers)を参照してください。
## 会話をアーカイブする
もう見たくない会話はアーカイブできます — 会話一覧で右クリックするか、詳細ページの「アーカイブ」ボタンを使ってください。アーカイブ後は次のようになります。
- 会話がアクティブな一覧から消えます(「アーカイブ済み」ビューで引き続き見つけられます)
- 過去のメッセージ、セッション ID、作業ディレクトリはすべて保持されます — 何も削除されません
<Callout type="warning">
**アーカイブ後には「復元」ボタンがありません。** 現在、アーカイブされた会話を再びアクティブな状態に戻す入口はありません。後でそのスレッドを続けたい場合は、新しい会話を始める必要があります。アーカイブされた会話の内容を再び見るには、「アーカイブ済み」ビューを開いて履歴を読んでください。
</Callout>
## 次へ
- [**オートパイロット**](/autopilots) — エージェントがスケジュールに従って自動的に作業を開始できるようにします
- [**エージェントにイシューを割り当てる**](/assigning-issues) — トピックをイシューボードに戻します

View File

@@ -0,0 +1,147 @@
---
title: CLI コマンドリファレンス
description: すべてのトップレベル Multica CLI コマンドを 1 ページにまとめた概要です。完全な使い方は `multica <command> --help` を実行してください。
---
import { Callout } from "fumadocs-ui/components/callout";
Multica CLI は、Web UI でできるほぼすべての操作をそのまま提供します([イシュー](/issues)の作成、[エージェント](/agents)の割り当て、[デーモン](/daemon-runtimes)の起動など)。このページでは、すべてのトップレベルコマンドを 1 行の説明とともに一覧します。フラグや例の完全な一覧は `multica <command> --help` を実行してください。
## 認証する
CLI を初めて使うときにこのコマンドを実行して、**パーソナルアクセストークンPAT**を取得します。
```bash
multica login
```
ブラウザが自動的に開きます。Web アプリで承認すると、CLI が PAT`mul_` プレフィックス付き)を `~/.multica/config.json` に保存します。これ以降のすべてのコマンドはこの PAT で認証されます。
<Callout type="tip">
CI やヘッドレス環境では、ブラウザフローをスキップできます。Web アプリの **Settings → Personal Access Tokens** で PAT を作成し、`multica login --token <mul_...>` で直接渡してください。
</Callout>
トークンの種類による違いについては、[認証とトークン](/auth-tokens)を参照してください。
## 認証とセットアップ
| コマンド | 用途 |
|---|---|
| `multica login` | ログインして PAT を保存 |
| `multica auth status` | 現在のログイン状態、ユーザー、ワークスペースを表示 |
| `multica auth logout` | ローカルの PAT を削除 |
| `multica setup cloud` | Multica Cloud のワンショットセットアップ(ログイン + デーモンのインストール) |
| `multica setup self-host` | セルフホストバックエンドのワンショットセットアップ |
## ワークスペースとメンバー
| コマンド | 用途 |
|---|---|
| `multica workspace list` | アクセスできるすべてのワークスペースを一覧 |
| `multica workspace get <slug>` | 1 つのワークスペースの詳細を表示 |
| `multica workspace member list` | 現在のワークスペースのメンバーを一覧 |
| `multica workspace update <id> --name "..." [--description "..."] [--context "..."] [--issue-prefix "..."]` | ワークスペースのメタデータを更新admin/owner。長いフィールドは `--description-stdin` / `--context-stdin` を使用できます。 |
## イシューとプロジェクト
<Callout type="info">
`list` 系のコマンド(`multica issue list`、`autopilot list`、`project list` など)は、デフォルトで短く**そのままコピー&ペーストできる** ID を出力します。イシューは `MUL-123` のようなイシューキー、それ以外のリソースは短い UUID プレフィックスです。以下の後続コマンドの `<id>` 引数は短い ID と完全な UUID のどちらも受け取るため、一般的な流れは `multica issue list` → キーをコピー → `multica issue get MUL-123` となります。正式な UUID が必要なときは `list` コマンドに `--full-id` を渡してください。
</Callout>
| コマンド | 用途 |
|---|---|
| `multica issue list` | イシューを一覧(コピー&ペーストできるイシューキーを出力) |
| `multica issue get <id>` | 単一のイシューを表示(イシューキーまたは UUID を受け取る) |
| `multica issue create --title "..."` | 新しいイシューを作成 |
| `multica issue update <id> ...` | イシューを更新(ステータス、優先度、担当者など) |
| `multica issue assign <id> --agent <slug>` | エージェントに割り当て(即座にタスクをトリガー) |
| `multica issue status <id> --set <status>` | ステータス変更のショートカット |
| `multica issue search <query>` | キーワード検索 |
| `multica issue runs <id>` | イシュー上のエージェント実行を表示 |
| `multica issue rerun <id>` | イシューの現在のエージェント担当者向けに新しいタスクを再キューイング |
| `multica issue comment <id> ...` | ネスト: コメントの表示 / 投稿 |
| `multica issue subscriber <id> ...` | ネスト: 購読 / 購読解除 |
| `multica project list/get/create/update/delete/status` | プロジェクトの CRUD |
## エージェントとスキル
| コマンド | 用途 |
|---|---|
| `multica agent list` | ワークスペースのエージェントを一覧 |
| `multica agent get <slug>` | エージェントの構成を表示 |
| `multica agent create ...` | エージェントを作成 |
| `multica agent update <slug> ...` | エージェントを更新 |
| `multica agent archive <slug>` | アーカイブ |
| `multica agent restore <slug>` | アーカイブ済みのエージェントを復元 |
| `multica agent tasks <slug>` | エージェントのタスク履歴を表示 |
| `multica agent skills ...` | ネスト: スキルのアタッチ / デタッチ |
| `multica skill list/get/create/update/delete` | スキルの CRUD |
| `multica skill import ...` | GitHub、ClawHub、またはローカルマシンからスキルをインポート |
| `multica skill files ...` | ネスト: スキルのファイルを管理 |
## スクワッド
| コマンド | 用途 |
|---|---|
| `multica squad list` | ワークスペースのスクワッドを一覧 |
| `multica squad get <id>` | 単一のスクワッドを表示 |
| `multica squad create --name "..." --leader <agent>` | スクワッドを作成owner / admin |
| `multica squad update <id> ...` | 名前、説明、指示、リーダー、またはアバターを更新 |
| `multica squad delete <id>` | アーカイブ(ソフト削除) — 割り当て済みのイシューをリーダーに移管 |
| `multica squad member list/add/remove <squad-id>` | スクワッドメンバーを管理 |
| `multica squad activity <issue-id> <action\|no_action\|failed> --reason "..."` | スクワッドリーダーエージェントがターンごとに評価を記録するために使用 |
完全なモデルについては[スクワッド](/squads)を参照してください。
## オートパイロット
| コマンド | 用途 |
|---|---|
| `multica autopilot list` | ワークスペースのすべてのオートパイロットを一覧 |
| `multica autopilot get <id>` | 単一のオートパイロットを表示 |
| `multica autopilot create ...` | オートパイロットを作成 |
| `multica autopilot update <id> ...` | 更新 |
| `multica autopilot delete <id>` | 削除 |
| `multica autopilot runs <id>` | 実行履歴を表示 |
| `multica autopilot trigger <id>` | 手動で実行をトリガー |
## デーモンとランタイム
| コマンド | 用途 |
|---|---|
| `multica daemon start` | デーモンを起動(デフォルトはバックグラウンド。`--foreground` を追加するとフォアグラウンドで実行) |
| `multica daemon stop` | デーモンを停止 |
| `multica daemon restart` | デーモンを再起動 |
| `multica daemon status` | デーモンがオンラインかどうかと同時実行数を確認 |
| `multica daemon logs` | デーモンのログを表示 |
| `multica runtime list` | 現在のワークスペースのランタイムを一覧 |
| `multica runtime usage` | リソース使用量を表示 |
| `multica runtime activity` | 最近のアクティビティログ |
| `multica runtime update <id> ...` | ランタイムの構成を更新 |
## その他
| コマンド | 用途 |
|---|---|
| `multica repo checkout <url>` | エージェントが使用できるようにリポジトリをローカルにクローン |
| `multica config` | ローカルの CLI 構成を表示または編集 |
| `multica version` | CLI のバージョンを出力 |
| `multica update` | CLI を最新のリリースにアップグレード |
| `multica attachment download <id>` | イシューまたはコメントから添付ファイルをダウンロード |
## 完全なフラグを確認する
すべてのコマンドが `--help` をサポートしています。
```bash
multica issue create --help
multica agent update --help
```
v2 では、各コマンドごとに専用の詳細なリファレンスページを提供する予定です。
## 次のステップ
- [認証とトークン](/auth-tokens) — PAT vs. JWT vs. デーモントークン
- [デーモンとランタイム](/daemon-runtimes) — `daemon` コマンドが内部でどう動作するか
- [エージェントの作成と構成](/agents-create) — `multica agent create` のすべてのオプション

View File

@@ -0,0 +1,119 @@
---
title: Cloud クイックスタート
description: サインアップからエージェントへの最初のタスク割り当てまで 5 分で。
---
import { Callout } from "fumadocs-ui/components/callout";
このページは Multica Cloud を最初から最後まで案内します — **サインアップ → [CLI](/cli) のインストール → [デーモン](/daemon-runtimes)の起動 → [エージェント](/agents)の作成 → 最初の[タスク](/tasks)の割り当て**。約 5 分かかります。
前提条件は 1 つだけです: ローカルに [AI コーディングツール](/providers)[Antigravity](/providers#antigravity)、[Claude Code](/providers#claude-code)、[Codex](/providers#codex)、[Cursor](/providers#cursor)、[Copilot](/providers#copilot)、[Gemini](/providers#gemini)、[Hermes](/providers#hermes)、[Kimi](/providers#kimi)、[Kiro CLI](/providers#kiro-cli)、[OpenCode](/providers#opencode)、[OpenClaw](/providers#openclaw)、[Pi](/providers#pi) のいずれか)を少なくとも 1 つ、すでにインストールしておくこと。デーモンは起動時にこれらを自動検出し、1 つもなければ起動を拒否します。
## 1. アカウントを作成する
[multica.ai](https://multica.ai) でサインアップしてください。メール6 桁の確認コード)または Google でログインできます。
サインアップ後は(アカウント名から生成された)デフォルトのワークスペースに自動的に配置されます。後で名前を変更したり、新しいワークスペースを作成したりできます。
## 2. Multica CLI をインストールする
**macOS / LinuxHomebrew 推奨)**:
```bash
brew install multica-ai/tap/multica
```
**macOS / LinuxHomebrew なし)**:
```bash
curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash
```
**WindowsPowerShell**:
```powershell
irm https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.ps1 | iex
```
インストールを確認します。
```bash
multica version
```
## 3. ログイン + デーモンの起動
コマンド 1 つでログインとデーモンの起動を処理します。
```bash
multica setup
```
`multica setup` は次を実行します。
1. CLI が Multica Cloud に接続するよう構成します
2. ログインのためにブラウザを開きますWeb と同じメール確認コード / Google OAuth
3. 生成された PAT を `~/.multica/config.json` に保存します
4. **デーモンを自動的に起動します** — 3 秒ごとにタスクをポーリングし、15 秒ごとにハートビートを送信し始めます
<Callout type="info">
**デスクトップアプリを使用していますか?** デスクトップアプリは起動時に**デーモンを自動的に起動します** — `multica setup` を手動で実行する必要はありません。[デスクトップアプリ](/desktop-app)を参照してください。
</Callout>
デーモンが実行中かどうかを確認します。
```bash
multica daemon status
```
`online` はサーバーに登録されたことを意味します。
## 4. ランタイムがオンラインか確認する
Web UI で **Settings → Runtimes** に移動します。先ほど起動したデーモンが、1 つ以上のアクティブなランタイムとして表示されるはずです — ローカルにインストールされた AI コーディングツールごとに 1 つです。
オフラインと表示されても慌てないでください — [トラブルシューティング → デーモンがサーバーに接続できない](/troubleshooting#daemon-cant-connect-to-the-server)を参照してください。
## 5. エージェントを作成する
Web UI で **Settings → Agents** に移動し、**New Agent** をクリックします。
- **Name** — ボードやコメントでこのエージェントに表示される名前です。好きな名前を選んでください
- **Provider** — ローカルにインストールした AI コーディングツールを選択します(ドロップダウンにはランタイムで検出されたツールのみが表示されます)
- **Model**(任意) — そのツール内部のモデル選択(プロバイダーによって静的な一覧または動的探索)
- **Instructions**(任意) — このエージェントのためのシステムプロンプト
作成されると、エージェントはワークスペースのメンバー一覧に表示され、人間のメンバーと同じように作業を割り当てられます。
## 6. 最初のタスクを割り当てる
Web UI でイシューを作成するか、CLI から作成します。
```bash
multica issue create --title "Add an ASCII architecture diagram to the README"
```
先ほど作成したエージェントにイシューを割り当てます — Web UI でアバターをクリックするか、CLI を使用します。
```bash
multica issue assign MUL-1 --to my-agent-name
```
`--to` はエージェントまたはメンバーの**名前**を受け取ります。部分文字列の一致も機能します — エージェント名が `my-code-reviewer` なら、`reviewer` でそれに解決されます。ワークスペースに名前が重複している場合は、代わりに `--to-id <uuid>``--to` と相互排他を渡してください。UUID は `multica agent list --output json` または `multica workspace member list --output json` で調べられます。
**次にデーモンで起きること**:
1. 3 秒以内にタスクを取得します(ステータスが `queued` から `dispatched` に変わります)
2. 一致する AI コーディングツールを呼び出して作業を開始します(ステータスが `running` になります)
3. AI がローカルで作業します — コードディレクトリを読んだり、コマンドを実行したり、ファイルを編集したりできます
4. 完了すると結果を Multica に報告します(自動リトライが作動するかどうかに応じて、ステータスが `completed` または `failed` になります)
Web UI は**リアルタイムで**WebSocket を通じて)更新されます — 再読み込みは不要です。
## 次のステップ
- [デーモンとランタイム](/daemon-runtimes) — デーモンがどう動作するかとランタイムの意味
- [タスク](/tasks) — タスクのライフサイクルとリトライルール
- [AI コーディングツール比較](/providers) — 12 個のツール間の機能差
- [デスクトップアプリ](/desktop-app) — デーモンを自分で実行したくない場合
- [セルフホストクイックスタート](/self-host-quickstart) — 自前のバックエンドを実行する

View File

@@ -0,0 +1,81 @@
---
title: コメントとメンション
description: イシューの下での共同作業 — コメント、返信、`@` メンション、リアクション、そしてコメントからエージェントをトリガーする方法。
---
import { Callout } from "fumadocs-ui/components/callout";
すべての[イシュー](/issues)にはコメントスレッドがあります。コメントを投稿し、誰かに返信し、[メンバー](/members-roles)や[エージェント](/agents)を `@` でメンションし、リアクションを追加する — これまで使ってきたどのタスク管理ツールでも行ってきたのと同じ操作です。唯一の違いは、**`@` でエージェントをメンションすると、そのエージェントが作業を開始するようトリガーされる**ことです。
## コメントを投稿する
イシュー詳細ページ下部の入力欄に内容を入力し、**送信**を押してください。コメントはすぐにスレッドに表示されます。コメントは Markdown に対応しています — 見出し、リスト、コードブロック、リンクがすべて使えます。
## コメントに返信する
任意のコメントの右上にある**返信**をクリックすると、その下にネストされた入力欄が開きます。返信はそのコメントの子要素として表示され、会話スレッドを形成します。返信にもさらに返信を付けられ、必要なだけ深くネストできます。
イシュー一覧にはトップレベルのコメント数だけが表示され、イシューを開くと会話ツリー全体が見えます。
## リアクション
各コメントの右上には、素早く意思を伝えるためのリアクションボタンがあります(👍、👀、🎉)— 同意を示すために「+1」コメントをわざわざ投稿する必要はありません。
## `@` メンション
コメントに `@` を入力するとピッカーが開きます。メンバーまたはエージェントを選ぶと、`@` と対象のスラッグが挿入されます(`@alice` や `@reviewer-bot`)。メンションされた相手は自分の[インボックス](/inbox)に通知を受け取ります。
**エージェントをメンションすると自動的にトリガーされます** — [コメントでエージェントをメンションする](/mentioning-agents)を参照してください。
1 つのコメントで同じ人を複数回メンションしても、通知は**1 つだけ**発生します。
### `@all` はワークスペース全体に通知する
`@all` は特別な対象です。ワークスペースのすべてのメンバーに通知を送ります。人もエージェントも `@all` を使えます — つまり進捗を報告するエージェントも `@all` できるので、エージェントの指示には控えめに使うよう伝えておきましょう。
<Callout type="warning">
**`@all` は慎重に使ってください。** 規模の大きいワークスペースでは、たった 1 回の `@all` がその人数分のインボックス通知を瞬時に生成します。全員が本当に知る必要があることだけに使い、日常的な更新には使わないでください。
</Callout>
## イシューを参照する
別のイシューをリンクするには、`MUL-123` のようにそのイシューキーを入力してください。Multica はコメント内で実在するイシューキーを解決し、内部的に `mention://issue/<uuid>` リンクとして保存します。イシューリンクは単なる相互参照にすぎません。人に通知を送ることはなく、エージェントをトリガーすることもありません。
通常は `[MUL-123](mention://issue/<uuid>)` を手で書く必要はありません。その形式は、Multica がキーを解決した後に使う標準的な内部表現です。
<Callout type="info">
Markdown の強調は CommonMark のルールに従います。太字テキストが句読点や閉じ引用符で終わり、その直後に韓国語の助詞が続く場合、閉じの `**` が認識されないことがあります。
引用符を太字の範囲の外に出すことをおすすめします。
```markdown
"**무엇을 먼저 정해두고 시작할지**"가
```
次の代わりに:
```markdown
**"무엇을 먼저 정해두고 시작할지"**가
```
</Callout>
## コメントの編集と削除
コメントは作成者のみが編集または削除できます。
コメントを削除すると、その下の**すべての返信も一緒に削除されます**(返信への返信も含む)。内容だけを変えたい場合は、削除ではなく編集を使ってください。
<Callout type="warning">
**コメントを編集して `@` を追加しても、エージェントはトリガーされません。** トリガーはコメントが**作成された**その瞬間に発生します — 後から編集して新しい `@` を追加したり、対象を変えたりしても、新しい通知は送られず、エージェントも起きません。見逃したエージェントを呼び出すには、そのエージェントを `@` する**新しいコメントを投稿**してください。
</Callout>
---
ここまで扱ってきた内容はすべて「人の世界」です — ワークスペース、メンバー、イシュー、プロジェクト、コメント。Linear や Jira を使ったことがあれば、これまでの内容はまったく目新しくないはずです。
しかし Multica の決定的な特徴はまだ登場していません。**エージェントをワークスペースの一級メンバーとして扱うこと**です。次はまさにこの話に移ります。
## 次へ
- [エージェント](/agents) — 何であり、人とどう違うのか
- [コメントでエージェントをメンションする](/mentioning-agents) — コメントで `@` を使ってエージェントを起動する

View File

@@ -0,0 +1,111 @@
---
title: デーモンとランタイム
description: エージェントは Multica のサーバーでは実行されません — あなた自身のマシンで実行されます。
---
import { Callout } from "fumadocs-ui/components/callout";
import { Mermaid } from "@/components/mermaid";
Multica では、[エージェント](/agents)は私たちのサーバーでは実行され**ません** — ローカルにインストールされた [AI コーディングツール](/providers)を呼び出す**デーモン**という小さなプログラムが駆動し、あなた自身のマシンで実行されます。Multica サーバーは調整役に徹します。[イシュー](/issues)を保存し、[タスク](/tasks)をキューに入れ、適切な**ランタイム**へ分配します(ランタイム = デーモン × AI コーディングツール 1 つ)。
この構造が Multica と Linear / Jira の最大の違いです。**あなたの API キー、ツールチェーン、コードディレクトリはすべてあなたのマシンに残り**、Multica サーバーはそのどれも見ることはありません。つまり「自分のエージェントが動かない」はほとんど常にローカルの問題です。デーモンが実行されていない、AI ツールがインストールされていない、キーが期限切れになっている、といったことです。まずローカルを確認してください。案内は[トラブルシューティング](/troubleshooting)を参照してください。
## デーモンを起動する
デーモンは Multica CLI の一部です。[Multica CLI](/cli) をインストールしたら、あなた自身のマシンで実行してください。
```bash
multica daemon start
```
起動時にデーモンは 4 つのことを行います。
1. ログイン時に保存された認証情報を読み込みます
2. `PATH` にインストールされた AI コーディングツールを検出します(内蔵 12 種: [Antigravity](/providers#antigravity)、[Claude Code](/providers#claude-code)、[Codex](/providers#codex)、[Cursor](/providers#cursor)、[Copilot](/providers#copilot)、[Gemini](/providers#gemini)、[Hermes](/providers#hermes)、[Kimi](/providers#kimi)、[Kiro CLI](/providers#kiro-cli)、[OpenCode](/providers#opencode)、[OpenClaw](/providers#openclaw)、[Pi](/providers#pi)
3. 検出した各ツールに対するランタイムとともに、自身をサーバーに登録します
4. **3 秒ごと**に取得すべきタスクがないかポーリングし、**15 秒ごとにハートビートを送信**し続けます
よく使うコマンド:
| コマンド | 用途 |
|---|---|
| `multica daemon start` | 起動(デフォルトはバックグラウンド。フォアグラウンドで実行するには `--foreground` を追加) |
| `multica daemon stop` | 停止 |
| `multica daemon restart` | 再起動 |
| `multica daemon status` | ステータス表示 |
| `multica daemon logs` | ログ表示(追従するには `-f` を追加) |
完全な CLI リファレンスは [CLI コマンド](/cli)を確認してください。
**デスクトップアプリにはデーモンが同梱されています。** [デスクトップアプリ](/desktop-app)を使う場合、`multica daemon start` を手動で実行する必要はありません。起動時にデーモンを自動的に立ち上げます。あなたのワークフローにどの方式が合うかは、[デスクトップアプリ](/desktop-app)ページを参照してください。
## 1 つのマシンに複数のランタイムができる理由
ランタイムはサーバーでもコンテナでもありません。「**デーモン × AI コーディングツール 1 つ**」の組み合わせです。たとえば、Claude Code と Codex の両方がインストールされた MacBook でデーモンを起動し、あなたが 2 つのワークスペースのメンバーだとします。すると Multica は 4 つのランタイムを登録します。
<Mermaid chart={`
graph TD
D["あなたのデーモン<br/>MacBook"]
D --> R1["ランタイム<br/>ワークスペース A × Claude Code"]
D --> R2["ランタイム<br/>ワークスペース A × Codex"]
D --> R3["ランタイム<br/>ワークスペース B × Claude Code"]
D --> R4["ランタイム<br/>ワークスペース B × Codex"]
`} />
要点:
- **1 つのデーモンは複数のランタイムにマッピングされ得ます** — インストールされたツールと、あなたが所属するワークスペースの組み合わせごとに 1 つできます
- **同じデーモン、ワークスペース、ツールは、ちょうど 1 つのランタイムを作ります** — デーモンを再起動しても重複レコードは生まれません
- Multica UI の**ランタイム**ページがこれらの行を一覧表示します
<Callout type="info">
**クラウドランタイムが近日提供されます。** 現在は順番待ちリストの段階です。提供が始まれば、ローカルのデーモンを実行せずに Multica Cloud 上で直接エージェントタスクを実行できるようになります。[ダウンロードページ](https://multica.ai/download)でメールアドレスを登録すると通知を受け取れます。
</Callout>
## ランタイムがオフラインと表示される時点
Multica はハートビートでランタイムがオンラインかどうかを判断します。3 つの重要な数値があります。
| イベント | しきい値 |
|---|---|
| デーモンのハートビート頻度 | **15 秒**ごと |
| 欠落として表示 | **45 秒**間ハートビートなし3 回欠落) |
| 自動削除 | 関連するエージェントがない状態で **7 日**以上欠落 |
欠落は永続的ではありません。デーモンが再びハートビートを送った瞬間にオンラインに戻り、ランタイムレコードも保持されます。デーモンを再起動してもランタイムは失われません。
<Callout type="warning">
**欠落したランタイムで実行中だったタスクは失敗として表示されます**(失敗理由 `runtime_offline`。リトライ可能なソースイシュー、チャットについては、Multica が自動的に再度キューに入れます。オートパイロットがトリガーしたタスクは自動的にはリトライされません。[タスク → どの失敗が自動リトライされるか](/tasks#which-failures-retry-automatically-which-dont)を参照してください。
</Callout>
## いくつのタスクを並列に実行できるか
Multica は 2 つの層で同時実行数の制限を適用します。
- **デーモン層**: デフォルトで**同時タスク 20 個**(環境変数 `MULTICA_DAEMON_MAX_CONCURRENT_TASKS` で調整可能)
- **エージェント層**: デフォルトで**エージェントあたり同時タスク 6 個**(エージェントごとに設定)
2 つのうち厳しい方が適用されます。デーモンがすでにタスク 20 個を実行中なら、あるエージェントに余裕が残っていても新しいタスクは待機します。
タスクが `dispatched` に進めず `queued` で止まっている場合、通常はこの 2 つの制限のいずれかが飽和しています。
## デーモンのクラッシュ後、進行中だったタスクはどうなるか
デーモンがクラッシュしたり強制終了されたりすると、デーモンが取得していたタスクは `dispatched` または `running` 状態に残ります。次回の起動時、デーモンはサーバーに「これらのタスクはもう私のものではないので、失敗として表示してください」と伝えます。サーバーはそれを理由 `runtime_recovery` とともに `failed` に切り替えます。リトライ可能なソースについては、タスクが自動的に再度キューに入ります。
この手順がネットワークの問題で失敗しても、バックアップとして**30 秒ごと**にサーバー側のスキャンが回ります。45 秒以上ハートビートのないランタイムは欠落として表示され、その上のタスクも一緒に回収されます。
## 動かないエージェントのトラブルシューティング
「自分のエージェントが動かない」という問題に遭遇したら、まずこの 3 ステップのチェックリストを進めてください。
1. `multica daemon status` を実行し、デーモンが実行中でオンラインかを確認します
2. `multica daemon logs -f` を実行し、エラーがないかを確認します
3. Multica UI の**ランタイム**ページを開き、ランタイムが「オンライン」と表示されているかを確認します
より多くのシナリオは[トラブルシューティング](/troubleshooting)を参照してください。
## 次へ
- [タスク](/tasks) — デーモンがタスクを取得した後の全ライフサイクル
- [プロバイダー対照表](/providers) — 12 種の AI コーディングツールの機能の違い

View File

@@ -0,0 +1,99 @@
---
title: デスクトップアプリ
description: Multica Desktop とは何か、Web アプリとどう違うのか、そしてどんなときに使う価値があるのかを解説します。
---
import { Callout } from "fumadocs-ui/components/callout";
Multica Desktop は macOS、Windows、Linux 向けのネイティブデスクトップアプリです。設定された環境に対して、Web アプリと同じバックエンドに接続し、同じデータを表示します。Desktop はデフォルトで Multica Cloud を使用しますが、セルフホスト環境はローカルのランタイム設定ファイルで構成できます。Desktop はブラウザにはできないいくつかの機能も追加で提供します。**[ワークスペース](/workspaces)ごとの独立したタブグループ**、**[デーモン](/daemon-runtimes)の自動起動**、**ワンクリックアップグレード**です。
## Desktop か Web か — どちらを選ぶか
| | Web | Desktop |
|---|---|---|
| アクセス方法 | ブラウザで URL を開く | ネイティブアプリをインストール |
| 複数タブ | ブラウザ自体のタブ(ワークスペースの区別なし) | **ワークスペースごとに独立したタブグループ 1 つ** |
| デーモン | `multica daemon start` を自分で実行 | 起動時に**自動的に開始** |
| アップグレード | 更新すると最新版になる | アプリがバックグラウンドで確認し、次回起動時にインストール |
| ログイン後のデータ | 同一 | 同一 |
**Web を選ぶ**: 一度きりの利用、他人のマシンでの作業、何もインストールしたくないとき。
**Desktop を選ぶ**: 毎日の利用、複数のワークスペースを同時に扱うとき、デーモンを手動で管理したくないとき。
## 複数タブ: ワークスペースを切り替えるとどうなるか
Desktop は**参加しているすべてのワークスペース**ごとに独立したタブグループを保持します。ワークスペースを切り替えると、現在のワークスペースのタブが 1 つの単位として非表示になり、以前のワークスペースのタブは離れたときのまま復元されます — VSCode のマルチワークスペースの挙動や、Slack でワークスペースを切り替えるのに似ています。
例: ワークスペース A でイシューのタブを 3 つ開いた状態でワークスペース B に切り替えます。A のタブ 3 つは消え、B には B で最後に開いていたものが表示されます。再び A に切り替えると、その 3 つのタブが以前の状態そのままに戻ってきます。**タブはワークスペース間で決して漏れ出しません。**
ログアウトすると**すべてのワークスペースのタブ状態が消去される**ため、複数のユーザーでマシンを共有していてもデータが漏れることはありません。
## Desktop の自動更新の仕組み
起動時に Desktop は GitHub Releases でより新しいバージョンがないかを確認します。新しいバージョンが見つかると、
1. バックグラウンドで新しいバージョンを静かにダウンロードします。
2. 「準備完了 — 次回起動時にインストールされます」と通知します。
3. 終了時(または次回の再起動時)に、アプリが閉じる前に更新をインストールします。
4. 次回起動時に新しいバージョンが実行されます。
このプロセス全体は**作業中の内容を妨げません**。
<Callout type="warning">
**Windows では ARM64 と x64 は別々の更新チャンネルです** — 間違ったアーキテクチャをインストールすると更新が検出されません。ダウンロードする際は、マシンに合った `.exe` を選んでくださいARM ビルドには `arm64` のサフィックスが付いています)。
</Callout>
macOS ビルドは署名・公証されているため、初回起動時に「未確認の開発者」の警告は表示されません。Linux ビルドは `.AppImage` です — 自動更新は electron-updater に依存しており、一部のディストリビューションでは不安定になることがあります。**自動更新が動作しない場合は、新しいバージョンを手動でダウンロードして古いファイルを置き換えてください。**
## 単体の CLI とデーモンはまだ必要ですか?
**いいえ。** Desktop には同じ `multica` CLI バイナリが内蔵されており、起動時に独自のデーモンプロファイルを起動します(ターミナルから手動で実行しているデーモンとは隔離されます)。
すでに CLI をインストールして `multica daemon start` を手動で実行していても、Desktop はそのデーモンを乗っ取りません — 別のプロファイルで独自のデーモンを開始します。両者は**異なるランタイム**として登録され、UI では 2 つの独立したランタイムが表示されます。
ターミナルで CLI コマンドを実行したい場合、Desktop は特別な経路を提供しません — 別途インストールした CLI を使うか、アプリのリソースディレクトリ内 `resources/bin/multica` にあるバンドル済みのコピーを実行してください。
## ダウンロードとインストール
[Multica ダウンロードページ](https://multica.ai/download)から、使用するプラットフォームのインストーラーを入手してください。
| プラットフォーム | ファイル |
|---|---|
| macOS (Intel または Apple Silicon) | `.dmg` |
| Windows x64 | `.exe`(標準) |
| Windows ARM64 | `.exe``arm64` サフィックス付き) |
| Linux | `.AppImage` |
初回起動時にはログインが必要です — Web アプリと同じメール + 認証コードのフローです。ログインすると、Desktop はワークスペース一覧を自動的に同期します。
<Callout type="info">
**Desktop はデフォルトで Multica Cloud を使用しますが、ローカルの設定ファイルでセルフホスト環境を指すように設定できます。** アプリ内には依然として「セルフホストに接続」を選ぶピッカーはありません。Desktop はレンダラーが起動する前に `~/.multica/desktop.json` を読み込みます。ファイルがない場合は Cloud のデフォルト値を使用します。
最小構成のセルフホスト設定:
```json
{
"schemaVersion": 1,
"apiUrl": "https://api.your-domain"
}
```
`apiUrl` は必須で、`http` または `https` を使用する必要があります。Desktop は同一オリジン上で `wsUrl` を `/ws` として導出し(`https` なら `wss`、`http` なら `ws`、API オリジンから `appUrl` を導出します。デプロイ環境が異なるオリジンを使用する場合は明示的に設定してください。
```json
{
"schemaVersion": 1,
"apiUrl": "https://api.your-domain",
"wsUrl": "wss://api.your-domain/ws",
"appUrl": "https://your-domain"
}
```
`desktop.json` は存在するが無効な場合、Desktop は安全側に倒して動作を停止し、Cloud に静かにフォールバックする代わりにブロック型の設定エラーを表示します。開発ビルドの場合、`electron-vite dev` 中は依然として `VITE_API_URL` / `VITE_WS_URL` / `VITE_APP_URL` が優先されます。ランタイムでの Desktop セルフホスト構成は [issue #1371](https://github.com/multica-ai/multica/issues/1371) で実装されました。
</Callout>
## 次のステップ
- [Cloud Quickstart](/cloud-quickstart) — Desktop 向けの Cloud オンボーディングフロー
- [Self-Host Quickstart](/self-host-quickstart) — 自前のバックエンドを実行し、CLI または Desktop のランタイム設定で接続する
- [デーモンとランタイム](/daemon-runtimes) — デーモンの仕組みDesktop が代わりに起動してくれますが、動作は同じです)

View File

@@ -0,0 +1,302 @@
---
title: 規約
description: コードのネーミング、i18n 翻訳用語集、中国語ボイスガイドの単一の信頼できる情報源。
---
このページは、コードのネーミング、i18n 翻訳用語集、中国語ボイスガイドの単一の信頼できる情報源です。かつて `packages/views/locales/glossary.md` やあちこちに散らばったコメントにあった内容は、現在すべてここに集約されています。
Multica のコードを書く、翻訳を変更する、あるいは中国語の製品コピーを書く場合は、このページを参照してください。
---
## 1. コードのネーミング
### ルート
ワークスペース進入前のルート(ユーザーがワークスペースに入る前から存在するルート)は、必ず単一の単語または `/{noun}/{verb}` パターンを使用しなければなりません。
- ✅ `/login`, `/inbox`, `/workspaces/new`
- ❌ `/new-workspace`, `/create-team`, `/accept-invite`
ルート直下のハイフンで連結した単語のまとまりは、ユーザーが自分で選んだワークスペースの slug と衝突し、際限のない予約 slug の監査を強いることになります。名詞(`workspaces`)を予約しておけば、`/workspaces/*` のサブツリー全体が自動的に保護されます。
### ワークスペーススコープのルート
常に `/{slug}/{section}` の下に置きます — `/{slug}/issues`、`/{slug}/agents`、`/{slug}/settings`。ワークスペースのルーティングロジックを絶対に重複させず、共有コードではフレームワーク固有の link API ではなく `useNavigation().push()` を使用してください。
### パッケージとモジュール
モノレポは厳格なパッケージ境界を強制します。
| パッケージ | 依存可能 | 依存禁止 |
| --- | --- | --- |
| `packages/core` | アプリ固有でないもののみ | `react-dom`, `localStorage`, `process.env`, `next/*`, UI ライブラリ |
| `packages/ui` | なし | `@multica/core`, ビジネスロジック |
| `packages/views` | `core/`, `ui/` | `next/*`, `react-router-dom`, stores |
| `apps/web/platform/` | `next/*` | 他のアプリ |
| `apps/desktop/.../platform/` | `react-router-dom`, electron | 他のアプリ |
両方のアプリに同じロジックが現れる場合は、必ず共有パッケージに抽出しなければなりません。「ささいな」重複という例外はありません。
### ファイルとコンポーネント
- ファイル: `kebab-case.tsx` / `kebab-case.ts`(例: `agent-row-actions.tsx`
- コンポーネント: `PascalCase`(例: `AgentRowActions`
- フック: `useCamelCase`(例: `useWorkspaceId`
- テスト: `<file>.test.ts(x)` として同じ場所に配置
- ストアZustand: `<feature>-store.ts`、`use<Feature>Store` として export
### データベースGo + sqlc
- テーブル: `snake_case` の単数形(`user`, `workspace`, `agent_runtime`
- カラム: `snake_case``workspace_id`, `created_at`, `last_seen_at`
- 外部キー: `<table>_id`
- ブール値: `is_<state>` または `<state>_at`(状態変更にはタイムスタンプ形式を推奨)
- マイグレーションファイル: `NNN_descriptive_name.up.sql` + `.down.sql` — 常に双方向を提供する
### Go
- 標準の `gofmt` + `go vet`。例外なし。
- Handler ファイルはドメインを反映する: `agent.go`, `auth.go`, `runtime.go`
- テスト: `<file>_test.go` を同じ場所に配置
- handler での UUID パースは、ルートの `CLAUDE.md` のルールに従ってください — 境界の入力には `parseUUIDOrBadRequest`、信頼できる往復には `parseUUID`panic 版を使い、error を確認せずに `util.ParseUUID` を直接使用しないでください。
### TypeScript
- ネットワーク上の API レスポンスは `snake_case` で、api client が境界で `camelCase` に変換します。TS コード内部では**常に camelCase**。
- 型: `PascalCase``Issue`, `AgentRuntime``IPrefix` は禁止、`_t` サフィックスも禁止。
- 列挙: string literal union を推奨し、ランタイムで反復処理が必要な場合にのみ `enum` を使用。
- TanStack Query のキー: `<feature>/queries.ts` 内のファクトリ関数、例: `issueKeys.detail(id)`。
### イシューキー
すべてのイシューには `MUL-123` のような人が読めるキーがあります。ワークスペースの `issue_prefix`(大文字と数字、通常 3 文字、最大 10 文字)+ 連番です。ワークスペースの admin は Settings → General で接頭辞を変更できますが、変更すると既存のすべてのイシューが番号を振り直されるため、古い接頭辞が埋め込まれた外部参照PR タイトル、ブランチ名、ドキュメントやチャット内のリンク)は解決されなくなります。
### コード内のコメント
英語のみです。リポジトリは Go と TypeScript の両方でこれを強制します。コード内に中国語のコメントを見つけたら、それはバグなので置き換えてください。
### コミットメッセージ
Conventional 形式: `feat(scope)`, `fix(scope)`, `refactor(scope)`, `docs`, `test(scope)`, `chore(scope)`。意図ごとにまとめられたアトミックなコミット。
---
## 2. i18n 翻訳用語集
これは、すべての翻訳 PR が**必ず**守らなければならない用語集です。かつては `packages/views/locales/glossary.md` にありましたが、そのファイルは現在ここを指す stub です。
### 中核となる区別: エンティティ vs 概念
Multica の製品名詞は 2 つのカテゴリに分かれます。
- **エンティティEntity** — URL、データベースの row、API の型を持ちます。中国語のテキストでは**小文字の英語**で表記し、視覚的に型名のように読めて「これは Multica のシステムエンティティだ」というシグナルを与えます。
- **概念Concept** — 一般名詞であり、データベースのエンティティではありません。**完全に翻訳**し、中国語ユーザーが流れるテキストの中にギザギザの英語を見ないようにします。
このルールは `apps/docs/content/docs/*.zh.mdx` と整合しています — これらのドキュメントは事実上の中国語ボイス標準であり、20 ページ以上で実戦検証されています。
### エンティティ — 混合ルール(`issue` / `skill` / `task`
`issue` / `skill` / `task` は Multica の中核エンティティです。スキーマのカラム、API のフィールド、製品 UI のラベルがすべて英語です。中国語のテキストでは**混合ルール**に従い、何を使うかは単語がどこに現れるかによって変わります。
| 文脈 | 表記 | 例 |
| --- | --- | --- |
| **UI 文字列、状態名、コード参照** | 小文字の英語 | "排队中的 task"、"创建子 issue"、"为智能体注入 skill" |
| **ドキュメントのタイトル / セクション見出し** | Title-case の英語 **または** 中国語の用語 | "Issue 与 project"、"Skills"、"执行任务" |
| **長文ドキュメントの本文で、エンティティが文の主語になっている場合** | 中国語の用語、初出時に括弧内に英語 | "**执行任务**task是智能体每一次工作的单位" |
| **API / DB フィールド** | 常に `task` / `issue` / `skill` | `task_id`, `issue_status`, `skill_uuid` |
中国語の用語の参考:
- `task` ↔ `执行任务`(文脈が明確になれば `任务` に短縮)
- `issue` には定着した中国語訳がありません — 英語のまま;タイトルでは `Issue` のように大文字にできます
- `skill` には定着した中国語訳がありません — 英語のまま;タイトルでは `Skills` のように大文字にできます
**`issue` / `skill` / `task` が `project` / `autopilot` のように中国語へ強制的に翻訳されない理由**:
- **`issue` / `task`**: 開発チームは英語で会話します。中国語の候補("任务" — あいまいすぎて "工作" とほぼ同義;"工单" — IT チケットのニュアンス;"议题" — GitHub 風だが製品の感覚に合わない)はいずれも `issue` よりも読みづらくなります。**ただし**、長文ドキュメントの本文で小文字の `task` を 50 回繰り返すとリズムが崩れるため、本文では `执行任务` を許容しつつ、UI 文字列と状態名は小文字の英語のままにします。
- **`skill`**: 定着した中国語の用語がない Multica 固有の概念です。
- **`project` → "项目"**: 定着した主流の中国語の単語です。Feishu / Tower / Teambition / PingCode / GitHub Projects — すべての中国語製品がこれを翻訳します。中国語の文脈で `project` をそのまま残す製品はありません。
- **`autopilot` → "自动化"**: 中国語で "autopilot" は Tesla の "自动驾驶" を連想させ、この機能が行うことスケジュールに従ってタスクを実行すると合いません。Notion も Feishu も "自动化" を使っており、それが業界の合意です。
### 翻訳しない — ブランドと頭字語
| カテゴリ | 用語 |
| --- | --- |
| ブランド | **Multica**, GitHub, Slack, Google, Anthropic, OpenAI, Claude, Codex, Cursor, Linear, Jira |
| 頭字語 | API, CLI, URL, SDK, OAuth, JWT, SSO, WebSocket, HTTP, JSON, YAML, SQL |
### 完全に翻訳する — 概念
| English | Chinese |
| --- | --- |
| Workspace | **工作区** |
| Agent | **智能体** |
| Project | **项目** |
| Autopilot | **自动化** |
| Daemon | **守护进程** |
| Runtime | **运行时** |
| Inbox | **收件箱** |
| Comment | **评论** |
| Reply | **回复** |
| Notifications | **通知** |
| Member | **成员** |
| Label | **标签** |
| Settings | **设置** |
| Onboarding | **上手引导** |
### 完全に翻訳する — 一般的な UI 用語
| English | Chinese |
| --- | --- |
| Invite / Invitation | 邀请 |
| Search | 搜索 |
| Email | 邮箱 (label) / 邮件 (action) |
| Password | 密码 |
| Sign in / Log in | 登录 |
| Sign up | 注册 |
| Sign out / Log out | 退出登录 |
| Save / Cancel / Delete | 保存 / 取消 / 删除 |
| Confirm / Continue / Back | 确认 / 继续 / 返回 |
| Edit / New / Create / Add | 编辑 / 新建 / 创建 / 添加 |
| Remove / Send / Open / Close | 移除 / 发送 / 打开 / 关闭 |
| Preview / Download / Upload | 预览 / 下载 / 上传 |
| Done / Loading... | 完成 / 加载中... |
| Profile / Account / Appearance | 个人资料 / 账号 / 外观 |
| Theme / Language | 主题 / 语言 |
| Light / Dark / System | 浅色 / 深色 / 跟随系统 |
| Active / Archived | 活跃 (or 启用) / 已归档 |
| Status / Priority | 状态 / 优先级 |
| Assignee / Reporter | 负责人 / 报告人 |
| Description / Title | 描述 / 标题 |
| Date / Time | 日期 / 时间 |
| Today / Yesterday / Tomorrow | 今天 / 昨天 / 明天 |
| Empty / Failed / Success | 空 / 失败 / 成功 |
| Error / Warning | 错误 / 警告 |
### ロールと状態の列挙型(小文字の英語、翻訳しない)
これらはスキーマレベルの識別子です。中国語の文脈でも小文字の英語で表記します。
- ロール: `owner` / `admin` / `member`
- イシューの状態: `backlog` / `todo` / `in_progress` / `in_review` / `done` / `blocked` / `cancelled`
UI ではこれらの値を英語で表示します(必要に応じて `code-style` で囲む)。
- "你需要 owner 权限"
- "已切换到 in_progress"
### 単語の組み合わせルール
英語の単語(エンティティ / ブランド / 頭字語)と周囲の中国語の間には、常に**単一の空白**を入れます。
- "Create new issue" → "新建 issue"
- "Assign to agent" → "分配给智能体"
- "Configure runtime" → "配置运行时"
- "Stop daemon" → "停止守护进程"
### 複数形と数
i18next は `_one` / `_other` を使います。中国語には文法的な数がないため、`_other` のみを埋めます。
```json
// en/issues.json
{
"issue_count_one": "{{count}} issue",
"issue_count_other": "{{count}} issues"
}
// zh-Hans/issues.json
{
"issue_count_other": "{{count}} 个 issue"
}
```
一般的な数の形式:
- `{{count}} issues` → `{{count}} 个 issue`
- `{{count}} agents` → `{{count}} 个智能体`
- `{{count}} workspaces` → `{{count}} 个工作区`
- `{{count}} comments` → `{{count}} 条评论`
- `{{count}} members` → `{{count}} 位成员`
- `{{count}} skills` → `{{count}} 个 skill`
### 補間
`{{var}}` を使います。中国語の翻訳では、自然な文章の流れのために順序を並べ替えてもかまいません。
```json
// en
{ "welcome_message": "Welcome back, {{name}}!" }
// zh-Hans
{ "welcome_message": "欢迎回来,{{name}}" }
```
### 翻訳キーのネーミング
3 階層のネスト: `feature.component.action`。
```json
{
"feature_or_component": {
"subcomponent_or_section": {
"action_or_label": "..."
}
}
}
```
例:
- `issues.toolbar.batch_update_success`
- `issues.detail.comment_form.placeholder`
- `inbox.empty.title`
- `settings.preferences.language.title`
### Web 専用 / Desktop 専用のコピー
- 共有コピー: namespace JSON の最上位
- Web 専用: `web` セクション
- Desktop 専用: `desktop` セクション
正式な例は `auth.json` を参照してください(`web` セクションに `prefer_desktop` / `desktop_handoff.*` が含まれます)。
---
## 3. 中国語のボイスとスタイル
### 句読点
- 中国語では全角の句読点を使用: `,。:;!?`
- 引用符: 英語の原文に合わせて、まっすぐな二重引用符 `"..."` を使用。`「」` や丸い引用符は使わないでください。
- 省略記号: 単一文字の `…` ではなく、3 つの点 `...`。英語の原文に合わせてください。
- 中国語と英語の混在: 英語の単語の両側にそれぞれ単一の空白(単語の組み合わせルールを参照)。
### スタイルの原則
- **簡潔かつ直接的に。** 翻訳調を避ける: "对于 X 来说"、"作为 X"、"我们的"。
- **エラーメッセージ**: 穏やかだが明確に。"无法保存修改" は "保存修改失败了!" よりも優れています。
- **ボタン**: 動詞を先頭に、2〜4 文字。"取消"、"保存修改"、"立即同步"。
- **ツールチップ**: 完結した短い文。"复制链接到剪贴板"。
- **プレースホルダー**: 例の形式。"输入 issue 标题..."。
### 迷ったときに参照する場所
用語集が特定の用語を扱っていない場合は、次を参照してください。
1. `apps/docs/content/docs/*.zh.mdx` — 事実上の中国語ボイス標準、一貫した翻訳が 20 ページ以上
2. `packages/views/locales/zh-Hans/auth.json` と `editor.json` — JSON 構造 + selector API パターン
3. `packages/views/auth/login-page.tsx` — コンポーネントレベルの selector API 呼び出し箇所
4. `packages/views/settings/components/preferences-tab.tsx` — 言語切り替えの参考
---
## このページを更新するとき
ここのルールを変更した場合は、次も併せて行ってください。
1. 関連する locale JSON / CLAUDE.md / ドキュメントページに適用する
2. PR の説明に変更点を記録し、レビュアーが下流の一括対応を確認できるようにする
このページが契約です。他の何ものもこれを上書きできません。

View File

@@ -0,0 +1,4 @@
{
"title": "開発者",
"pages": ["conventions"]
}

View File

@@ -0,0 +1,224 @@
---
title: 環境変数
description: セルフホストの Multica サーバーを実行するための環境変数の完全な一覧です。
---
import { Callout } from "fumadocs-ui/components/callout";
セルフホストの Multica [サーバー](/self-host-quickstart)は、起動時に環境変数から設定を読み込みます — データベース、サインイン、メール、ストレージ、サインアップ許可リストはすべてここにあります。このページでは、すべての変数を用途別にグループ化しています。各セクションでは、**設定しないと何が起きるか**、そして**プロダクションで必ず設定すべきものはどれか**を明確に説明します。auth 関連の変数を実際にどう設定するかについては、[サインインとサインアップの設定](/auth-setup)を参照してください。
## コアサーバー変数
デプロイ前に必ず検討すべきコア変数です — 一部はサーバーを起動できるようにするデフォルト値を持っていますが、プロダクションでは必須項目を明示的に設定すべきです。
| 変数 | デフォルト | プロダクションで必須? |
|---|---|---|
| `DATABASE_URL` | `postgres://multica:multica@localhost:5432/multica?sslmode=disable` | **はい** |
| `PORT` | `8080` | いいえ(ポートを変更する場合を除く) |
| `JWT_SECRET` | `multica-dev-secret-change-in-production` | **はい**(デフォルトは安全ではありません) |
| `APP_ENV` | 空 | **はい**`production` である必要があります) |
| `FRONTEND_ORIGIN` | 空 | **はい**(セルフホストは自身のドメインを設定する必要があります) |
| `MULTICA_DEV_VERIFICATION_CODE` | 空 | いいえ(プロダクションでは必ず空のままにしてください) |
<Callout type="warning">
**プロダクションでは `MULTICA_DEV_VERIFICATION_CODE` を空のままにしてください。** 固定のローカルテストコードはデフォルトで無効になっていますが、`MULTICA_DEV_VERIFICATION_CODE=888888` で有効にすると、`APP_ENV` が production 以外の間は、コードを要求できる誰もがその固定値でサインインできてしまいます。このショートカットは `APP_ENV=production` のときには無視されます。
</Callout>
### データベース接続プール
| 変数 | デフォルト | 説明 |
|---|---|---|
| `DATABASE_MAX_CONNS` | `25` | pgxpool の最大接続数。デーモンは頻繁に3 秒ごとに)ポーリングして接続を使用するため、規模の大きいデプロイではより高い値が必要になる場合があります |
| `DATABASE_MIN_CONNS` | `5` | 最小アイドル接続数 |
**設定しない場合**、上記の値が使われます — 以前プロダクションでプール枯渇を引き起こした pgx 組み込みの 4/NumCPU デフォルトでは**ありません**。
## メール設定
Multica は 2 つの配信バックエンドをサポートします — クラウドデプロイ向けの [Resend](https://resend.com/) と、内部 / オンプレミスネットワーク向けの SMTP relay です。両方が設定されている場合は `SMTP_HOST` が `RESEND_API_KEY` より優先されます。
### Resend
| 変数 | デフォルト | 説明 |
|---|---|---|
| `RESEND_API_KEY` | 空 | Resend API key |
| `RESEND_FROM_EMAIL` | `noreply@multica.ai` | 送信元アドレスResend アカウントで検証済みのドメインである必要があり、SMTP を使用する場合も `From:` ヘッダーとして再利用されます) |
### SMTP relay
| 変数 | デフォルト | 説明 |
|---|---|---|
| `SMTP_HOST` | 空 | SMTP relay のホスト名。これを設定すると SMTP モードが有効になり、Resend を上書きします |
| `SMTP_PORT` | `25` | SMTP ポート。STARTTLS サブミッションには `587` を使用してください。**ポート 465SMTPS / 暗黙的 TLSはサポートされていません** |
| `SMTP_USERNAME` | 空 | SMTP ユーザー名。認証なしの relay の場合は空のままにしてください |
| `SMTP_PASSWORD` | 空 | SMTP パスワード |
| `SMTP_TLS_INSECURE` | `false` | TLS 証明書の検証をスキップするには `true` に設定(プライベート CA / 自己署名証明書のみ) |
サーバーが STARTTLS を通知すると自動的にアップグレードされます。dial タイムアウトは 10 秒で、SMTP セッション全体には 30 秒のデッドラインがあるため、ブラックホール化した relay が auth ハンドラーをハングさせることはできません。
**どちらも設定していない場合の動作**: サーバーはエラーを出しませんが、送信されるはずだったすべてのメール(検証コード、招待リンク)は**サーバーの stdout にのみ記録されます**。ローカル開発には便利です — サーバーログからコードをコピーして使ってください。**プロダクションでこれを設定し忘れると、静かなブラックホールが生まれ**、ユーザーはメールをまったく受け取れず、エラーも一切表面化しません。
## Google OAuth 設定
任意です。メール + 検証コードのみを使用する場合は設定しないままにし、サインインページに「Sign in with Google」を追加する場合は設定してください。
| 変数 | デフォルト | 説明 |
|---|---|---|
| `GOOGLE_CLIENT_ID` | 空 | Google Cloud OAuth client ID |
| `GOOGLE_CLIENT_SECRET` | 空 | Google Cloud OAuth secret |
| `GOOGLE_REDIRECT_URI` | `http://localhost:3000/auth/callback` | OAuth コールバック URLセルフホスト: 自身のフロントエンドドメインに置き換えてください) |
**ランタイムで適用されます**: フロントエンドはこれらの設定をランタイムに `/api/config` 経由で読み込むため、**変更してもフロントエンドのリビルドや再デプロイは不要です** — サーバーを再起動すれば適用されます。
完全なセットアップGoogle Cloud Console の手順を含む)は[サインインとサインアップの設定](/auth-setup#google-oauth-configuration)にあります。
## ファイルストレージ設定
Multica はユーザーがアップロードした添付ファイル(コメント内の画像やファイル)を保存します。**S3 が推奨されます**。S3 が設定されていない場合はローカルディスクにフォールバックします。
### S3 / S3 互換ストレージ
| 変数 | デフォルト | 説明 |
|---|---|---|
| `S3_BUCKET` | 空 | **バケット名のみ**(例: `my-bucket`)。`.s3.<region>.amazonaws.com` サフィックスは含め**ないでください** — サーバーが `S3_BUCKET` + `S3_REGION` から公開ホストを構築します。これを設定すると S3 ストレージが有効になります |
| `S3_REGION` | `us-west-2` | AWS リージョン。バケットの実際のリージョンと一致する必要があります — SDK 署名と公開 URL の構築の両方に使われます |
| `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` | 空 | 静的な認証情報。両方を設定しない場合は AWS SDK のデフォルト認証情報チェーンIAM role / 環境認証情報)が使われます |
| `AWS_ENDPOINT_URL` | 空 | カスタムの S3 互換エンドポイント(例: [MinIO](https://min.io/))。これを設定すると path-style URL に切り替わります |
**`S3_BUCKET` を設定しない場合**: サーバーは起動時に `"S3_BUCKET not set, cloud upload disabled"` をログに記録し、すべてのアップロードはローカルディスクにフォールバックします。
**公開 URL** は次の優先順位で構築されます。
1. `CLOUDFRONT_DOMAIN` が設定されている場合は `https://<CLOUDFRONT_DOMAIN>/<key>`。
2. `AWS_ENDPOINT_URL` が設定されている場合は `<AWS_ENDPOINT_URL>/<S3_BUCKET>/<key>`path-style
3. `https://<S3_BUCKET>.s3.<S3_REGION>.amazonaws.com/<key>`virtual-hosted-style。`S3_BUCKET` にドットが含まれる場合、AWS が発行するワイルドカード TLS 証明書がドットを含むバケットホストを検証できないため、サーバーは `https://s3.<S3_REGION>.amazonaws.com/<S3_BUCKET>/<key>`path-styleにフォールバックします。
### ローカルディスクS3 が設定されていない場合)
| 変数 | デフォルト | 説明 |
|---|---|---|
| `LOCAL_UPLOAD_DIR` | `./data/uploads` | ローカルストレージのディレクトリ |
| `LOCAL_UPLOAD_BASE_URL` | 空(相対パスを返します) | 公開 base URL — 設定しないとフロントエンドが添付ファイルの完全な URL を解決できません |
### CloudFront任意
S3 の前段に CloudFront を置く場合、3 つの変数が適用されます: `CLOUDFRONT_DOMAIN`、`CLOUDFRONT_KEY_PAIR_ID`、`CLOUDFRONT_PRIVATE_KEY`(または Secrets Manager から読み込むには `CLOUDFRONT_PRIVATE_KEY_SECRET`。CloudFront を使わない場合はスキップしてください — S3 設定とは競合しません。
### Cookie ドメイン
| 変数 | デフォルト | 説明 |
|---|---|---|
| `COOKIE_DOMAIN` | 空 | セッション cookie のスコープ |
- **空**: cookie は訪問した正確なホストでのみ有効です(単一ホストのデプロイに適切)
- **`.example.com` に設定**: cookie がサブドメイン間で共有されます(そのため `app.example.com` と `api.example.com` がサインインセッションを共有します)
- 警告: IP アドレスにはできません(ブラウザは無視します)
## 誰がサインアップできるかを制限する
3 つの許可リストの層が優先順位に従って組み合わされます。**いずれか 1 つの層でも空でない値に設定されると、一致しないメールは拒否されます** — `ALLOW_SIGNUP=true` でさえこれを上書きできません。
| 変数 | デフォルト | 説明 |
|---|---|---|
| `ALLOWED_EMAILS` | 空 | 明示的なメール許可リスト(カンマ区切り)。空でない場合、リストにあるメールのみがサインアップできます |
| `ALLOWED_EMAIL_DOMAINS` | 空 | ドメイン許可リスト(カンマ区切り)。空でない場合、リストにあるドメインのみがサインアップできます |
| `ALLOW_SIGNUP` | `true` | サインアップのマスタースイッチ。サインアップを完全に無効にするには `false` に設定 |
**直感に反する部分**: `ALLOWED_EMAIL_DOMAINS=company.io` + `ALLOW_SIGNUP=true` は「company.io または全員を許可」という意味では**なく**、**company.io のみを許可**という意味です。許可リストの層は AND セマンティクスです — 完全な決定木は[サインインとサインアップの設定 → サインアップ許可リスト](/auth-setup#restricting-who-can-sign-up)にあります。
**招待フロー自体はサインアップ許可リストをチェックしません** — ただし、招待された人は招待を承諾する前に依然として**サインイン**できる必要があります。すでに Multica アカウントを持っている場合(例: 別のワークスペースから)、許可リストの影響を受けずに直接承諾できます。**一度もサインアップしたことがない場合**、サインインの最初のステップ(検証コードの要求)は依然として許可リストのチェックを通過し、`ALLOW_SIGNUP=false` や `ALLOWED_EMAILS` / `ALLOWED_EMAIL_DOMAINS` によって拒否されたメールは**サインアップを完了できず、したがって招待を承諾できません**。
## ワークスペース作成をロックダウンする
`ALLOW_SIGNUP=false` は新しいアカウントをブロックしますが、すでにサインイン済みのユーザーが `POST /api/workspaces` 経由で別のワークスペースを作成することは**ブロックしません**。すべてのイシュー、リポジトリ、エージェントがプラットフォーム管理者に見えなければならないセルフホストインスタンスでは、そのギャップを塞ぐために `DISABLE_WORKSPACE_CREATION=true` を設定してください。
| 変数 | デフォルト | 説明 |
|---|---|---|
| `DISABLE_WORKSPACE_CREATION` | `false` | `true` の場合、`POST /api/workspaces` へのすべての呼び出しが `403 workspace creation is disabled for this instance` を返します。Web UI は `/api/config` 経由ですべての「ワークスペース作成」要素を非表示にします。役割 / owner の例外はありません — このゲートはインスタンス単位で全体に適用されます |
推奨されるブートストラップ手順:
1. `DISABLE_WORKSPACE_CREATION` を設定しないまま(デフォルト)インスタンスを起動します。
2. 管理者としてサインインし、共有ワークスペースを作成します。
3. `DISABLE_WORKSPACE_CREATION=true` を設定してバックエンドを再起動します。この時点から、ユーザーは招待によってのみ参加できます。
招待されたユーザーが最初の検証コードでサインアップを完了できるよう `ALLOW_SIGNUP=true` を維持したい場合は、`DISABLE_WORKSPACE_CREATION=true` を `ALLOWED_EMAIL_DOMAINS` / `ALLOWED_EMAILS` と組み合わせて、どのアドレスがサインアップできるかの範囲を指定してください。`ALLOW_SIGNUP=false` を設定すると、保留中の招待対象者がアカウントを作成すること自体も追加でブロックされます — すべてのメンバーがすでに Multica アカウントを持っているインスタンスでのみ有用です。
## レート制限(任意の Redis
公開 auth エンドポイント — `/auth/send-code`、`/auth/verify-code`、`/auth/google` — の前段には、IP ごとの固定ウィンドウのレート制限があります。リミッターは Redis によって支えられています。`REDIS_URL` を設定しない場合、ミドルウェアは **no-op**fail-openになり、バックエンドは起動時に `rate limiting disabled: REDIS_URL not configured` をログに記録します。
| 変数 | デフォルト | 説明 |
|---|---|---|
| `REDIS_URL` | 空 | Redis 接続 URL例: `redis://localhost:6379/0`)。設定しないと auth エンドポイントのレート制限が無効になります。同じ Redis はリアルタイムハブの fan-out、PAT キャッシュ、デーモントークンキャッシュでも使われます — 設定しない場合はすべてインメモリ / 直接 DB モードにフォールバックします |
| `RATE_LIMIT_AUTH` | `5` | `/auth/send-code` および `/auth/google` に対する IP あたり毎分の最大リクエスト数 |
| `RATE_LIMIT_AUTH_VERIFY` | `20` | `/auth/verify-code` に対する IP あたり毎分の最大リクエスト数 |
| `RATE_LIMIT_TRUSTED_PROXIES` | 空 | リミッターがその `X-Forwarded-For` ヘッダーを信頼することを許可する、カンマ区切りの CIDR。空デフォルトは **XFF を決して信頼しない**ことを意味します — リミッターは直接接続の `RemoteAddr` のみを使用します |
リクエストが制限を超えると、サーバーは `429 Too Many Requests`、`Retry-After: 60`、そして本文 `{"error":"too many requests"}` で応答します。
<Callout type="warning">
**リバースプロキシの背後では `RATE_LIMIT_TRUSTED_PROXIES` を必ず設定する必要があります。** そうしないと、バックエンドの観点ではすべての実際のユーザーがプロキシの IP を共有することになり、デプロイ全体が 1 つのバケットに入り、`/auth/send-code` がサイト全体で毎分 5 リクエストになってしまいます。一般的な値: 同一ホストの Caddy / Nginx には `127.0.0.1/32,::1/128`、Cloudflare / ALB / CloudFront には該当 CDN が公開している IP 範囲。`RemoteAddr` がこれらの CIDR のいずれかに含まれる IP のみが、`X-Forwarded-For` を使ってクライアントを識別できます。
</Callout>
この独立した `RATE_LIMIT_TRUSTED_PROXIES` は、オートパイロット webhook リミッター(`/api/webhooks/autopilots/{token}`)を制御する `MULTICA_TRUSTED_PROXIES` とは**異なります**。各リミッターは自身のリストをパースするため、プロキシの背後にあるデプロイは両方を設定すべきです。
## デーモンのチューニングパラメータ
デーモンはユーザーのローカルマシン上で実行され、その設定もローカル環境変数から読み込まれます。一般的なものは次のとおりです。
| 変数 | デフォルト | 説明 |
|---|---|---|
| `MULTICA_SERVER_URL` | `ws://localhost:8080/ws` | サーバーアドレス(セルフホスト: 自身のドメインに置き換えてください) |
| `MULTICA_DAEMON_HEARTBEAT_INTERVAL` | `15s` | ハートビート間隔 |
| `MULTICA_DAEMON_POLL_INTERVAL` | `3s` | タスクのポーリング間隔 |
| `MULTICA_DAEMON_MAX_CONCURRENT_TASKS` | `20` | 最大同時タスク数 |
| `MULTICA_<PROVIDER>_PATH` | CLI 名に一致 | 各 AI コーディングツールの実行ファイルへのパス(例: `MULTICA_CLAUDE_PATH` |
| `MULTICA_<PROVIDER>_MODEL` | 空 | 各 AI コーディングツールのデフォルトモデル |
各パラメータがデーモンの動作にどう影響するかの完全な説明は、[デーモンとランタイム](/daemon-runtimes)を参照してください。
## フロントエンドのアクセス制御
| 変数 | デフォルト | 説明 |
|---|---|---|
| `FRONTEND_ORIGIN` | 空 | フロントエンドアドレス。招待メールのリンク、CORS 許可リスト、cookie ドメインはすべてこの値から派生します。設定しない場合、招待メールのリンクはホスト型ドメイン `https://app.multica.ai` にフォールバックします — セルフホストはこれを明示的に設定する必要があります |
| `CORS_ALLOWED_ORIGINS` | 空 | 追加で許可する CORS originカンマ区切り |
| `ALLOWED_ORIGINS` | 空 | WebSocket 専用の origin 許可リスト(カンマ区切り)。設定しない場合、フォールバック順序は `CORS_ALLOWED_ORIGINS` → `FRONTEND_ORIGIN` → `localhost:3000/5173/5174` です |
<Callout type="warning">
**`FRONTEND_ORIGIN` を設定しないと 2 つの静かな失敗が発生します**: (1) 招待メールのリンクが `https://app.multica.ai`(ホスト型ドメイン)を指し、クリックしてもユーザーがセルフホストインスタンスに戻ってこない。(2) WebSocket の Origin チェックが `localhost:3000 / 5173 / 5174` にフォールバックするため、プロダクションデプロイのすべての WebSocket 接続が拒否され、フロントエンドが「リアルタイム更新を受け取れない」ように見える。
</Callout>
## GitHub 連携
[GitHub PR ↔ イシュー連携](/github-integration)には 2 つの変数が必要です。設定で Connect GitHub を有効にし、受信 webhook を受け付けるには両方を設定してください。
| 変数 | デフォルト | 説明 |
|---|---|---|
| `GITHUB_APP_SLUG` | 空 | GitHub App の slug`https://github.com/apps/<slug>` の末尾部分)。設定 → GitHub のインストールボタン URL を構成します |
| `GITHUB_WEBHOOK_SECRET` | 空 | GitHub App に設定した Webhook secret。すべての `pull_request` / `installation` delivery の HMAC-SHA256 検証に使われ、setup コールバックの state token の HMAC キーとしても使われます |
**どちらかが設定されていない場合の動作:**
- 設定 → GitHub の `Connect GitHub` が**無効**になり、admin に「not configured」というヒントを表示します。
- `/api/webhooks/github` エンドポイントは **`503 github webhooks not configured`** を返します — Multica はすべての署名を有効として扱うのではなく、secret なしではイベント処理を拒否します。
**注:** `GITHUB_WEBHOOK_SECRET` はインストールフローの state token の署名キーとして再利用されるため、運用者は secret を 1 つだけ管理すればよいです。これは GitHub App の *Client* secret では**ありません** — Client secret は OAuth 関連であり、この連携では使われません。完全な手順は [GitHub 連携 → セルフホストのセットアップ](/github-integration#self-host-setup)を参照してください。
## 使用量分析
デフォルトでは、サーバーは Multica の公式 PostHog インスタンスにレポートします。オプトアウトするには `ANALYTICS_DISABLED=true` を設定してください。
| 変数 | デフォルト | 説明 |
|---|---|---|
| `ANALYTICS_DISABLED` | `false` | バックエンド分析を完全に無効にするには `true` に設定 |
| `POSTHOG_API_KEY` | 組み込みのデフォルトキー | 自身の PostHog インスタンスを指す場合に設定 |
| `POSTHOG_HOST` | `https://us.i.posthog.com` | PostHog をセルフホストする場合は自身のホストに変更 |
## 次へ
- [サインインとサインアップの設定](/auth-setup) — 上記の auth 関連変数を実際にどう設定するか、そして落とし穴がどこにあるか
- [GitHub 連携](/github-integration) — `GITHUB_APP_SLUG` / `GITHUB_WEBHOOK_SECRET` を支える GitHub App をどうセットアップするか
- [トラブルシューティング](/troubleshooting) — よくある設定ミスの症状と対処法
- [デーモンとランタイム](/daemon-runtimes) — `MULTICA_DAEMON_*` パラメータが実際に何をするか

View File

@@ -0,0 +1,183 @@
---
title: GitHub 連携
description: GitHub App を一度連携すれば、ブランチ・タイトル・本文にイシュー識別子を含む PR が該当イシューに自動で紐づきます。そして PR をマージするとイシューが Done に移動します。
---
import { Callout } from "fumadocs-ui/components/callout";
**設定 → GitHub** で GitHub アカウントまたは組織を一度だけ連携してください。その後は、ブランチ名・タイトル・本文にイシュー識別子(例: `MUL-123`)を含むあらゆる pull request が該当する[イシュー](/issues)に**自動で紐づき**、イシューサイドバーの **Pull requests** に表示され、PR がマージされるとイシューが **Done** に移動します。
イシューごとの設定はありません。フロー全体が識別子で駆動されます。
## 連携が行うこと
| 場所 | 動作 |
|---|---|
| **設定 → GitHub** | ワークスペースの admin には、マスタートグル、**Connect GitHub** ボタン、機能スイッチPR サイドバー、Co-authored-by、自動紐づけを備えた GitHub タブが表示されます。インストール後は GitHub タブに戻ります。 |
| **イシューサイドバー → Pull requests** | このイシューに自動で紐づいたすべての PR が、タイトル、リポジトリ、状態(`Open` / `Draft` / `Merged` / `Closed`)、作成者とともに表示されます。行をクリックすると GitHub の該当 PR に移動します。 |
| **Webhookバックグラウンド** | すべての `pull_request` イベントで、Multica は PR 行を upsert し、PR からイシュー識別子をスキャンして、紐づけ行を(再)構築します。冪等性があり、同じ delivery を再送しても変化はありません。 |
| **マージ時のステータス自動変更** | PR が `merged` に遷移すると、まだ `Done` でも `Cancelled` でもない、紐づいたすべてのイシューが `Done` に移動します。ステータス変更は source `github_pr_merged` でタイムラインに記録されます。 |
ミラーリングされるのは PR 自体のみです。コミット、オープンな PR のないブランチ ref、CI チェックの状態はモデル化され**ません**。この連携は意図的に狭く設計されています。
## 識別子のマッチング方法
Webhook は次の順序で 3 つのフィールドから識別子を抽出します: **PR head ブランチ**、**PR タイトル**、**PR 本文**。マッチャーは次のとおりです。
- 大文字小文字を区別しません — `mul-123`、`MUL-123`、`Mul-123` はすべてマッチします。
- 境界があります — 左側の `\b` と右側の数字アンカーにより、`v1.2-3` のようなバージョン番号やメール形式の文字列を誤って拾わないようにしています。
- ワークスペーススコープに限定されます — そのワークスペース固有の[イシュー prefix](/workspaces)にのみマッチします。prefix が `MUL` のワークスペースでは、整数が別のイシューと一致しても `FOO-1` は無視されます。
- 重複が除去されます — 本文に `MUL-1, MUL-1` と並べても、イシューは一度だけ紐づきます。
1 つの PR で**複数のイシュー**を参照できます。`Closes MUL-1, MUL-2` は PR を両方のイシューに紐づけ、マージすると両方が `Done` に進みます。
## マージ時の Done 自動変更ルール
PR の `merged` フィールドが `true` に切り替わると、紐づいたすべてのイシューが評価されます。
| イシューの現在のステータス | 結果 |
|---|---|
| `done` | 変化なし(すでに終了状態)。 |
| `cancelled` | **変化なし** — cancelled はユーザーが作業を明示的に放棄したことを意味するため、連携はこのシグナルを上書きしません。 |
| それ以外すべて(`todo`、`in_progress`、`in_review`、`blocked`、`backlog` | `done` に移動。 |
PR をマージ**せずに**クローズした場合は、PR カードの状態が `Closed` に更新されるだけです。紐づいたイシューはそのまま維持されます — マージせずにクローズすることが何を意味するかはユーザーが決めるからです。
<Callout type="info">
この動作はタイムライン上で `system` アクターに帰属します。イシューの購読者は、人がステータスを移動したときと同じように、ステータス変更に関するインボックス通知を受け取ります。
</Callout>
## 自動で紐づかないもの
- **コミットメッセージ内の識別子** — ブランチ / タイトル / 本文のみがスキャンされます。`MUL-123: fix login` というタイトルのコミットは、同じ文字列が PR タイトルや本文にも現れない限り自動では紐づきません。
- **PR コメント内の識別子** — PR 自体のメタデータのみがスキャンされ、後から付いた GitHub コメントは無視されます。
- **App がインストールされていないリポジトリの PR** — App がなければ、Multica は webhook をまったく受け取りません。
- **PR をイシューに手動で紐づける** — まだこのための UI はありません。チームの慣習で識別子を Multica が読まない場所に置いている場合は、PR タイトルや本文に追加してください。
## 連携解除
**設定 → GitHub** にはインストール一覧はありません — 既存のインストールは GitHub から直接管理します。
- **GitHub から** — `https://github.com/settings/installations`(個人)または `https://github.com/organizations/<org>/settings/installations`(組織)で Multica GitHub App をアンインストールします。Multica は `installation.deleted` webhook を受け取ってリアルタイムで行を削除し、開いている Settings タブはリロードなしで更新されます。
- **Multica 内部からの連携解除は admin 専用です** — GitHub タブの連携解除コントロールは、admin 以外のユーザーには非表示です。マスター GitHub スイッチがオフでも利用可能なままなので、admin はワンクリックで機能を無効化した後でも、古いインストールを取り消せます。
連携解除後も、ミラーリングされた PR 行はデータベースに残り、過去のイシューサイドバーで何が紐づいていたかを引き続き表示しますが、そのインストールから新たに入ってくる webhook イベントは受理されなくなります。
## 権限と可視性
- **連携 / 連携解除**にはワークスペースの **owner または admin** が必要です。member にはカードの説明は見えますが、Connect ボタンは見えません。
- イシューの **Pull requests** サイドバーは、そのイシューを閲覧できる誰にでも表示されます — イシュー詳細の他の部分と同じ権限です。
- GitHub App は pull request とメタデータへの**読み取り専用**アクセスを要求します。Multica はコミット、コメント、ステータスチェックを GitHub に書き戻すことはありません。
## セルフホストのセットアップ
Multica Cloud で Multica を実行している場合、連携はすでに構成済みです — このセクションは飛ばしてください。
セルフホストの場合は、GitHub App を 1 つ作成し、サーバーを指すように設定し、環境変数を 2 つ設定します。フロー全体は以下のとおりです。
### 1. GitHub App を作成する
次のいずれかにアクセスしてください。
- 個人アカウント → `https://github.com/settings/apps/new`
- 組織 → `https://github.com/organizations/<org>/settings/apps/new`
次を入力します。
| フィールド | 値 |
|---|---|
| **GitHub App name** | 見分けやすい名前、例: `Multica` または `Multica (staging)`。 |
| **Homepage URL** | Multica フロントエンド、例: `https://multica.example.com`。 |
| **Callback URL** | 空欄のままにしてください — Multica は OAuth ユーザー ID を使用しません。 |
| **Setup URL** | `https://<api-host>/api/github/setup`。**「Redirect on update」をチェックしてください。** |
| **Webhook → Active** | 有効。 |
| **Webhook URL** | `https://<api-host>/api/webhooks/github`。 |
| **Webhook secret** | 長いランダム文字列を生成してください(例: `openssl rand -hex 32`)。手順 2 で同じ値を Multica の env に貼り付けます。 |
| **Permissions → Repository → Pull requests** | **Read-only**。 |
| **Permissions → Repository → Metadata** | Read-only必須。 |
| **Subscribe to events** | **Pull request** をチェックしてください。 |
| **Where can this GitHub App be installed?** | お好みで。単一組織のセットアップなら `Only on this account` で十分です。 |
**Create GitHub App** の後、App の詳細ページから 2 つのことを控えておいてください。
- 上部の **public link** — その末尾が slug です。`https://github.com/apps/multica-acme` → slug = `multica-acme`。
- 先ほど生成した **webhook secret**(後で GitHub から読み戻すことはできません — 今すぐ保存してください)。
<Callout type="warning">
**Webhook secret ≠ Client secret。** App 設定ページには両方のフィールドが並んで配置されています。**Webhook secret** は `pull_request` の payload に署名する値で、Multica が必要とするものです。**Client secret** は OAuth 用で、この連携では使用しません。この 2 つを混同すると、すべての webhook delivery で紛らわしい `401 invalid signature` が発生します。
</Callout>
### 2. 環境変数を設定する
API サーバーで:
```dotenv
GITHUB_APP_SLUG=multica-acme
GITHUB_WEBHOOK_SECRET=<the webhook secret you generated>
```
両方の変数が必須です。どちらかが欠けていると:
- Settings の `Connect GitHub` が**無効**になり、「not configured」のヒントが表示されます。
- `/api/webhooks/github` エンドポイントが **`503 github webhooks not configured`** を返します — Multica は secret なしでイベントを処理することを拒否し、すべての署名を黙って有効として扱うことはありません。
`FRONTEND_ORIGIN` も設定されている必要がありますどのプロダクションのセルフホストでもすでに設定されています。インストール後、setup コールバックがユーザーを `<FRONTEND_ORIGIN>/settings?tab=github` に戻します。
env 変数を設定した後は API を再起動してください。
### 3. マイグレーションを実行する
この連携はテーブルをマイグレーション `079_github_integration` で提供します。古いデプロイをアップグレードする場合:
```bash
make migrate-up
```
3 つのテーブルが作成されます: `github_installation`、`github_pull_request`、`issue_pull_request`。これらはワークスペースとともに cascade-delete されるため、ワークスペースを削除すると自動的にクリーンアップされます。
### 4. UI から連携する
Multica で:
1. owner または admin 権限で **設定 → GitHub** を開きます。
2. **Connect GitHub** をクリックします。GitHub が新しいタブで開きます。
3. アクセスを付与するリポジトリを選び、**Install** します。
4. GitHub が `<api-host>/api/github/setup` にリダイレクトしてインストールを記録し、`<FRONTEND_ORIGIN>/settings?tab=github&github_connected=1` に戻します。
その後、ブランチ / タイトル / 本文にイシュー識別子を含む PR を開いてみてください — 数秒以内に、そのイシューの詳細ページに Pull requests ブロックが表示されます。
### 5. curl プローブで検証する
インストール後に GitHub の **Recent Deliveries** ページで `401 invalid signature` が報告される場合、両側の secret が異なっています。どちらが間違っているかを最も速く突き止める方法は、GitHub を迂回することです。
```bash
SECRET="<the value you put in GITHUB_WEBHOOK_SECRET>"
BODY='{"zen":"test"}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')
curl -i -X POST https://<api-host>/api/webhooks/github \
-H "X-Hub-Signature-256: sha256=$SIG" \
-H "X-GitHub-Event: ping" \
-H "Content-Type: application/json" \
-d "$BODY"
```
| HTTP ステータス | 意味 | 解決方法 |
|---|---|---|
| `200` `{"ok":"pong"}` | サーバーがロードした secret が `$SECRET` と一致します。不一致は GitHub 側にあります。 | App → Webhook secret を編集 → **同じ値を貼り付け** → **Save changes**(保存せずにフィールドの外をクリックすると古い secret が維持されます)。再送してください。 |
| `401 invalid signature` | サーバーがロードした secret が思っている値で**ありません**。 | env 変数が実行中のプロセスに反映されたか確認してください(例: `kubectl exec` → `echo -n "$GITHUB_WEBHOOK_SECRET" \| wc -c`)。再デプロイしてください。 |
| `503 github webhooks not configured` | プロセスで `GITHUB_WEBHOOK_SECRET` が空です。 | env 変数を設定し、API を再起動してください。 |
## 制限事項
現時点で知っておくべき、いくつかの粗い部分があります。
- **まだ手動の紐づけ UI はありません** — PR を紐づける唯一の方法は、ブランチ、タイトル、本文に識別子を置くことです。
- **CI / チェック状態はありません** — PR 自体のみがミラーリングされます。ビルド状態、レビューコメント、レビュアーは Multica には表示されません。
- マージ → Done ルールに対する**ワークスペースレベルの設定はありません** — 固定のデフォルトです(`cancelled` でない限り `merged → done`)。ワークスペースでカスタマイズできるマッピングは将来の追加予定です。
- **1 つのイシューに複数の PR が紐づく場合、マージは保守的です** — 2 つの PR がどちらも `MUL-123` を参照していて最初の 1 つがマージされると、イシューはただちに `Done` に移動します。進める前に紐づいたすべての PR が解決されるのを待つ後続の変更が進行中です。
## 次に
- [イシュー](/issues) — PR から参照されるイシュー識別子(`MUL-123`
- [ワークスペース](/workspaces) — ワークスペース固有のイシュー prefix を設定する場所
- [環境変数](/environment-variables) — 上記の GitHub 変数を含む env の完全なリファレンス

View File

@@ -0,0 +1,54 @@
---
title: Multica の仕組み
description: 3 つのコア構成要素(サーバー / デーモン / AI コーディングツール)がどのように連携してエージェントの作業を実行するかを説明します。
---
import { ArchitectureDiagram } from "@/components/architecture-diagram";
Multica は**分散型**プラットフォームです。あなたが目にする Web インターフェースは表に見えている部分にすぎず、実際の作業は 3 つの構成要素が処理します。**Multica サーバー**はデータを保持します([ワークスペース](/workspaces)、[イシュー](/issues)、[メンバー](/members-roles)、[タスク](/tasks)キューなど)。**[デーモン](/daemon-runtimes)**はあなた自身のマシンで実行され、タスクを取得して AI コーディングツールを駆動します。そして **[AI コーディングツール](/providers)**Claude Code、Codex、その他のローカル CLIが、実際にコードを書く構成要素です。これが Multica と Linear や Jira との最大の違いです。**[エージェント](/agents)は当社のサーバーではなく、あなたのマシンで実行されます。**
## 3 つのコア構成要素
<ArchitectureDiagram />
- **Multica サーバー** — あなたが目にするワークスペース、イシュー一覧、コメントスレッドは、すべてここのデータベースに保存されます。また、あなたと同僚の間でリアルタイム更新をプッシュする WebSocket ハブでもあります。エージェントのタスクは**実行しません**。
- **デーモン** — Multica CLI の一部であり、あなた自身のマシンで実行されます。起動時にローカルにインストールされた AI コーディングツールを検出し、サーバーに登録したうえで、3 秒ごとにタスクをポーリングし、15 秒ごとにハートビートを送信し始めます。
- **AI コーディングツール** — 次の 12 種類のうちの 1 つ(または複数を並列で): [Antigravity](/providers#antigravity)、[Claude Code](/providers#claude-code)、[Codex](/providers#codex)、[Cursor](/providers#cursor)、[Copilot](/providers#copilot)、[Gemini](/providers#gemini)、[Hermes](/providers#hermes)、[Kimi](/providers#kimi)、[Kiro CLI](/providers#kiro-cli)、[OpenCode](/providers#opencode)、[OpenClaw](/providers#openclaw)、[Pi](/providers#pi)。デーモンがタスクを取得した後は、これらのツールを使って実際の作業を行います。
ツールチェーンがローカルに留まるため、**あなたの API キー、コードディレクトリ、認可されたツール**は、あなたのマシン上でのみ使用されます。Multica サーバーはそのいずれも目にすることはありません。これはセルフホストでも Cloud でも同じように適用されます。
## タスクのライフサイクル
最も一般的なシナリオである、イシューをエージェントに割り当てる場合を見てみましょう。
1. あなたが Web UI で割り当てをクリックします。ブラウザが Multica サーバーへ HTTP リクエストを送ります。
2. サーバーがそのイシューの担当者をエージェントに設定し、同時にタスクキューに状態 `queued` の実行タスクを作成します。
3. あなたのマシンにあるデーモンが、次のポーリング3 秒以内)でタスクを取得します。タスクの状態が `dispatched` に変わります。
4. デーモンがローカルに隔離された作業ディレクトリを作成し、該当する AI コーディングツールを呼び出します。タスクの状態が `running` に変わります。
5. AI がローカルでコードを書き、テストを実行し、コメントをサーバーへ投稿します。
6. 実行が終了します。デーモンが結果(成功 / 失敗)をサーバーに報告し、タスクの状態が `completed` または `failed` に変わります。あなたは Web UI で進捗の更新をリアルタイムにWebSocket を通じて)確認します。
詳しい動作の仕組みは、[デーモンとランタイム](/daemon-runtimes)および[タスク](/tasks)を参照してください。
## エージェントを動かす 4 つの方法
「イシューの割り当て」だけではありません。Multica にはコラボレーションのスタイルごとに 1 つずつ、4 つのトリガーがあります。
| 方法 | 一般的なシナリオ | ドキュメント |
|---|---|---|
| **イシューの割り当て** | 最も一般的な方法。イシューをエージェントに割り当てると、自分で作業を始めます | [イシューの割り当て](/assigning-issues) |
| **コメントでエージェントを @メンション** | 「これちょっと見てくれる?」— 担当者や状態を変えず、コメント 1 つで実行を開始します | [エージェントのメンション](/mentioning-agents) |
| **ダイレクトチャット** | イシューに紐づかない独立した会話 — 質問したり、イシューの下書きを作らせたりします | [チャット](/chat) |
| **オートパイロット(スケジュール)** | 常時の指示 — 「毎週月曜の朝にスタンドアップのまとめをして」のようなもの | [オートパイロット](/autopilots) |
## ランタイム: どこで実行され、ツールは何個か
**ランタイム**とは「デーモン × 1 つの AI コーディングツール」の組み合わせです。あるマシンのデーモンに Claude Code と Codex の両方がインストールされており、2 つのワークスペースに参加している場合、Multica は 4 つの独立したランタイム(ワークスペース 2 個 × ツール 2 個)を登録します。
現在は**ローカルデーモン**のランタイムモデルのみがサポートされています。クラウドランタイム(自分のマシンを起動しておく必要がない方式)は**近日提供予定**で、現在はウェイトリストの登録のみを受け付けています。[ダウンロード](https://multica.ai/download)ページでお申し込みください。
## 次のステップ
- [Cloud Quickstart](/cloud-quickstart) — 5 分で Multica Cloud に接続する
- [Self-Host Quickstart](/self-host-quickstart) — 自前のバックエンドを実行する
- [デーモンとランタイム](/daemon-runtimes) — アーキテクチャが依存する構成要素を深掘りする

View File

@@ -0,0 +1,65 @@
---
title: インボックスと購読
description: Multica がいつ通知を送るか、そして関心のないイシューをミュートする方法。
---
import { Callout } from "fumadocs-ui/components/callout";
インボックスは Multica があなたを**割り込む**場所です。あなたに割り当てられた[イシュー](/issues)、[`@` メンション](/comments)、そしてあなたが購読しているイシューのアクティビティがすべてここに届きます。
あなたは**購読**と**購読解除**を通じて、どのイシューのアクティビティが自分に届くかを制御します。
## インボックスに表示されるもの
次のイベントがあなたのインボックスに通知を届けます。
- **イシューの割り当て / 割り当て解除 / 再割り当て** — あなたが新しい担当者(または以前の担当者)になると通知を受け取ります
- **あなたが購読しているイシューのステータス、優先度、期限の変更**
- **あなたが購読しているイシューの新しいコメント**
- **あなたがコメントで `@` メンションされた** — 購読しているかどうかに関係なく届きます
- **誰かがあなたのイシューやコメントにリアクションした**
- **あなたが割り当てたエージェントの[タスク](/tasks)が失敗した**
## `@all` はワークスペース全体に通知します
`@all` は特殊な対象です。ワークスペースの**すべてのメンバー**に通知をプッシュします。
<Callout type="warning">
**`@all` は控えめに使ってください。** 50 人規模のワークスペースでは、`@all` コメント 1 つで瞬時に 50 件のインボックス通知が生成されます。日常的な議論ではなく、重大な事案(プロダクション障害、マイルストーンの告知)にのみ使ってください。
</Callout>
## エージェントは通知を受け取りません
エージェントは**決して**インボックス通知を受け取りません。担当者や作成者であるときも、コメントで `@` メンションされたときも受け取りません。
これはバグではありません。エージェントはインボックスを読みません。エージェントは[**即時トリガー**](/assigning-issues)方式で動作します。イシューを割り当てたり、コメントでエージェントを `@` メンションしたりすると、ただちにそのエージェント向けのタスクが始まります。インボックスは人間のためのリマインダーの仕組みであり、エージェントにとっては何の意味も持ちません。
## 購読のルール
次の 4 つの状況で、あなたはイシューに**自動購読**されます。
- あなたがそのイシューを**作成**した場合
- あなたがそのイシューに**割り当て**られた場合
- あなたがそのイシューに**コメント**した場合
- あなたがそのイシューまたはそのコメントで **`@` メンション**された場合
自動購読は一度だけ起こります。作成者であり同時にメンション対象でもあっても、2 回購読されることはありません。
<Callout type="warning">
**再割り当ては自動で購読を解除しません。** あなたが以前は担当者だったのに交代させられた場合でも、**そのイシューの更新を引き続き受け取ります** — 自動購読がデータベースにそのまま残っているためです。
通知を受け取らないようにするには、イシューを開いて手動で購読を解除してください。
</Callout>
また、どのイシュー(無関係なイシューでも)でも**手動で購読**したり、どの自動購読でも**手動で購読解除**したりできます。UI ではイシューページの右パネルを使い、CLI では `multica issue subscriber add/remove` を使ってください。
## 子イシューのステータス変更は親イシューに伝播します
子イシューの**ステータス**が変更されると、親イシューの購読者も通知を受け取ります。たとえ子イシューを購読していなくても同様です。
これは**ステータスにのみ**適用されます。子イシューのコメント、優先度、期限の変更は親イシューに伝播**しません**。
## 次へ
- [コメントとメンション](/comments) — `@` メンションの仕組みと注意点
- [エージェントにイシューを割り当てる](/assigning-issues) — エージェントがトリガーされる仕組み(そしてエージェントがインボックスを読まない理由)

View File

@@ -0,0 +1,50 @@
---
title: ようこそ
description: 人間と AI エージェントが同じワークスペースで一緒に働く、タスクコラボレーションプラットフォーム。
---
import { Callout } from "fumadocs-ui/components/callout";
Multica は、人間と AI [エージェント](/agents)が同じ[ワークスペース](/workspaces)で一緒に働くタスクコラボレーションプラットフォームです。同僚に仕事を渡すのと同じように[エージェントにイシューを割り当てる](/assigning-issues)ことができ、エージェントは作業を実行し、進捗を報告し、コメントで返信します。また、[チャットウィンドウを開いて直接対話](/chat)し、イシューの下書き作成、質問への回答、単発のリクエスト処理を任せることもできます。
このページでは、エージェントがどこで実行されるか、そして Multica を使い始めるさまざまな方法を説明します。
## エージェントが実行される場所
エージェントは Multica のサーバー上でタスクを実行**しません**。現在 Multica は 1 つのランタイムモデルをサポートしています。
- **ローカル[デーモン](/daemon-runtimes)** — 自分のマシンで `multica daemon` を実行すると、デーモンがローカルにインストールされた [AI コーディングツール](/providers)を駆動します。現在 12 種類が標準で組み込まれています: [Antigravity](/providers#antigravity)、[Claude Code](/providers#claude-code)、[Codex](/providers#codex)、[Cursor](/providers#cursor)、[Copilot](/providers#copilot)、[Gemini](/providers#gemini)、[Hermes](/providers#hermes)、[Kimi](/providers#kimi)、[Kiro CLI](/providers#kiro-cli)、[OpenCode](/providers#opencode)、[OpenClaw](/providers#openclaw)、[Pi](/providers#pi)。API キー、ツールチェーン、コードディレクトリはすべて自分のマシンに留まります。
<Callout type="info">
**クラウドランタイムが近日提供予定です。** 現在はウェイトリストのみで運用されています。提供が開始されればローカルデーモンは不要になり、エージェントのタスクは Multica Cloud 上で直接実行されます。[ダウンロード](https://multica.ai/download)ページで登録すると通知を受け取れます。
</Callout>
## Multica を使う 3 つの方法
最初の 2 つのカードは**バックエンドの選択肢**で、Multica サーバーがどこで実行されるかを決めます。3 つ目は**クライアントの選択肢**で、どのインターフェースを使うかを決めます。デスクトップアプリはどちらのバックエンドとも組み合わせて使えます。
<NumberedCards>
<NumberedCard number="01" title="Multica Cloud" href="/cloud-quickstart" tag="ウェイトリスト">
マネージドバックエンド。CLI をインストールし、ローカルでデーモンを実行してから、Multica がホスティングするサーバーに接続します。約 5 分で完了します。
</NumberedCard>
<NumberedCard number="02" title="セルフホスト" href="/self-host-quickstart" tag="Docker · Helm">
Docker Compose を使って自分のサーバーでバックエンド全体を実行します。データベース、サーバー、ストレージがすべて自分のインフラ上に配置されます。
</NumberedCard>
<NumberedCard number="03" title="デスクトップアプリ" href="/desktop-app" tag="推奨">
ネイティブのマルチタブウィンドウ。CLI が内蔵されており、起動時にデーモンを自動的に開始します。インストール後に実行するコマンドは一切ありません。Multica Cloud またはセルフホストのバックエンドに接続します。
</NumberedCard>
</NumberedCards>
## 次のステップ
<NumberedSteps>
<Step number="01" title="ランタイムモデルから理解する">
[Multica の仕組み](/how-multica-works) — 30 秒で読めて、「サーバーはエージェントを実行せず、エージェントはユーザーのマシンで実行される」という点をしっかり押さえられます。
</Step>
<Step number="02" title="始める方法を選ぶ">
上記の 3 つから 1 つを選びましょう。ほとんどの方は[デスクトップアプリ](/desktop-app)から始めます。CLI のセットアップが不要で、5 分で動き出します。
</Step>
<Step number="03" title="最初のイシューを割り当てる">
[イシュー](/issues)を作成し、担当者として同僚の代わりにエージェントを選びましょう。エージェントが結果を届けるのを待つだけです。
</Step>
</NumberedSteps>

View File

@@ -0,0 +1,180 @@
---
title: エージェントランタイムをインストールする
description: Multica はあなたのマシンにインストールされている AI コーディングツールを駆動します。このページでは、デーモンがそれらを検出できるように、サポートされている 12 種のツールをそれぞれインストールする方法を説明します。
---
import { Callout } from "fumadocs-ui/components/callout";
Multica における**ランタイム**とは、あなたのマシンのデーモンと、デーモンが `PATH` で見つけた AI コーディングツール 1 つが組になったものです。オンボーディングの「ランタイムを接続」ステップで **No supported tools detected** と表示される場合、それはデーモンが `PATH` をスキャンしたものの、駆動方法を知っている 12 種のツールのいずれも見つけられなかったことを意味します。以下のツールのいずれか(または複数)をインストールしてから、そのステップに戻って再スキャンしてください — 数秒以内にランタイムが表示されます。
このページは次のドキュメントのインストール側の補完ドキュメントです。
- [デーモンとランタイム](/daemon-runtimes) — 検出の仕組み
- [AI コーディングツールマトリクス](/providers) — 各ツールができることとできないことセッション再開、MCP、モデル選択
<Callout type="info">
Multica サーバーがあなたの API キーやツール自体を見ることは決してありません。以下のすべて — インストール、認証、モデルアクセス — はあなたのローカルマシン上に存在します。何かが失敗する場合、それはほぼ常にローカルの問題です。
</Callout>
## 始める前に
以下の**すべての**ツールに 2 つの前提条件が適用されます。
1. **Multica デーモンが実行中である必要があります。** [Multica CLI](/cli) をインストールした後に `multica daemon start` を実行するか、デーモンを自動的に起動する [Multica デスクトップアプリ](/desktop-app)を使用してください。デーモンが実行されていなければ、ツールを検出する主体がありません。
2. **ツールのバイナリが `PATH` で到達可能である必要があります。** デーモンは各ツールを名前で呼び出して実行します(各セクションの**デーモンが探す名前**の列を参照)。ターミナルで `which <name>` で見つからなければ、デーモンも見つけられません。インストール後は、新しいターミナルを開く(またはデーモンを再起動する)ことで、新しい `PATH` エントリが反映されるようにしてください。
ツールをインストールした後は、デーモンを再起動してください。
```bash
multica daemon restart
```
または、デスクトップアプリではアプリを再起動するだけで構いません。デーモンは起動するたびに `PATH` を再スキャンします。
## サポートされている 12 種のツール
おおよそ利用者の多い順に並べています。すでに認証情報を持っているものを選んで使ってください — 12 種すべてをインストールする必要はありません。
### Claude Code (Anthropic)
最も完全な連携です。セッション再開が動作し、MCP が動作し、**11 種のうちエージェントの `mcp_config` フィールドを実際に読み込む唯一のツール**です(詳しくは[マトリクス](/providers#mcp-configuration-only-claude-code-actually-reads-it)を参照)。
| | |
|---|---|
| デーモンが探す名前 | `claude` |
| インストール | [claude.com/claude-code](https://www.claude.com/claude-code) の公式ガイドに従ってください。標準的な方法は npm パッケージ `@anthropic-ai/claude-code` ですNode.js 18+ が必要)。 |
| 認証 | `claude` を一度実行して CLI 内のログイン手順に従うか、`ANTHROPIC_API_KEY` を設定してください。 |
| 備考 | 新しいユーザーに最初に推奨する選択肢です。 |
### Codex (OpenAI)
よりきめ細かい承認ゲートを備えた JSON-RPC 2.0 のトランスポートです。**セッション再開のコードは存在しますが、現在は到達できません** — 再開が必要な場合は Claude Code か ACP 系列のいずれかを選んでください。
| | |
|---|---|
| デーモンが探す名前 | `codex` |
| インストール | [github.com/openai/codex](https://github.com/openai/codex) の公式ガイドに従ってください。標準的な方法は npm パッケージ `@openai/codex` です。 |
| 認証 | `codex login`(ブラウザベース)または `OPENAI_API_KEY`。 |
### Cursor (Anysphere)
Cursor エディタに対応する CLI です。**セッション再開は動作しません** — Cursor の CLI がセッション id を返さないため、再開時に渡す値は常に無効です。
| | |
|---|---|
| デーモンが探す名前 | `cursor-agent` |
| インストール | [Cursor エディタ](https://cursor.com/)をインストールしてから、[docs.cursor.com](https://docs.cursor.com/) のドキュメントに従って CLI をインストールしてください。バイナリ名は `cursor` ではなく `cursor-agent` です。 |
| 認証 | Cursor エディタを通じてログインすると、CLI がそのセッションを再利用します。 |
### GitHub Copilot
モデルのルーティングはあなたの GitHub アカウントのエンタイトルメントentitlementを通じて行われます — ツールが自分でモデルを選ぶのではなく、どのモデルを受け取るかは GitHub が決めます。
| | |
|---|---|
| デーモンが探す名前 | `copilot` |
| インストール | GitHub の CLI ドキュメント [github.com/github/copilot-cli](https://github.com/github/copilot-cli) を参照してください。 |
| 認証 | CLI を通じたブラウザベースの GitHub ログイン。 |
| 備考 | ログインしているアカウントに有効な GitHub Copilot サブスクリプションが必要です。 |
### Gemini (Google)
Gemini 2.5 および 3 シリーズをサポートします。セッション再開と MCP はありません — 単発のタスクに適しています。
| | |
|---|---|
| デーモンが探す名前 | `gemini` |
| インストール | [github.com/google-gemini/gemini-cli](https://github.com/google-gemini/gemini-cli) の公式ガイドに従ってください。標準的な方法は npm パッケージ `@google/gemini-cli` です。 |
| 認証 | `gemini` を実行すると Google アカウントのログインを求められるか、`GEMINI_API_KEY` を設定してください。 |
### OpenCode (SST)
オープンソースの CLI エージェントです。独自の設定ファイルから利用可能なモデルを動的に発見します — 自分のモデルカタログを持ち込みたいユーザーによく合います。
| | |
|---|---|
| デーモンが探す名前 | `opencode` |
| インストール | [opencode.ai](https://opencode.ai/) の公式ガイド、または GitHub リポジトリ [github.com/sst/opencode](https://github.com/sst/opencode) に従ってください。一般的な方法はインストールスクリプトまたは npm パッケージです。 |
| 認証 | OpenCode のドキュメントに従ってモデルプロバイダーAnthropic、OpenAI など)を構成してください。 |
### Kiro CLI (Amazon)
ACP-over-stdio のトランスポートです。セッション再開は ACP `session/load` を通じて動作し、スキルは `.kiro/skills/` にコピーされます。
| | |
|---|---|
| デーモンが探す名前 | `kiro-cli` |
| インストール | [kiro.dev](https://kiro.dev/) の Kiro ドキュメントを参照してください。バイナリ名は `kiro` ではなく `kiro-cli` です。 |
| 認証 | AWS アカウントベースで、Kiro 独自のオンボーディングに従ってください。 |
### Kimi (Moonshot)
ACP プロトコルのエージェントで、主に中国市場を対象としています。スキルは `.kimi/skills/` 配下に置かれます(ネイティブ発見)。
| | |
|---|---|
| デーモンが探す名前 | `kimi` |
| インストール | [github.com/MoonshotAI/kimi-cli](https://github.com/MoonshotAI/kimi-cli) の公式ガイドに従ってください。 |
| 認証 | Moonshot API キーで、ベンダーのドキュメントに従って構成します。 |
### Hermes (Nous Research)
ACP プロトコルのエージェントですKimi とトランスポートを共有)。セッション再開が動作します。スキル注入のパスは汎用の `.agent_context/skills/` にフォールバックします — 依存する前に、スキルが正しくロードされているか確認してください。
| | |
|---|---|
| デーモンが探す名前 | `hermes` |
| インストール | 最新の CLI ディストリビューションは Nous Research のリポジトリ [github.com/NousResearch](https://github.com/NousResearch) を参照してください。 |
| 認証 | ベンダーのドキュメントに従います。 |
### OpenClaw
オープンソースの CLI エージェントオーケストレーターです。**モデルはエージェント層にバインドされます**`openclaw agents add --model` — タスクごとに上書きすることはできず、Multica から `--model` や `--system-prompt` を渡すこともできません。
| | |
|---|---|
| デーモンが探す名前 | `openclaw` |
| インストール | プロジェクト [github.com/openclaw-org/openclaw](https://github.com/openclaw-org/openclaw) を参照してください(コミュニティによる保守)。 |
| 認証 | OpenClaw のドキュメントに従って、基盤となるモデルプロバイダーを構成してください。 |
### Pi (Inflection AI)
ミニマルです。**セッション再開の方式が特殊です** — 再開 id が文字列 id ではなく、ディスク上のセッションファイルへのパスです。
| | |
|---|---|
| デーモンが探す名前 | `pi` |
| インストール | Inflection の CLI ドキュメント [pi.ai](https://pi.ai/) を参照してください。 |
| 認証 | ベンダーのドキュメントに従います。 |
### Antigravity (Google)
Google の Antigravity CLI`agy`です。Google の Antigravity サービスと組になり、Gemini ベースのモデルを実行します。セッション再開は `--conversation <id>` を通じて動作し、デーモンが CLI のログファイルからこれをキャプチャします。モデル選択は Antigravity CLI 自体の内部で管理されます — Multica はこのプロバイダーに対してエージェントごとのモデルピッカーを無効にします。スキルは `.agents/skills/` に書き込まれますCLI が Gemini CLI のワークスペーススキルレイアウトを継承します — [Antigravity ドキュメント](https://antigravity.google/docs/gcli-migration)を参照)。
| | |
|---|---|
| デーモンが探す名前 | `agy` |
| インストール | [antigravity.google/docs/cli-overview](https://antigravity.google/docs/cli-overview) の公式ガイドに従ってください。CLI はあらかじめビルドされて提供されます — `agy install` を一度実行して PATH とシェルエイリアスを設定してください。 |
| 認証 | `agy` を対話的に一度実行して Google アカウントのログインを完了するか、Antigravity デスクトップアプリを通じてログインしてください — CLI は GUI が書き込んだ keyring エントリを再利用します。 |
| 備考 | CLI は構造化されたイベントストリームではなく、stdout に通常のアシスタントテキストを出力します。途中の「I will run X」の行と最終的な応答の両方がテキストとして Multica に中継されます。 |
## インストールした後
1. **バイナリが `PATH` にあるか確認してください。** 新しいターミナルを開いて `which <name>`(例: `which claude`、`which cursor-agent`、`which kiro-cli`、`which agy`)を実行してください。パスが出力されれば、デーモンが見つけられます。何も出力されない場合は、まずシェルの `PATH` を修正してください(典型的な原因は、リロードされていないシェルごとの rc ファイルです)。
2. **デーモンを再起動してください。** `multica daemon restart` を実行するか、デスクトップアプリを再起動してください。デーモンは起動時にのみ `PATH` をスキャンします。
3. **ランタイムページを確認してください。** Multica UI の**ランタイム**ページに、`(ワークスペース × ツール)` の組み合わせごとに 1 行ずつ表示されるはずです。行に「offline」と表示される場合は、[デーモンとランタイム → ランタイムがオフラインと表示されるとき](/daemon-runtimes#when-a-runtime-is-marked-offline)を参照してください。
4. **オンボーディングに戻ってください。** 「ランタイムを接続」ステップはポーリングを行い、数秒以内に新しいランタイムを認識します — リロードは不要です。
## トラブルシューティング
- **`which` はバイナリを見つけるのにデーモンは見つけません。** デーモンが古い `PATH` で起動されています。再起動してください。
- **バイナリは存在するのに起動に失敗します。** ターミナルからツール自体の `--version` や `--help` を一度実行してください — ここで発生する失敗のほとんどは、認証の欠落、期限切れのトークン、または Node.js / ランタイムの不一致です。
- **ランタイムページに行は表示されるのに、タスクがすぐに失敗します。** タスクをトリガーしながら `multica daemon logs -f` を確認してください。デーモンはツール自体のエラー出力をそのまま表示します。
より広範な症状については、[トラブルシューティングガイド](/troubleshooting)を参照してください。
## 次に
- [デーモンとランタイム](/daemon-runtimes) — 検出、ハートビート、オフライン処理の仕組み
- [AI コーディングツールマトリクス](/providers) — ツールが接続された後の機能差
- [エージェントの作成と構成](/agents-create) — エージェントに使うツールを選び、タスクの実行を開始する

View File

@@ -0,0 +1,79 @@
---
title: イシューとプロジェクト
description: 人またはエージェントに割り当てられる、Multica の中心的な作業単位。
---
import { Callout } from "fumadocs-ui/components/callout";
イシューは Multica における独立した作業単位です — バグ、新機能、対応が必要なことなら何でも構いません。すべてのイシューには **タイトル**、**説明**(Markdown 対応)、**ステータス**、**優先度**、**担当者** があり、任意で **プロジェクト** に属することもできます。Linear や Jira を使ったことがあれば、同じ形だと分かるはずです。
**Multica の最大の特徴は、イシューの担当者が人でもエージェントでもよいという点です** — [エージェント](/agents) — ここから始めましょう。
## エージェントにイシューを割り当てる
イシューをエージェントに[割り当てる](/assigning-issues)と、その作業をエージェントに引き渡すことになります。エージェントは **自動的に開始します** — 数秒以内に実行を始め、コメントで進捗を報告し、完了するとステータスを done に切り替えます。同僚に仕事を渡すのとの唯一の違いは、エージェントはオフラインにならず、リマインドも要らず、24時間365日いつでも対応できることです。
<Callout type="info">
エージェントのアイデンティティ、設定、実行場所については [エージェント](/agents) を参照してください。
</Callout>
非公開エージェントをイシューに割り当てられるのは、ワークスペースの owner と admin だけです。ロールの権限については [メンバーとロール](/members-roles) を参照してください。
## ステータス
Multica には7つのステータスがあります。**どのステータスからでも、ほかのどのステータスへも直接移動できます** — Multica はワークフローを強制せず、`backlog` から `done` へ一気に飛んでも止めません。
| ステータス | 意味 |
|---|---|
| `backlog` | まだ予定に入っていない |
| `todo` | 予定が決まり、着手できる |
| `in_progress` | 作業中 |
| `in_review` | レビュー待ち |
| `done` | 完了 |
| `blocked` | 外部要因で止まっている |
| `cancelled` | キャンセル済み |
イシューがエージェントに割り当てられると、エージェントは自動的にステータスを `backlog` / `todo` から `in_progress` に移し、完了すると `done` にします。いつでも手動で変更することもできます。
## 優先度
優先度には5段階があり、デフォルトのイシュー一覧の並び替えに使われます:
| 優先度 | 用途 |
|---|---|
| `No priority` | まだ決めていない(デフォルト) |
| `Urgent` | 緊急 |
| `High` | 高 |
| `Medium` | 中 |
| `Low` | 低 |
## イシュー番号
すべてのイシューには、ワークスペース内で一意の番号が `<prefix>-<digits>` 形式で付きます — 例えば `MUL-123` のように。番号は作成時にシステムが付与し、**決して変わりません**。[ワークスペース → イシュー番号](/workspaces#issue-numbers) を参照してください。
## コメント
イシューの下のコメントスレッドは、協業が行われる場所です — コメントに返信し、人やエージェントを `@` でメンションし、リアクションを追加できます。
コメントでエージェントを `@` でメンションすると **自動的にトリガーされます** — これは「割り当て」と並ぶ、エージェントを起動する2つ目の方法です。[コメントとメンション](/comments) と [コメントでエージェントをメンションする](/mentioning-agents) を参照してください。
## イシューを削除する
<Callout type="warning">
イシューを削除すると、その下のすべてのコメント、リアクション、添付ファイルと、キューに入っているエージェントのタスクが **即座に** 消えます(実行中のタスクはキャンセルされます)。**元に戻せません。**
単にイシューを見えないようにしたいだけなら、**ステータスを `cancelled` に変更するほうが削除より安全です** — データは残り、後から戻すことができます。
</Callout>
## プロジェクト
プロジェクトは、複数のイシューをまとめるコンテナです。イシューは最大1つのプロジェクトに属するか、どのプロジェクトにも属さないかのいずれかです。
プロジェクトには独自の **リード** がいます — **イシューの担当者と同じように、リードも人でもエージェントでもかまいません**。
プロジェクトを削除しても **その中のイシューは削除されません**: それらのイシューはプロジェクトから切り離されるだけで、ワークスペースにそのまま残ります。
## 次に読む
- [コメントとメンション](/comments) — イシューの下で協業する
- [エージェント](/agents) — 「エージェントに割り当てる」が実際にどう動くのかを理解する

View File

@@ -0,0 +1,60 @@
---
title: メンバーと役割
description: ワークスペースの3つの役割owner、admin、memberがそれぞれ何をできるのか、そして人をどのように招待するのかを説明します。
---
import { Callout } from "fumadocs-ui/components/callout";
[ワークスペース](/workspaces)に属するすべての人は役割を持ち、その役割によって何ができるかが決まります。Multica には3つの役割があります。**owner**(ワークスペースのオーナー)、**admin**、**member** です。[イシュー](/issues)の作成、[コメント](/comments)の作成、[エージェント](/agents)の利用といった日常的な作業のほとんどは、3つの役割すべてで利用できます。**違いはチーム管理の領域に集中しています。**
## 権限の一覧
以下の表は、チーム管理アクションにおける最も重要な違いをまとめたものです。
| アクション | owner | admin | member |
|---|---|---|---|
| 新しい admin または member を招待 | ✓ | ✓ | ✗ |
| **新しい owner を招待** | ✓ | ✗ | ✗ |
| admin または member を降格 / 削除 | ✓ | ✓ | ✗ |
| **別の owner を降格 / 削除** | ✓ | ✗ | ✗ |
| ワークスペースの削除 | ✓ | ✗ | ✗ |
**member は誰も招待できません** — 招待は admin 層の権限です。**owner だけが他の人を owner に昇格できます** — admin は member や他の admin を昇格・降格できますが、新しい owner を作成することはできません。同様に、admin は member や他の admin を削除できますが、**既存の owner には手を出せません**。要点は、最上位の層をすでに保有している人だけがその層を付与できるようにすることです — 権限は上方向に漏れません。
<Callout type="info">
エージェントの可視性には「workspace」と「private」の2種類があります。private エージェントは owner と admin だけがイシューに割り当てられます — これは特定の人だけが利用するように作られた構成を保護するためです。[エージェント](/agents)を参照してください。
</Callout>
## 新しいメンバーを招待する
Multica はメールで新しいメンバーを招待します。
1. ワークスペース設定ページで **メンバーを招待** をクリックし、メールアドレスを入力して役割を選択します。
2. Multica が一意のリンクを含む招待メールを送信します。
3. 受信者がリンクをクリックしてログイン(または登録)し、**招待を承諾** するとワークスペースに参加します。
招待されるメールアドレスは **あらかじめ Multica に登録されている必要はありません** — アカウントがなければ、招待を承諾した時点で自動的に作成されます。
招待メールの配信に失敗しても(誤ったアドレス、メールサービスの不具合など)、招待レコードはそのまま保持されます。ワークスペース設定からメールを再送するか、招待リンクを別の経路で共有できます。
招待は **7日間有効** です。それ以降にリンクをクリックすると「期限切れ」のメッセージが表示され、招待した人が新しく送り直す必要があります。
## 常に最低1人の owner を維持する
すべてのワークスペースには **常に最低1人の owner が存在しなければなりません**。この制約により、2つの操作が自動的にブロックされます。
- 最後の owner は自分自身を降格できません。
- 他の owner や admin は、最後の owner を削除できません。
<Callout type="warning">
あなたが最後の owner でチームを離れようとしている場合は、**まず owner の役割を別のメンバーに譲渡してから**、ワークスペースを離れるか引き継いでください。そうしないと操作が拒否されます。
</Callout>
## メンバーを削除する
owner と admin は、ワークスペースから他のメンバーを削除できます。削除されたメンバーは即座にアクセス権を失います。そのメンバーが作成したイシュー、コメントなどのコンテンツは、ワークスペースにそのまま保持されます。
## 次へ
- [イシューとプロジェクト](/issues) — メンバーが取り組む対象
- [コメントとメンション](/comments) — イシューの下で協業する

View File

@@ -0,0 +1,63 @@
---
title: "コメントでエージェントを @メンションする"
description: コメントで @ を使ってエージェントをメンションし、ちょっと見てもらいましょう — 担当者の変更も、ステータスの変更もなく、割り当てより軽い操作です。
---
import { Callout } from "fumadocs-ui/components/callout";
[コメント](/comments)で[エージェント](/agents)を `@`メンションするのは、より軽いトリガーです — **担当者の変更も、ステータスの変更もなく**、ただエージェントに現在の[イシュー](/issues)を見てもらうよう軽く促すだけです。[**割り当て**](/assigning-issues)(エージェントを担当者にしてイシューを渡すこと)と比べると、@メンションは「この部分をちょっと見て」「別の角度から分析して」「ちょっと呼び込んで一緒に議論しよう」といった場面に向いています。
## コメントでエージェントをメンションする
メンバーをメンションするのと同じです — `@` を入力してピッカーを開き、エージェントを選んでください。コメントが投稿されると、Multica はメンションされた各エージェントに対して**そのコメント**をトリガーコンテキストとして、すぐに `task` をキューに入れます。エージェントがタスクを受け取ると、次のものを読めます。
- イシュー全体(説明 + すべての過去のコメント)
- トリガーコメント自体 — 今回の実行の起点として
`@mention` の Markdown 構文、ピッカー、そして `@all` のセマンティクスは [**コメント**](/comments)で扱います。
<Callout type="info">
**コメントで[スクワッド](/squads)を `@`メンションすることもできます。** 同じピッカーがメンバーやエージェントと並べてスクワッドも表示します。スクワッドを選ぶと `[@SquadName](mention://squad/<uuid>)` が挿入され、スクワッドの**リーダーエージェント**が応答を調整するようトリガーされます — 担当者とステータスはそのまま維持されます。
</Callout>
## 割り当てとどう違うか
どちらもエージェントを働かせますが、仕組みはまったく異なります。
| 観点 | 割り当て | @メンション |
|---|---|---|
| `assignee` の変更 | ✓ | ✗ |
| `status` の変更 | ✗ | ✗ |
| `task` のキュー追加 | すぐにBacklog 以外) | すぐに |
| トリガーコメント ID | 任意 | 常に現在のコメントを含む |
| 1 回の操作あたりの対象エージェント | 1担当者 1 名) | 複数1 つのコメントで複数を @ 可能) |
| 優先度 | イシューから継承 | イシューから継承 |
判断の目安は単純です。**エージェントに「これからこのイシューを所有してほしい」なら割り当てを、「現在のコンテキストをちょっと見てほしい」なら @メンションを使ってください。**
## 複数のエージェントを @ するとどうなるか
1 つのコメントで複数のエージェントを @メンションすると、各エージェントは自分のランタイムで独立した `task` をキューに受け取ります — **互いをブロックすることなく並列に実行されます**。
同じイシューで、あるエージェントがすでに `queued` または `dispatched` 状態の `task` を持っている場合(たとえば、たった今メンションされてまだ開始していない場合)、今回のメンションは**重複排除**され、重複した `task` はキューに追加されません。重複排除は**単一のコメント単位で**適用されます — 数秒間隔で投稿された別々の 2 つのコメントが両方とも同じエージェントを @ すると、どちらも `task` をキューに入れます。
<Callout type="warning">
**コメントを編集して @ を追加しても、再トリガーされません。** 投稿した後で `@agent` を追加しなければと気づいた場合、編集で入れた `@` は表示される内容を変えるだけで、そのエージェントに新しい `task` を**届けません**。トリガーするには、新しいコメントを投稿するか、イシューをそのエージェントに割り当ててください。
</Callout>
## `@all` はどのエージェントもトリガーしない
`@all` で全員を呼ぶとき、**ワークスペースのメンバーだけがインボックスに入り、エージェントは `@all` の展開に含まれません。** これは意図された設計です。エージェントはインボックス通知を受け取らないため、`@all` はエージェントにとって意味を持ちません。エージェントを働かせるには、名前で直接メンションしてください。
## エージェントが自分自身を @メンションしてもループしない
エージェントは実行中にコメントを投稿でき、そのコメントには `@mention` が含まれることがあります。Multica にはハードコードされたガードがあります。**コメントの作成者が `@` メンションの対象エージェントと同じ場合、そのメンションはスキップされます** — 「エージェント A がエージェント A を @ → 新しい task → 再びエージェント A を @」のような無限ループは発生しません。
このガードは**直接的な自己参照だけをブロックします。** エージェント A がエージェント B を @メンションするのは正常に動作し、その後 B が応答で A を @メンションすると A が再びトリガーされます — つまり**間接的な再帰はブロックされません**。エージェントの指示を書くときは、複数のエージェントが互いを @メンションして循環を作らないよう注意してください。
## 次へ
- [**スクワッド**](/squads) — スクワッドを `@`メンションすると、リーダーが質問を適切なメンバーにルーティングします
- [**チャット**](/chat) — イシューと無関係な 1 対 1 の会話
- [**オートパイロット**](/autopilots) — エージェントがスケジュールに沿って自動的に作業を開始するようにする
- [**コメント**](/comments) — `@mention` の構文、ピッカー、そして `@all` のセマンティクス

View File

@@ -0,0 +1,46 @@
{
"title": "ドキュメント",
"pages": [
"index",
"how-multica-works",
"cloud-quickstart",
"self-host-quickstart",
"---ワークスペース & チーム---",
"workspaces",
"members-roles",
"issues",
"projects",
"comments",
"project-resources",
"---エージェント---",
"agents",
"agents-create",
"skills",
"squads",
"---エージェントの実行方法---",
"daemon-runtimes",
"install-agent-runtime",
"tasks",
"providers",
"---エージェントとの協業---",
"assigning-issues",
"mentioning-agents",
"chat",
"autopilots",
"---インボックス---",
"inbox",
"---連携---",
"github-integration",
"---セルフホスト & 運用---",
"environment-variables",
"auth-setup",
"troubleshooting",
"---リファレンス---",
"cli",
"auth-tokens",
"desktop-app",
"mobile-app",
"---開発者---",
"developers"
]
}

View File

@@ -0,0 +1,82 @@
---
title: モバイルアプリ (iOS)
description: まだ App Store にないオープンソースの Multica iOS アプリを、自分の iPhone に自分でビルドする方法。
---
import { Callout } from "fumadocs-ui/components/callout";
Multica の iOS クライアントはオープンソースで、web、desktop、バックエンドとともに[メインリポジトリ](https://github.com/multica-ai/multica)に含まれています。まだ App Store にはなく、その状況が変わるまでは、iPhone で使いたい人がソースから自分でビルドします。ビルドは初回は約 10〜20 分、それ以降は約 2 分かかり、[multica.ai](https://multica.ai) と同じバックエンドと通信するため、既存のアカウントがそのまま使えます。
<Callout type="info">
このページは**個人利用**向けです。アプリ開発者はリポジトリの [`apps/mobile/README.md`](https://github.com/multica-ai/multica/blob/main/apps/mobile/README.md) を読んでください — dev / staging のバリアントと全スクリプト一覧を扱っています。
</Callout>
## 必要なもの
- Xcode がインストールされた **Mac**App Store から無料で入手できます)。
- Xcode → Settings → Accounts に追加した無料の **Apple ID**。有料の Apple Developer Program アカウントは任意で、7 日間の署名期間を 1 年に延長するだけです — 下記の [7 日制限](#7-day-signing-limit)を参照してください。
- USB ケーブルで接続され、[Developer Mode が有効になった](https://docs.expo.dev/guides/ios-developer-mode/) **iPhone**(設定 → プライバシーとセキュリティ → デベロッパモード)。
- チェックアウトした Multica のソースコード:
```bash
git clone https://github.com/multica-ai/multica.git
cd multica
pnpm install
```
この一覧に欠けているものがあれば、Expo の [Set up your environment](https://docs.expo.dev/get-started/set-up-your-environment/) に沿って進めてください(**Development build → iOS Device** を選択)。リポジトリのチェックアウトを除くすべてに関する公式のセットアップガイドです。
## ビルドする
コマンドは 1 つ:
```bash
pnpm ios:mobile:device:prod:release
```
Xcode は Apple ID が自動的に所有する "Personal Team" でビルドに署名します — この team はどの Apple ID であれ初めて Xcode にサインインしたときに静かに作成されるため、何かを設定した記憶がなくてもすでに存在しています。これは **Release ビルド**です。Metro への依存がなく、スプラッシュ画面 → アプリへとつながり、App Store からインストールしたものとまったく同じです。
初回ビルドは CocoaPods をダウンロードし、React Native をソースからコンパイルします — 10〜20 分ほど見込んでください。以降のビルドは Xcode のキャッシュを再利用します。
一般的な手順はこれで終わりです。署名が失敗したら [トラブルシューティング](#troubleshooting)に進んでください。
## 7 日間の署名制限
無料の Apple ID はビルドを **7 日間**署名します。それを過ぎると、アプリは iPhone での起動を拒否し、「untrusted developer」エラーを表示します。Mac に再び接続して同じコマンドを再実行し、再署名してください — データはアプリではなくバックエンドにあるため、そのまま保持されます。
これを延長する唯一の方法は **Apple Developer Program アカウント**です([developer.apple.com](https://developer.apple.com) で年間 $99。すると署名は更新の間 1 年間有効になり、TestFlight を通じて他のデバイスに配布することもできます。
## 更新
まだ自動更新はありません。Multica のコードベースが進んだら、pull して再ビルドしてください。
```bash
git pull
pnpm install
pnpm ios:mobile:device:prod:release
```
Xcode がネイティブコンパイルをキャッシュするため、以降のビルドは高速です。
## なぜまだ App Store にないのか
iOS アプリはまだ速いペースで動いています — チームは今のところ App Store の審査サイクルよりも、リリースして反復改善することを好んでいます。正式な App Store リリースの前に TestFlight ベータが最も可能性の高い次のステップです。それまでは、上記の自前ビルドが iOS で Multica を使う唯一の方法です。
TestFlight が公開されたときに通知を受け取りたい場合は、[GitHub リポジトリ](https://github.com/multica-ai/multica)を watch してください。
## トラブルシューティング
**「No matching provisioning profiles found」** — Xcode がデフォルトのバンドル id `ai.multica.mobile` をあなたの Apple ID で署名することを拒否しています。まれですが、誰かが Apple の開発者ポータルでそのプレフィックスを登録していると発生します。自分が管理する任意の逆引きドメイン(`com.yourname.multica` で十分です)を選んで export し、再実行してください。
```bash
export EXPO_BUNDLE_IDENTIFIER_PROD=com.yourname.multica
pnpm ios:mobile:device:prod:release
```
id 自体に意味がある必要はありません — Apple は単に他の team に占有されていないことだけを求めています。
**「Could not launch &lt;app&gt;」/「Untrusted Developer」** — 7 日制限に達したかビルドを再実行してください、iPhone で開発者プロファイルを手動で信頼する必要があります。設定 → 一般 → VPN とデバイス管理 → あなたの Apple ID をタップ → 信頼。
**`Pod install` でビルドが止まる、または延々とコンパイルが続く** — 初回ビルドは CocoaPods が依存関係をダウンロードし、Xcode が React Native をソースからコンパイルするため、実際に 10〜20 分かかります。以降のビルドははるかに高速です。
**アプリがバックエンドに接続できない** — `apps/mobile/.env.production` が変更されていないか確認してください(デフォルトでは `EXPO_PUBLIC_API_URL=https://api.multica.ai` が同梱されています)。変更した場合は `git checkout apps/mobile/.env.production` で復元してください。

View File

@@ -0,0 +1,262 @@
---
title: プロジェクトリソース
description: 型付きのポインターGit リポジトリ、ローカルディレクトリ、今後さらに増える種類)をプロジェクトに添付し、エージェントが範囲を限定したコンテキストとして取り込めるようにします。
---
**プロジェクトリソースProject Resource** は型付きのポインターです — Git リポジトリの URL、自分のマシン上のパス、いずれは Notion ページまで — これを[プロジェクト](/workspaces)に添付します。[エージェント](/agents)がそのプロジェクト内のイシューに対して実行されると、デーモンはプロジェクトのリソース一覧をエージェントの作業ディレクトリと[メタスキル](/skills)プロンプトに自動的に書き込みます。
その結果、エージェントは、どのリポジトリをチェックアウトすべきか(またはどのローカルディレクトリで作業すべきか)、そしてこのプロジェクトの「主要な参照資料」が何かを、誰もコンテキストをイシュー本文にコピー&ペーストしなくても把握できます。
## メンタルモデル
プロジェクトはもはや単なるラベルではありません。小さな **リソースコンテナ** です。
- プロジェクトは 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`](#resource-type-github_repo)(タスクごとに隔離されたワークツリーへクローン)と [`local_directory`](#resource-type-local_directory)(特定のデーモンのマシン上のフォルダ内で直接実行)です。
## リソースタイプ: `github_repo`
デフォルトのリソースタイプです — タスクごとに隔離されたワークツリーへチェックアウトされます。
```json
{
"resource_type": "github_repo",
"resource_ref": {
"url": "https://github.com/owner/repo",
"default_branch_hint": "main"
}
}
```
`default_branch_hint` は任意です — 指定すると、デーモンがこれをメタスキルに出すため、エージェントはどのブランチを基準に作業すべきかを把握できます。
## リソースタイプ: `local_directory`
タスクごとに再クローンするのが現実的でないリポジトリ — 数ギガバイトのゲームのチェックアウト、大規模な monorepo、またはタスクごとのワークツリーモデルが煩わしいあらゆるプロジェクト — の場合、プロジェクトは代わりに **特定の[デーモン](/daemon-runtimes)のマシン上にある既存のディレクトリ** を指すことができます。エージェントは、クローンもコピーもワークツリーもなしに **そのフォルダ内で直接** 実行されます。
```json
{
"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` を選んでください。
1. **再クローンのコストが法外に大きい場合** — 数ギガバイトのゲームのチェックアウト、重い LFS アセットを持つ monorepo、またはタスクごとの `git clone` が実際の作業を圧倒するあらゆる場合。並行性をクローン不要の実行と引き換えにすることになります。
2. **変更がきめ細かく、変更が起きるそばからローカルでレビューしたい場合** — 単一のコンポーネントを繰り返し磨いていて、数分ごとにエージェントの編集と自分のエディターを行き来したく、`~/multica_workspaces/` から掘り出さなければならないタスクごとのワークツリーよりも、既存のチェックアウトを信頼できる情報源にしたい場合です。
どちらの場合でも受け入れるトレードオフは同じです: **このバージョンはファイル単位の書き込みロックを提供しません。** ディレクトリごとの直列ゲート同じフォルダで一度に1つのタスクが、別々の2つのイシューのエージェントが同時に同じファイルを触るのを防ぐ唯一の保護手段です。2つのイシューのエージェントを同じ `local_directory` に向けると、それらのタスクは並列化されずにキューに入ります — これは意図された動作です。同じコードベースで本物の並列性が必要なら、`github_repo` を使い続けてください。
### ローカルディレクトリを添付する
フォルダピッカーは **Desktop アプリ** にのみあります — Web アプリは OS のパスを読み取る方法がないため、「ローカルディレクトリを追加」ボタンはそこでは非表示になっています。Desktop では:
1. プロジェクトを開く → **Resources** パネル。
2. **ローカルディレクトリを追加** をクリックします。ネイティブのフォルダピッカーが開きます。
3. フォルダを選択します。そのパスは **この Desktop インストールが現在登録しているデーモン** にバインドされます — リソースレコードにはパスとそのデーモンの ID が一緒に保存されます。
Desktop では、このマシンのデーモンがオフラインのとき、またはプロジェクトにすでにこのデーモンへバインドされた `local_directory` があるとき、ボタンは表示されたまま **ヒントとともに無効化** されます — そのため *なぜ* 使えないのかが分かります。Web アプリではそもそもフォルダピッカーが一切ないため、ボタンは完全に非表示になります。)別のマシンのディレクトリをバインドするには、そのマシンに Desktop をインストールし、そこからリソースを追加してください。
CLI からも可能です(デーモン ID を自分で指定すれば、Web 専用環境でも動作します)。
```bash
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` を持つイシューでタスクがディスパッチされると、デーモンは次のことを行います。
1. パスを再検証します(上記のルール)。
2. symlink を解決した実際のパスをキーとして、ディレクトリごとのロックを取得します — そのため、同じフォルダに向かう2つの経路1つは symlink 経由、1つは直接も依然として直列化されます。
3. エージェントの `CLAUDE.md` / `AGENTS.md`(および `.multica/project/resources.json`)を **ユーザーのディレクトリ内に** 書き込みます。エージェントは、あなたが自分でそのフォルダを開いたのとまったく同じように、そこで作業します。
4. 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** から:
```bash
# 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で、エージェントの作業ディレクトリに書き込まれます。
```json
{
"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 呼び出しが失敗すると、プロンプトからプロジェクトセクションが省略され、ファイルも書き込まれませんが、タスクは依然として開始されます。エージェントは、欠落したプロジェクトコンテキストのために止まることは決してありません。
## 新しいリソースタイプを追加する
この抽象化の要点は、新しいタイプが安価だということです。完全な経路は:
1. **サーバーの検証器**`server/internal/handler/project_resource.go`)— `validateAndNormalizeResourceRef` に、新しいペイロードをパースして正規化する case を追加します。
2. **デーモンのメタスキルフォーマッター**`server/internal/daemon/execenv/runtime_config.go`)— `formatProjectResource` に case を追加し、エージェントのプロンプトが新しいタイプを読みやすい箇条書きとしてレンダリングするようにします。
3. **TypeScript の型**`packages/core/types/project.ts`)— `ProjectResourceType` を拡張し、ペイロードのインターフェースを追加します。
4. **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 のキャッシュされた文書テキストは、それらのタイプとともに提供される予定です。
これらは意図的な省略です — 最初のカットの目標は、可動部分を最小限にしてこの抽象化を検証することです。

View File

@@ -0,0 +1,49 @@
---
title: プロジェクト
description: 関連するイシューをまとめて1つの単位として追跡します — 優先度、ステータス、進捗、担当者とともに。
---
import { Callout } from "fumadocs-ui/components/callout";
Multica の **プロジェクト** は、関連する[イシュー](/issues)をまとめるコンテナです。作業の分量がイシュー1つよりは大きいが、ワークスペース全体よりは小さいときに使ってください — リリース、マイグレーション、複数の部分に分かれる機能、いくつもの枝に分岐する調査などです。
各プロジェクトには、名前、アイコン、説明、**リード**(メンバーまたは[エージェント](/agents))、**ステータス**`planned` / `in_progress` / `paused` / `completed` / `cancelled`)、**優先度**`urgent` / `high` / `medium` / `low` / `none`)、そして紐づくイシューのステータスから自動的に算出される **進捗** の百分率があります。
## プロジェクトとイシューの関係
プロジェクトとイシューは独立したオブジェクトで、多対一の関係です。1つのイシューは **最大1つの** プロジェクトに属することができ、1つのプロジェクトは **任意の数の** イシューを保持できます。紐づけと紐づけ解除はいつでも元に戻せます — ボードビューでドラッグするか、イシュー右側のプロパティパネルにあるプロジェクトピッカーを使ってください。
プロジェクトの進捗バーは、紐づくイシューから計算されます — `done` に到達したイシューが多いほど、バーがより満たされます。`cancelled` のイシューは集計から除外されます。`backlog` のイシューは分母にはカウントされますが、分子にはカウントされません。
## サイドバーにピン留めする
プロジェクト右上のピンアイコンをクリックすると、サイドバーのピン留めリストに追加されます。ピン留めされたプロジェクトは、ワークスペースのどこにいてもワンクリックでアクセスできます。チームの全員がそれぞれ独立してピン留めできます — ピン留めは個人ごとの設定です。
サイドバーの **ワークスペース → プロジェクト** リンクは、常にワークスペースのすべてのプロジェクトを表示します。ピン留めはその上に重ねる個人用のショートカットにすぎません。
## リソースを添付する
各プロジェクトには、GitHub リポジトリを添付する **Resources** セクションがあります。添付すると、このプロジェクトのイシューに割り当てられた[エージェント](/agents)は、タスクを実行する際にそれらのリポジトリを読み書きできます — Multica がリポジトリ URL をコンテキストとして[デーモン](/daemon-runtimes)に渡します。
リソースはプロジェクト単位です。複数のプロジェクトが同じリポジトリを共有する場合は、それぞれに添付してください。
## プロジェクトを削除する
プロジェクトを削除しても **イシューは削除されません**。紐づくイシューは単に紐づけが解除され、ワークスペースのフラットなイシュー一覧に戻ります。これは意図された動作です — プロジェクトの枠組みが変わっても、プロジェクトの範囲として定められた作業が使い捨てになることはまれだからです。
<Callout type="info">
作業も一緒に削除したい場合は、まずイシューをアーカイブまたは削除してから、プロジェクトを削除してください。
</Callout>
## プロジェクトリード
リードは、プロジェクトに対して責任を負う人 — またはエージェント — です。これはアクセス制御ではなく、弱いシグナルです。誰がリードであるかに関わらず、ワークスペースのすべてのメンバーがプロジェクトを編集できます。プロジェクトのリードには次のものを設定できます。
- ワークスペースのメンバー(人間のチームメイト)
- [エージェント](/agents) — プロジェクトの作業の大半をエージェントに委任する場合に便利です(例: 「週次のバグトリアージ」をトリアージ用エージェントがリードする)
## 次へ
- [イシュー](/issues) — プロジェクトの中に存在する作業の単位
- [プロジェクトリードとしてのエージェント](/agents) — エージェントが適切な担当者となる場合
- [Multica の仕組み](/how-multica-works) — より広い全体像

View File

@@ -0,0 +1,127 @@
---
title: AI コーディングツール対応表
description: Multica は 12 個の AI コーディングツールをサポートしています。すべて同じインターフェースを実装していますが、機能の詳細は大きく異なります。
---
import { Callout } from "fumadocs-ui/components/callout";
Multica は **12 個の AI コーディングツール**を標準でサポートしています。これらはすべて同じインターフェース(キューへの投入、ディスパッチ、実行、結果の返却)を実装しているため、同じ Multica ボードからどれでも動かすことができます。**しかし機能の詳細は大きく異なります**: セッション再開が実際に動作するか、MCP をサポートするか、スキルファイルがどこに置かれるか、モデルをどう選択するか。このページがその完全な対応表です。
エージェントを作成するときにツールを選ぶ際のガイダンスは、[エージェントの作成と構成](/agents-create)を参照してください。
## 機能対応マトリクス
| ツール | ベンダー | セッション再開 | MCP | スキル注入パス | モデル選択 |
|---|---|---|---|---|---|
| **Antigravity** | Google | ✅ (`--conversation <id>`) | ❌ | `.agents/skills/` | Antigravity CLI 自体の内部で管理 |
| **Claude Code** | Anthropic | ✅ | **✅(実際に使用する唯一のツール)** | `.claude/skills/` | 静的 + flag |
| **Codex** | OpenAI | ⚠️ コードは存在するが到達不可 | ❌ | `$CODEX_HOME/skills/` | 静的 |
| **Copilot** | GitHub | ✅ | ❌ | `.github/skills/` | 静的(アカウントの権限で決定) |
| **Cursor** | Anysphere | ⚠️ コードは存在するが使用不可 | ❌ | `.cursor/skills/` | 動的探索 |
| **Gemini** | Google | ❌ | ❌ | `.agent_context/skills/` | 静的 |
| **Hermes** | Nous Research | ✅ | ❌ | `.agent_context/skills/`(フォールバック) | 動的探索 |
| **Kimi** | Moonshot | ✅ | ❌ | `.kimi/skills/` | 動的探索 |
| **Kiro CLI** | Amazon | ✅ | ❌ | `.kiro/skills/` | 動的探索 |
| **OpenCode** | SST | ✅ | ❌ | `.opencode/skills/` | 動的探索 |
| **OpenClaw** | オープンソース | ✅ | ❌ | `.agent_context/skills/`(フォールバック) | エージェントにバインドされ、タスクごとに切り替え不可 |
| **Pi** | Inflection AI | ✅(セッションがファイルパス) | ❌ | `.pi/skills/` | 動的探索 |
## 各ツールの用途
### Antigravity
Google が提供します。CLI バイナリ名は `agy` です。Google の Antigravity サービスと連携し、Gemini ベースのデフォルトモデルが付属しています。**セッション再開が動作します** — `--conversation <id>` を通じて行われ、stdout が構造化されたイベントストリームではなくプレーンテキストであるため、デーモンが CLI のログファイルから conversation UUID をキャプチャします。`--model` flag はありません — モデル選択は Antigravity CLI の設定内にあるため、Multica はこのプロバイダーに対してエージェントごとのモデルピッカーを無効にします。スキルは `.agents/skills/` に配置されますCLI が Gemini CLI のワークスペーススキルレイアウトをそのまま継承します — [Antigravity 移行ドキュメント](https://antigravity.google/docs/gcli-migration)を参照)。
### Claude Code
Anthropic が提供します。**新規ユーザーにとって第一の選択肢**であり、最も完成度の高い機能セットを備えています: セッション再開が実際に動作し、**11 個の中で MCP 構成を本当に読み取る唯一のツール**であり、`--max-turns` や `--append-system-prompt` のような細かな調整 flag をサポートします。Anthropic API キーが必要です。
### Codex
OpenAI が提供します。JSON-RPC 2.0 を使用し、ステートフルな能力がより強く、よりきめ細かい承認メカニズム(`exec_command` および `patch_apply` に対する手動承認)を備えています。**セッション再開のコードは存在しますが、現在は到達できません** — 再開が必要なら、Claude Code または ACP 系のいずれかを選んでください。
### Copilot
GitHub が提供します。モデルルーティングは GitHub アカウントの権限を経由します — ツールが直接モデルを選択するのではなく、GitHub がどのモデルを提供するかを決定します。`.github/skills/` にスキルを置くのは GitHub CLI のネイティブな探索メカニズムです。
### Cursor
Anysphere が提供し、Cursor エディターに対応する CLI です。**セッション再開のコードは存在しますが、実際には動作しません** — Cursor CLI のイベントストリームがセッション ID を返さないため、渡す再開値は常に無効です。再開が必要なら、別のものを選んでください。
### Gemini
Google が提供し、Gemini 2.5 および 3 シリーズをサポートします。**セッション再開も MCP もサポートしません** — 長いコンテキストの記憶が不要なワンショットタスクに適しています。
### Hermes
Nous Research が提供します。ACP プロトコルを使用しますKimi とトランスポート層を共有します)。セッション再開が動作します。しかし**スキル注入パスは専用のものではなく汎用のフォールバック**`.agent_context/skills/`)です — Hermes CLI 自体がこのパスを読み取らない場合、スキルが適用されないことがあります。テストで確認してください。
### Kimi
Moonshot が提供し、中国市場を対象としています。Hermes と ACP プロトコルを共有しますが、スキルパス `.kimi/skills/` は Kimi CLI のネイティブな探索メカニズムであり、Hermes のフォールバックとは異なります。
### Kiro CLI
Amazon が提供します。`kiro-cli acp` を通じて stdio 上で ACP を使用します。セッション再開は ACP `session/load` で動作し、モデル選択は `session/set_model` で動作し、スキルはプロジェクトレベルのネイティブ探索のために `.kiro/skills/` にコピーされます。
### OpenCode
SST が提供するオープンソースです。利用可能なモデルを動的に探索しますCLI の構成ファイルをスキャン)。セッション再開が動作します。**自分のモデルカタログをカスタマイズしたい、いじるのが好きなユーザーに適しています。**
### OpenClaw
オープンソースプロジェクトであり、CLI エージェントオーケストレーターです。**モデルはエージェント層にバインドされます**`openclaw agents add --model` — タスクごとに上書きできません。構成は厳格に制御されます: ユーザーは `--model` や `--system-prompt` を渡せず、エージェント登録時の構成が決定します。
### Pi
Inflection AI が提供し、ミニマルです。**セッション再開の方式が独特です** — セッション ID が文字列 ID ではなく、ディスク上のファイルパス(`~/.pi/...`)です。他のツールでは再開 id は CLI が返す文字列ですが、Pi では再開 id はセッションファイルそのものです。
## セッション再開: 実際にサポートするツール
セッション再開のメカニズムは[タスク](/tasks#can-a-task-continue-from-the-previous-context)で扱います。以下はツールごとの**正確な現在の状態**です。
| 状態 | ツール | 意味 |
|---|---|---|
| ✅ 実際に動作 | Antigravity, Claude Code, Copilot, Hermes, Kimi, Kiro CLI, OpenCode, OpenClaw, Pi | 再開 id を渡すと以前のコンテキストから続行します |
| ⚠️ コードは存在するが到達不可 | Codex, Cursor | コードに再開パスがありますが、実際には到達しませんCodex は静かにフォールバックし、Cursor はセッション id を返しません) — **未サポートとみなしてください** |
| ❌ なし | Gemini | CLI に再開メカニズムがありません |
**意思決定のために**: ワークフローでエージェントがタスク間でコンテキストを保持する必要がある場合(失敗時のリトライ、手動の再実行、対話的な反復)、✅ の行にあるツールだけを選んでください。
## MCP 構成: Claude Code だけが実際に読み取る
**12 個のツールのうち、`mcp_config` を実際に消費するのは Claude Code だけです**。残りの 11 個はこのフィールドを受け取りますが、**完全に無視します** — エラーも警告もなく、構成はただ効果を発揮しません。
<Callout type="warning">
エージェント構成で `mcp_config` を設定しても、Claude Code 以外のツールを選んだ場合、MCP サーバーはそのエージェントに**何の効果**も及ぼしません。現在、MCP 連携は Claude Code のみをカバーしています。
</Callout>
## スキルファイルが置かれる場所
各ツールは**それぞれ独自の**スキル探索パスを使用します。タスクが実行される前に、Multica デーモンがワークスペースのスキルファイルを対応するパスにコピーします。
| ツール | パス | ネイティブ探索か |
|---|---|---|
| Claude Code | `.claude/skills/` | ✅ ネイティブ |
| Codex | `$CODEX_HOME/skills/` | ✅ ネイティブ |
| Copilot | `.github/skills/` | ✅ ネイティブ |
| Cursor | `.cursor/skills/` | ✅ ネイティブ |
| Kimi | `.kimi/skills/` | ✅ ネイティブ |
| Kiro CLI | `.kiro/skills/` | ✅ ネイティブ |
| OpenCode | `.opencode/skills/` | ✅ ネイティブ |
| Pi | `.pi/skills/` | ✅ ネイティブ |
| Antigravity | `.agents/skills/` | ✅ ネイティブGemini CLI のワークスペースレイアウトを継承 — [Antigravity ドキュメント](https://antigravity.google/docs/gcli-migration)を参照) |
| Gemini | `.agent_context/skills/` | ⚠️ 汎用フォールバック |
| Hermes | `.agent_context/skills/` | ⚠️ 汎用フォールバック |
| OpenClaw | `.agent_context/skills/` | ⚠️ 汎用フォールバック |
フォールバックパスを使うツールが実際にこのディレクトリを読み取るかどうかは、そのツール自体のドキュメントによって異なり、保証されません。Gemini / Hermes / OpenClaw でスキルが適用されない場合は、まずこの点を確認してください。
スキルの作成と使用については、[スキル](/skills)を参照してください。
## 次へ
- [エージェントの作成と構成](/agents-create) — エージェントに使うツールを選ぶ
- [タスク](/tasks) — タスクのライフサイクルとセッション再開のメカニズム
- [デーモンとランタイム](/daemon-runtimes) — ツールが実行される場所と Multica への接続方法
- [エージェントランタイムのインストール](/install-agent-runtime) — サポートされる 12 個のツールそれぞれのインストールと認証

View File

@@ -0,0 +1,275 @@
---
title: セルフホスティングのクイックスタート
description: Docker で自分のサーバーやマシン上に Multica を実行しますKubernetes では Helm が利用できます。所要時間は約10分です。
---
import { Callout } from "fumadocs-ui/components/callout";
このページでは、Docker を使って Multica **サーバー**(バックエンド + フロントエンド + PostgreSQLを自分のマシンやサーバー上で実行する手順を案内します。完了すると、[ワークスペース](/workspaces)、[イシュー](/issues)、[コメント](/comments)、[エージェント](/agents)の構成を含むデータが、完全にあなたの管理下に置かれます。
エージェントの **実行** は、依然としてローカルで動かす[デーモン](/daemon-runtimes)と、そのマシンにインストールされた [AI コーディングツール](/providers)に依存します — Cloud とまったく同じです。セルフホスティングはサーバー層を置き換えるだけで、実行層を置き換えるわけではありません。
## 前提条件
- **Docker** がインストールされ、`docker compose` を実行できること
- **Git**(任意ですが、ソースを取得できるので推奨)
- 常時稼働させられるマシン(ローカル / 内部ネットワーク / クラウドホストのいずれでも可)
- **デーモンを実行するマシン** に AI コーディングツールが最低1つインストールされていることサーバーを実行するマシンである必要はなく、開発用ートパソコンでも構いません
## 1. プロジェクトを取得してバックエンドを起動する
<Callout type="info">
**すでに Kubernetes を使っていますか?** Docker をスキップして代わりに Helm チャートを使ってください — 下記の [Kubernetes デプロイ](#kubernetes-deployment-alternative)へ移動し、初回ログインのために [ステップ4](#4-first-login--create-a-workspace)に戻ってきてください。
</Callout>
```bash
git clone https://github.com/multica-ai/multica.git
cd multica
make selfhost
```
`make selfhost` は次のことを行います。
1. `.env` がなければ `.env.example` から生成し、**ランダムな JWT_SECRET** を併せて作成します
2. 公式の Docker イメージPostgreSQL、Multica backend、Multica frontendを取得します
3. `docker-compose.selfhost.yml` を使ってすべてのサービスを起動します
4. バックエンドの `/health` エンドポイントが準備できるまで待機します
起動後の継続的なプロダクションプローブには、データベースや migration の問題でチェックが失敗するようにしたい場合は `/readyz` を使ってください。
バックエンドのコンテナは起動時に **データベースの migration を自動で実行します**`docker/entrypoint.sh` がサーバー起動前に `./migrate up` を実行)— バックエンドのログで migration の出力を確認できます。バージョンアップグレードも同じ方法で処理されます。
<Callout type="info">
**イメージがまだ公開されていませんか?** `make selfhost` がイメージを取得できない場合、まだリリースされていないバージョンタグにいる可能性があります。安定リリースに切り替えるか、ソースからビルドしてください: `make selfhost-build`。
</Callout>
起動すると次のようになります。
- **フロントエンド**: [http://localhost:3000](http://localhost:3000)
- **バックエンド**: [http://localhost:8080](http://localhost:8080)
<Callout type="info">
**ポートは `127.0.0.1` でのみ待ち受けます。** `docker-compose.selfhost.yml` は公開されるすべてのポートを loopback にバインドします — `ss -tlnp` には `0.0.0.0:8080` は表示されず、設計上、他のマシンからはサービスにアクセスできません。デフォルトの `JWT_SECRET` と Postgres の認証情報は、公開インターネット上に置いては絶対にいけません。マシン間アクセスが必要な場合は、TLS を終端するリバースプロキシをスタックの前に置いてください — [ステップ5b — マシン間: リバースプロキシを前に置く](#5b-cross-machine-front-with-a-reverse-proxy)を参照してください。
</Callout>
## 2. 重要: プロダクションの安全設定を維持する
<Callout type="warning">
**`docker-compose.selfhost.yml` はデフォルトで `APP_ENV` を `production` に設定し**、`MULTICA_DEV_VERIFICATION_CODE` を空のままにするため、公開インスタンスには固定コードがありません。
`MULTICA_DEV_VERIFICATION_CODE` はローカルまたは非公開のテスト自動化でのみ設定してください。`APP_ENV` が non-production のときに固定コードが有効になっていると、コードをリクエストできる誰もがその固定値でサインインできてしまいます。[認証設定 → 固定のローカルテストコード](/auth-setup#fixed-local-testing-codes)を参照してください。
公開デプロイの前には、`.env` に `APP_ENV=production` が設定され、`MULTICA_DEV_VERIFICATION_CODE` が空であることを必ず確認してください。
</Callout>
## 3. メールサービスを構成する(任意ですが推奨)
メールを構成しないと、ユーザーはメールで認証コードを受け取れず、サーバーは生成したコードを代わりに stdout に出力します。
2種類の配信バックエンドがサポートされています — ネットワークに合うものを選んでください。
**オプション A — Resendクラウド / 公開インターネットのデプロイ):**
1. [Resend](https://resend.com/) にサインアップして API key を取得します
2. 自分が管理する送信用ドメインを認証します
3. `.env` に次を設定します。
```bash
RESEND_API_KEY=re_xxxxxxxxxxxx
RESEND_FROM_EMAIL=noreply@yourdomain.com
```
**オプション B — SMTP relay内部ネットワーク / オンプレミス):**
デプロイ環境が `api.resend.com` に到達できない場合や、すでに内部メールリレーMicrosoft Exchange、Postfix、オンプレミスの SendGrid など)がある場合に使ってください。両方が設定されている場合は `SMTP_HOST` が Resend より優先されるため、認証メールと招待メールは内部リレーにとどまります。ポート 465SMTPS / 暗黙的 TLSは現在サポートされていません — 25 または 587 を使ってください。
**匿名 Exchange 内部リレー(ポート 25** — ホストが IP で信頼され、認証情報なしで送信する場合:
```bash
SMTP_HOST=exchange.internal.example.com
SMTP_PORT=25
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_TLS_INSECURE=false
RESEND_FROM_EMAIL=noreply@yourdomain.com # reused as the From: header
```
**認証付き送信(ポート 587、STARTTLS** — リレーがサービスアカウントを必要とし、STARTTLS が広告されると自動的にアップグレードされる場合:
```bash
SMTP_HOST=smtp.internal.example.com
SMTP_PORT=587
SMTP_USERNAME=multica
SMTP_PASSWORD=...
SMTP_TLS_INSECURE=false # set true only for private CA / self-signed
RESEND_FROM_EMAIL=noreply@yourdomain.com
```
その後、再起動します: `docker compose -f docker-compose.selfhost.yml restart backend`。再起動時、バックエンドはどのプロバイダーを選んだかを出力します(`EmailService: SMTP relay …` / `Resend API` / `DEV mode`)— 認証情報は決してログに残らないため、この行はヘルプを求めるときに共有しても安全です。
追加の認証構成OAuth、サインアップの許可リストと SMTP 変数の完全なリファレンスは、[認証設定](/auth-setup)と[環境変数 → メール](/environment-variables#email-configuration)を参照してください。
## 4. 初回ログイン + ワークスペースの作成
[http://localhost:3000](http://localhost:3000) を開きます。
- メールアドレスを入力します
- 構成したメールバックエンドResend または SMTP relayから認証コードを受け取ります。どちらも構成していない場合は、サーバーコンテナの stdout からコピーしてください — `[DEV] Verification code` の行を探します
- non-production の非公開インスタンスで `MULTICA_DEV_VERIFICATION_CODE=888888` を明示的に設定した場合を除き、`888888` を使わないでください
- ログインして最初のワークスペースを作成します
## 5. CLI を自分のサーバーに向ける
CLI のインストールは [Cloud クイックスタート → 2. CLI をインストールする](/cloud-quickstart#2-install-the-multica-cli) と同じです — Homebrew / スクリプト / PowerShell のいずれかを選んでください。
### 5a. 同じマシン
CLI とサーバーが同じホストで動作している場合、デフォルト値ですでに動作します。
```bash
multica setup self-host
```
これにより CLI が `http://localhost:8080`(バックエンド)と `http://localhost:3000`フロントエンドを指すようになり、ブラウザログインを案内し、PAT をローカルに保存して、**デーモンを自動的に起動します**。
### 5b. マシン間: リバースプロキシを前に置く
compose スタックは `127.0.0.1` でのみ待ち受けるため、別のマシンにあるデーモンは `http://<server-ip>:8080` に直接接続できません — そして、そうなることを望むべきでもありません。さもなければデフォルトの `JWT_SECRET` が公開インターネットから到達可能になってしまうからです。TLS を終端し、`127.0.0.1:8080`(バックエンド)と `127.0.0.1:3000`フロントエンドへ転送するリバースプロキシをサーバーに置き、CLI を公開 HTTPS URL に向けてください。
```bash
multica setup self-host \
--server-url https://<your-domain> \
--app-url https://<your-domain>
```
単一のホスト名でフロントエンドとバックエンドの両方を前段に置く(デーモンと Web アプリの両方に必要な WebSocket サポートを含む)最小限の Caddyfile は次のとおりです。
```nginx
multica.example.com {
# WebSocket route — must come before the catch-all
@ws path /ws /ws/*
handle @ws {
reverse_proxy 127.0.0.1:8080 {
flush_interval -1
}
}
# Backend API
handle /api/* {
reverse_proxy 127.0.0.1:8080
}
# Everything else → frontend
reverse_proxy 127.0.0.1:3000
}
```
プロキシを立ち上げたら、サーバーの `.env` に `FRONTEND_ORIGIN=https://multica.example.com` を設定してバックエンドを再起動してください — そうしないと WebSocket の origin チェックがブラウザを拒否します([トラブルシューティング → WebSocket が接続できない](/troubleshooting#websocket-cant-connect))。
[Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) も堅実な選択肢です — ホストにポートを一切公開せずに TLS と公開ホスト名を提供してくれます。Nginx で同等に構成する方法(`app.` / `api.` を別々のホスト名に分離、WebSocket 用の `proxy_set_header Upgrade`も同じくらいうまく動作します。重要な要件は、TLS の終端と `/ws` での `Upgrade` ヘッダーの転送です。
## 6. エージェントの作成 + 最初のタスクの割り当て
Cloud と同じ流れです — [Cloud クイックスタート → ステップ5-6](/cloud-quickstart#5-create-an-agent)を参照してください。
## 7. 使用量ロールアップのスケジューリング(使用量ダッシュボードに必須)
<Callout type="warning">
使用量 / ランタイムのダッシュボードは、`rollup_task_usage_hourly()` が埋める派生テーブル `task_usage_hourly` からデータを読み取ります。バンドルされた `pgvector/pgvector:pg17` の Postgres イメージには **`pg_cron` が含まれておらず**、バックエンドもロールアップをインプロセスで実行しません。`rollup_task_usage_hourly()` をスケジューリングするものが何もないと、生の `task_usage` 行は届き続けるのに、ダッシュボードは永遠にゼロのままになります。
</Callout>
サポートされているオプションのいずれか1つを選んでください — 1つあれば十分です。
**オプション A — 外部 cron / systemd-timer最もシンプル。** 任意の帯域外スケジューラから5分ごとにロールアップを実行します。冪等でウォーターマーク駆動なので、取りこぼしたティックは追いつきます。
```bash
# /etc/cron.d/multica-rollup — every 5 minutes
*/5 * * * * root docker compose -f /path/to/multica/docker-compose.selfhost.yml \
exec -T postgres psql -U multica -d multica \
-c "SELECT rollup_task_usage_hourly();" >/dev/null
```
**オプション B — Postgres を `pg_cron` を同梱したイメージに置き換える。** `docker-compose.selfhost.yml` の `pgvector/pgvector:pg17` を、`pgvector` と `pg_cron` の両方を備えたイメージ(`supabase/postgres`、またはカスタムビルド)に置き換え、`shared_preload_libraries=pg_cron` を設定して再起動してから、ジョブを一度登録します。
```sql
CREATE EXTENSION IF NOT EXISTS pg_cron;
SELECT cron.schedule(
'rollup_task_usage_hourly',
'*/5 * * * *',
$$SELECT rollup_task_usage_hourly()$$
);
```
**オプション C — まず履歴をバックフィルする(アップグレード経路)。** `v0.3.4 → v0.3.5+` へアップグレード中で、既存の `task_usage` 行がある場合、migration `103` は hourly テーブルがシードされるまで `refusing to drop legacy daily rollups: ...` とともに `migrate up` を中断します。バンドルされたバックフィルを一度実行してから、オプション A または B を設定してください。
```bash
docker compose -f docker-compose.selfhost.yml exec backend \
./backfill_task_usage_hourly --sleep-between-slices=2s
```
`--sleep-between-slices=2s` は、忙しい DB での読み取り負荷を調整します。完了後、バックエンドのコンテナを再起動すると(起動時に migration が実行されます)アップグレードが完了します。
完全なリファレンス — Kubernetes の `CronJob` テンプレートとアップグレード順序を含む — は、リポジトリの [`SELF_HOSTING_ADVANCED.md → Usage Dashboard Rollup`](https://github.com/multica-ai/multica/blob/main/SELF_HOSTING_ADVANCED.md#usage-dashboard-rollup) にあります。
## Kubernetes デプロイ(代替手段)
すでに Kubernetes クラスターを運用している場合、リポジトリには `deploy/helm/multica/` に Helm チャートも同梱されています。k8s 用の `make selfhost` に相当します — 同じバックエンドイメージ、フロントエンドイメージ、`pgvector/pgvector:pg17` の Postgres を Deployment / Service / Ingress としてパッケージングし、`values.yaml` からレンダリングされた1つの `ConfigMap` を併せて提供します。k3s + Traefik + `local-path` を基準に作成されており、Ingress コントローラーとデフォルトの `ReadWriteOnce` StorageClass があるあらゆるクラスターで動作するはずです。
このチャートは **シークレット値をテンプレート化しません**。`multica-secrets` という名前の Secret を名前で参照するため、実際の JWT / DB / Resend / Google キーが git や `values.yaml` に置かれる必要はまったくありません。ネームスペースと Secret を kubectl で一度作成してください。
```bash
kubectl create namespace multica
kubectl -n multica create secret generic multica-secrets \
--from-literal=JWT_SECRET="$(openssl rand -hex 32)" \
--from-literal=POSTGRES_PASSWORD="$(openssl rand -hex 16)" \
--from-literal=RESEND_API_KEY="" \
--from-literal=GOOGLE_CLIENT_SECRET="" \
--from-literal=CLOUDFRONT_PRIVATE_KEY="" \
--from-literal=MULTICA_DEV_VERIFICATION_CODE=""
```
その後、チャートをインストールします。
```bash
git clone https://github.com/multica-ai/multica.git
cd multica
helm install multica deploy/helm/multica -n multica
```
デフォルト値はホスト名 `multica.dev.lan`webと `api.multica.dev.lan`(バックエンド)を想定しています。これらを `/etc/hosts`(またはローカル DNSに追加し、Ingress に到達可能な任意のノード IP を指すようにしてください。別のホスト名を使うには、`deploy/helm/multica/values.yaml` をコピーして `ingress.frontend.host` / `ingress.backend.host` と、それに対応する `backend.config.appUrl` / `frontendOrigin` / `localUploadBaseUrl` / `googleRedirectUri` を編集し、`-f my-values.yaml` でインストールしてください。
コールドクラスターでは、バックエンドが Postgres を待ち、migration を実行する間、数分間 `Running` 状態だが `Ready` ではないことがあります — startupProbe がこれを吸収するため、ポッドは再起動されないはずです。`Ready` になったら:
```bash
curl -H "Host: api.multica.dev.lan" http://<ingress-ip>/healthz
# {"status":"ok","checks":{"db":"ok","migrations":"ok"}}
```
その後 `http://multica.dev.lan` を開き、上記の [ステップ4 — 初回ログイン](#4-first-login--create-a-workspace)から続けてください。CLI を Ingress のホスト名に向けます。
```bash
multica setup self-host \
--server-url http://api.multica.dev.lan \
--app-url http://multica.dev.lan
```
チャートを変更せずに最新のイメージだけを取得するには、`kubectl -n multica rollout restart deploy/multica-backend deploy/multica-frontend` を実行してください。特定の Multica リリースに固定するには、values ファイルで `images.backend.tag` / `images.frontend.tag` を設定して `helm upgrade` を実行してください。`helm -n multica uninstall multica` はワークロードを削除しますが、PVC と Secret は保持します。`kubectl delete namespace multica` はすべてを消去します。
完全なリファレンス — 3つのログインモード、web イメージにビルド時に焼き込まれた `REMOTE_API_URL` に対する `backend` ExternalName の回避策、リソース制限、TLS — は、リポジトリの [`SELF_HOSTING.md`](https://github.com/multica-ai/multica/blob/main/SELF_HOSTING.md#kubernetes-deployment-alternative) にあります。
## よくある問題
- **バックエンドが起動しない**: `docker compose -f docker-compose.selfhost.yml logs backend` でコンテナのログを確認してください。たいていは `.env` の不正な `DATABASE_URL` または `JWT_SECRET` が原因です
- **認証コードが届かない**: メールバックエンドが構成されていない場合Resend も SMTP もない)→ `docker compose logs backend` で `[DEV] Verification code` を探してください
- **WebSocket が接続できない**: 公開デプロイでは、`FRONTEND_ORIGIN` を実際のフロントエンドのドメインに必ず設定する必要があります。[トラブルシューティング → WebSocket が接続できない](/troubleshooting#websocket-wont-connect)を参照してください
- **使用量 / ランタイムのダッシュボードがゼロのまま**: `rollup_task_usage_hourly()` がスケジューリングされていません — 上記の [ステップ7](#7-schedule-the-usage-rollup-required-for-the-usage-dashboard)と[トラブルシューティング → 使用量ダッシュボードがゼロと表示される](/troubleshooting#usage-dashboard-stays-at-zero)を参照してください
- **`migrate up` が `refusing to drop legacy daily rollups` で失敗する**: `v0.3.4 → v0.3.5+` のアップグレード経路ガードです。まず `backfill_task_usage_hourly` を実行してください — [ステップ7 → オプション C](#7-schedule-the-usage-rollup-required-for-the-usage-dashboard)を参照してください
## 次のステップ
- [環境変数](/environment-variables) — 完全な env リファレンス
- [認証設定](/auth-setup) — Resend / OAuth / サインアップ許可リストの詳細
- [GitHub 連携](/github-integration) — GitHub App を接続して、PR がイシューに自動でリンクされ、マージするとイシューが閉じられるように設定する
- [トラブルシューティング](/troubleshooting) — うまくいかないときはここから始めてください
- [デスクトップアプリ](/desktop-app) — `~/.multica/desktop.json` を通じた任意のデスクトップ設定。Web フロントエンド + CLI が依然として最速のセルフホスティング経路です

View File

@@ -0,0 +1,67 @@
---
title: スキル
description: エージェントに「ナレッジパック」を取り付けましょう — Anthropic Agent Skills オープン標準と互換性があります。
---
import { Callout } from "fumadocs-ui/components/callout";
スキルは[エージェント](/agents)のための**ナレッジパック**です — `SKILL.md` 1 つと、任意の補助ファイルスクリプト、設定、参照テンプレートで構成され、エージェントに「この種のタスクに出くわしたら、こう考えてこう動け」と伝えます。Multica は [Anthropic Agent Skills](https://agentskills.io) オープン標準を採用しているため、Anthropic 公式リポジトリ、ClawHub、skills.sh などから取得した、標準に準拠したどのスキルでも直接インポートできます。
## ワークスペーススキルとローカルスキル
Multica は 2 つのスキルソースに対応しています。
- **ワークスペーススキル** — Multica のクラウドに保存されます。エージェントに取り付けると、タスク実行時にあなたのデーモンへ同期されます。これが**チーム全体でスキルを共有する標準的な方法**です。
- **ローカルスキル** — あなたのマシン上のディレクトリに存在します(各 AI コーディングツールには慣例的なデフォルトパスがあります。例: Claude Code の `~/.claude/skills/`)。あなたが要求すると、[デーモン](/daemon-runtimes)がマシンをスキャンし、どれをワークスペースに取り込むかを手動で選びます。
ほとんどの場合は**ワークスペーススキル**が望ましいでしょう。一度インポートすれば、すべてのチームメイトのエージェントが使えるからです。ローカルスキルは、まずローカルでテストしたい場合や、内容に機密性の高いローカル資料が含まれる場合に適しています。
## スキルをインポートする
ワークスペーススキルは 4 つのソースから取得します。
- **新規作成** — UI で `SKILL.md` と関連ファイルを直接作成します
- **GitHub から** — リポジトリ URL を貼り付けると(例: `https://github.com/owner/repo/tree/main/skills/my-skill`、Multica がそのディレクトリの `SKILL.md` とすべてのファイルを取得します
- **ClawHub から** — [ClawHub](https://clawhub.io) 公開マーケットプレイスで検索し、バージョンを選択してインポートします
- **ローカルから** — デーモンがあなたのマシンのスキルディレクトリをスキャンし、ワークスペースに取り込むものを選びます
個々のファイルもスキルパック全体も容量の上限がありますGitHub からインポートする際の単一ファイルの上限は約 1 MB。正確なルールはインポートダイアログに表示され、上限を超えるとエラーが返されます。
## エージェントに取り付ける
インポートしたスキルは、**特定のエージェントに取り付けて**初めて効果を発揮します。1 つのエージェントに複数のスキルを取り付けられ、1 つのスキルを複数のエージェントに取り付けることもできます。
取り付けた後は、エージェントが次にタスクを開始するときにスキルを取り込みます — 各 AI コーディングツールには固有のスキル探索パスがありClaude Code は `.claude/skills/`、Cursor は `.cursor/skills/`、Antigravity は `.agents/skills/` などを使用、Multica が正しい場所にファイルを自動的に配置します。**ただし、3 つのツールGemini、Hermes、OpenClawは現在、汎用のフォールバックパス `.agent_context/skills/` を使用しており、これらのツールが実際にそのパスからスキルを読み込むかどうかはツール自体に依存します。** 完全なパスマッピングと、ネイティブ探索とフォールバックの区別は [AI コーディングツール比較 → スキルファイルが置かれる場所](/providers#where-skill-files-go)にあります。
スキルの内容を編集した後は、**新しく作成されたタスクだけが新しいバージョンを取り込みます** — すでに実行中のタスクは以前のスキルをそのまま使い続けます。
## サードパーティスキルの安全性
GitHub や ClawHub からインポートしたスキルには、スクリプトや実行可能なコンテンツが含まれることがあります。Multica 自体はそれらを**署名も、監査も、サンドボックス化もしません** — スキルの内容はそのまま対応する AI コーディングツールに渡され、ツールがそれを実行可能なものとして扱うかどうかはツール次第です。
<Callout type="warning">
**サードパーティスキルをインポートする前に、`SKILL.md` と同梱されるすべてのファイルを確認してください。**
2026 年 2 月に発生した「ClawHavoc」事件では、人気のスキルパックに仕込まれた悪意ある指示が、影響を受けたユーザーの API キーを盗み出しました。ClawHub はその後 VirusTotal スキャンを追加しましたが、**自動スキャンはあなた自身の確認の代わりにはなりません。**
**信頼できるソースからのみインポートしてください。** 機密データが関わるプロジェクトでは、自分で書いたローカルスキルだけを使うことを検討してください。
</Callout>
## スキルと MCP
どちらもエージェントができることを拡張しますが、方向が異なります。
- **スキル** = 構造化された**ナレッジパック**(静的なコンテンツ + 指示)。エージェントはスキルを読んで「問題 X を見たら、こう考えてこう行動する」を学びます。
- **MCP**Model Context Protocol= **ツールチャネル**。エージェントは MCP を使って外部サービス(データベース、ファイルシステム、サードパーティ APIに接続し、それらを**呼び出します**。
この 2 つは相互補完的です。現在の Multica では、MCP のサポートを**実際に使うのは Claude Code だけ**です — 他のツールは MCP 設定を受け取りはしますが、実際には使いません。MCP 専用のセクションは今後のリリースで追加される予定です。
---
これで、エージェントとは何か、どう作るか、スキルをどう取り付けるかが分かりました。次の問いはこれです。**エージェントは実際にどこで実行され、なぜ自分のエージェントはときどき止まってしまうのか?** 次の章では実行アーキテクチャ — デーモン、ランタイム、そしてタスクがどう連携するか — を扱います。
## 次のステップ
- [デーモンとランタイム](/daemon-runtimes) — エージェントが実際に実行される場所、そしてオンラインとオフラインの見分け方
- [タスクの実行](/tasks) — 1 回の「エージェント作業セッション」の全ライフサイクル
- [AI コーディングツール比較](/providers) — 12 ツール全体の比較(各ツールのスキル注入パスを含む)

View File

@@ -0,0 +1,136 @@
---
title: スクワッド
description: "スクワッドは、1 人の指定されたリーダーエージェントが率いるエージェント(そして任意で人間のメンバー)のグループです。スクワッドにイシューを割り当てると、リーダーが誰が引き受けるかを決定します。"
---
import { Callout } from "fumadocs-ui/components/callout";
スクワッドは、1 人の指定された**リーダーエージェント**を擁する、**[エージェント](/agents)と人間の[メンバー](/members-roles)の名前付きグループ**です。スクワッド自体が一級の担当者です。どの **Assignee** ピッカーからでもスクワッドを選ぶと、リーダーがトリガーを受け取り、イシューを読んだ上で、その作業に最も適したスクワッドメンバーを `@` でメンションします。スクワッドを使えば、専門家を一度組み立てておいて、**名前ではなくトピックで**作業を割り振れます — チームが大きくなっても、ルーティングはそのまま維持されます。
## スクワッドの動作原理
- **リーダー 1 人、メンバー多数。** リーダーは必ずエージェントでなければならず、メンバーはエージェントでも人間のメンバーでも構いません。リーダーだけのスクワッドも許可されますリーダーブリーフィングに「no other members」と表示されます。同じエージェントが複数のスクワッドに所属することもできます。
- **人を選べるあらゆる場所で割り当て可能。** スクワッドは Assignee ピッカー、@メンションピッカー、クイック作成モーダルに表示されます — エージェントやメンバーを選べる場所ならどこでも、スクワッドを選べます。
- **アーカイブによるソフト削除。** スクワッドをアーカイブすると、ピッカーや一覧から消えます。現在そのスクワッドに割り当てられているイシューはすべて**リーダーエージェントに移管され**、作業が途切れないようにします。アーカイブされたスクワッドに新しいイシューを割り当てることはできません。
## スクワッドと単一エージェントのどちらを使うか
| スクワッドを選ぶ場合… | 単一エージェントを選ぶ場合… |
|---|---|
| 複数の専門家がいるが、このイシューに誰が合うか事前にわからないとき | 作業の範囲が 1 つの専門分野に明確で、誰がやるべきかわかっているとき |
| 実際の応答者はイシューごとに変わっても、担当者(スクワッド)は安定して保ちたいとき | イシューにエージェントの名前を残し、明確な個人の説明責任を持たせたいとき |
| コメントで `@FrontendTeam` のようなルーティング先がほしいとき | 一対一の `@agent-name` だけで十分なとき |
スクワッドは能力を加えません。**ルーティング**を加えます。メンバーは依然として普通のエージェントであり、リーダーの唯一の役割は適切な人を選ぶことです。
## 権限
| 操作 | 実行できる人 |
|---|---|
| スクワッドの作成 / 更新 / アーカイブ | ワークスペースの **owner** または **admin** |
| メンバーの追加・削除、ロールの変更 | ワークスペースの **owner** または **admin** |
| スクワッドにイシューを割り当て | すべてのワークスペースメンバー(エージェントへの割り当てと同じ) |
| コメントでスクワッドを `@` でメンション | すべてのワークスペースメンバー |
| スクワッドリーダーの評価を記録 | スクワッドリーダーエージェントのみCLI 経由) |
完全なロールマトリクスは[メンバーとロール](/members-roles)にあります。
## スクワッドを作成する
サイドバーで **スクワッド → 新しいスクワッド** を開き、次を入力してください。
- **名前Name** — 例: `Frontend Team`、`Bug Triage`。ワークスペース内で一意である必要はありません。
- **説明Description、任意** — スクワッドカードと詳細ページに表示される短い紹介文。
- **リーダーLeader** — 既存のエージェントを選びます。リーダーは `leader` ロールで自動的にスクワッドに追加されます。
作成後、スクワッドの詳細ページを開いて次を行えます。
- **メンバーを追加** — エージェントや人間のメンバーを選び、任意で各自に短いロールの説明(例: 「owns the migrations」、「reviewer of last resort」を付けます。リーダーは誰に委任するかを決めるときにこれらのロールを使います。
- **指示を書く** — リーダーが実行のたびに見るスクワッドレベルのガイダンスです(詳しくは後述)。
- **アバターを設定** — エージェントに使うのと同じピッカーから選びます。
CLI での同等のコマンド:
```bash
multica squad create --name "Frontend Team" --leader frontend-lead-agent
multica squad member add <squad-id> --member-id <agent-or-user-uuid> --type agent --role "Owns Tailwind / shadcn surface"
```
## スクワッドに割り当てられたイシューの実行方法
Backlog でないイシューがスクワッドに割り当てられると、Multica はただちに**リーダーエージェント**のための `task` をキューに入れます(すべてのメンバーのためではありません)。その後のフローは次のようになります。
1. **リーダーがタスクを引き受けます。** エージェントランタイムが次のポーリングでタスクを引き受けます。これは他のエージェント割り当てと同じです。
2. **リーダーがブリーフィングを受けます。** 引き受けた時点で、Multica はリーダーのシステムプロンプトに 3 つのセクションを追記します — 下記の[リーダーが毎ターン見る内容](#what-the-leader-sees-on-every-turn)を参照してください。
3. **リーダーが 1 つの委任コメントを投稿します。** そのコメントは、名簿rosterにある正確なメンションマークダウンを使って、選んだメンバーを `@` でメンションします。このメンションが、メンションされた各エージェントのための新しい `task` をトリガーします。
4. **リーダーが評価を記録します** — `multica squad activity <issue-id> action --reason "..."` を通じて記録します。これはイシューのアクティビティタイムラインにエントリを書き込み、リーダーが実際にトリガーを評価したことを人が確認できるようにします。
5. **リーダーが停止します。** リーダーは実装作業を自分では行いません。委任されたメンバーが返信を投稿すると、リーダーが再びトリガーされて更新を読み、次のステップを委任するか、エスカレーションするか、沈黙を保ちます。
イシューが **Backlog** の状態であれば、リーダーはトリガーされません — Backlog は駐車場であり、エージェントへ直接割り当てる場合と同じルールが適用されます。
### リーダーが毎ターン見る内容
スクワッドリーダーが実行されるたびに、3 つのブロックがリーダーの指示に追記されます。
- **Squad Operating Protocol** — ハードコードされたルール集です: イシューを読み、`@` メンションで委任し、簡潔に(イシュー本文を繰り返さない — 担当者が自分で読めます)書き、毎ターン評価を記録し、**ディスパッチ後に停止する**。このプロトコルはシステムが管理しており、編集できません。
- **Squad Roster** — リーダー自身の行と、アーカイブされていないメンバーごとに 1 行ずつで構成されます。各行には、リーダーが貼り付けるべき正確なメンションマークダウン(`[@Name](mention://agent/<uuid>)` または `[@Name](mention://member/<uuid>)`)が含まれています — 単なるテキストの `@name` を入力しても誰もトリガーされません。
- **Squad Instructions** — このスクワッドのためのカスタムガイダンスです(スクワッドの詳細ページで設定するか、`multica squad update --instructions` で設定。ルーティングルール「DB 作業は Alice に、フロントエンドは Bob に」)、エスカレーションポリシー、その他イシュー自体にはない、リーダーが知っておくべき事柄を書くのに使ってください。
## リーダーが再トリガーされる場合
最初のディスパッチの後、リーダーはイシューの**ほとんどの後続コメント**によって自動的に起こされます。正確なルールは次のとおりです。
| イベント | リーダーがトリガーされるか? |
|---|---|
| 非メンバー(人間のレポーター、外部エージェント)がコメントを投稿 | **はい** |
| スクワッドメンバーが `@mention` なしで進捗の更新を投稿 | **はい** — リーダーが次のステップが必要かどうかを再評価します |
| 誰かが別のエージェント / メンバー / スクワッド / `@all` を明示的に `@` メンションするコメントを投稿 | **いいえ** — 明示的な `@` がルーティングシグナルであり、リーダーは身を引きます |
| リーダー自身のコメント(自己トリガー) | **いいえ** — ループを防ぐためにガードされています |
| イシューの相互参照(`[MUL-123](mention://issue/...)`)のみを含むコメント | **はい** — イシュー参照はルーティングではありません |
これらのルールの上に重複排除が適用されます。リーダーがこのイシューにすでに `queued` または `dispatched` 状態のタスクを持っている場合、新しいトリガーが重複したタスクをキューに入れることはありません。
<Callout type="info">
**メンバーが `@` メンションを投稿したときにリーダーがトリガーされない理由。** スクワッドメンバーが誰かを直接 `@` したら、そのコメントは意図的な引き継ぎです — リーダーを起こしてルーティングを「観察」させても、何もしないターンを生み出してタイムラインを散らかすだけです。エージェントが書いたコメントは例外です。あるエージェントが別のエージェントを `@` する結果を投稿すると、リーダーは依然として起き上がり、スレッドを調整できます。
</Callout>
## コメントでスクワッドを `@` でメンションする
スクワッドはメンバーやエージェントと並んで `@` ピッカーに表示されます。スクワッドをメンションすると `[@SquadName](mention://squad/<uuid>)` が挿入され、イシューをスクワッドに割り当てたかのように**スクワッドリーダー**をトリガーします — ただし担当者やステータスは変わりません。現在の所有者をそのまま保ちながら、スクワッドに質問やサブタスクを担当する人を選ばせたいときに使ってください。
同じアンチループのルールが適用されます。リーダーは自分自身をスキップし、同じコメント内に明示的なメンバーの `@` メンションがあれば、そのメンバーに直接ルーティングされます。
## スクワッドの再割り当てまたはアーカイブ
**イシューをスクワッドから別の担当者に再割り当てする**のは、他のあらゆる担当者変更と同じように動作します。イシューのアクティブなタスク(リーダーのものを含む)がすべてキャンセルされ、新しい担当者(エージェント、メンバー、または別のスクワッド)がキューに入ります。「担当者を変えずにスクワッドだけを外す」という別個の操作はありません。別の担当者を選んでください。
**スクワッドのアーカイブ**`multica squad delete <id>`、または詳細ページの Archive ボタン):
1. **現在スクワッドに割り当てられているイシューをリーダーエージェントに移管し**、作業が途切れる代わりに具体的なエージェントを相手に継続するようにします。
2. スクワッドに `archived_at` / `archived_by` を記録します。行は保存されるため過去のアクティビティエントリは引き続き解決されますが、スクワッドは一覧、ピッカー、@メンションのドロップダウンから消えます。
3. このスクワッドへの**今後の割り当てを拒否**し、`cannot assign to an archived squad` を返します。
現在アーカイブ解除のコマンドはありません。ルーティングを復活させる必要がある場合は、新しいスクワッドを作成してください。
## CLI からのスクワッド操作
| コマンド | 用途 |
|---|---|
| `multica squad list` | ワークスペースのスクワッド一覧を表示 |
| `multica squad get <id>` | 1 つのスクワッドの名前、リーダー、説明、指示を表示 |
| `multica squad create --name "..." --leader <agent>` | スクワッドを作成owner / admin |
| `multica squad update <id> [--name X] [--description X] [--instructions X] [--leader Y] [--avatar-url Z]` | 1 つ以上のフィールドを更新 |
| `multica squad delete <id>` | アーカイブ(ソフト削除) — 割り当てられたイシューをリーダーに移管 |
| `multica squad member list <id>` | スクワッドのメンバー一覧を表示 |
| `multica squad member add <id> --member-id <uuid> --type agent\|member [--role "..."]` | メンバーを追加owner / admin |
| `multica squad member remove <id> --member-id <uuid> --type agent\|member` | メンバーを削除(リーダーは削除できません — 先にリーダーを変更してください) |
| `multica squad activity <issue-id> <action\|no_action\|failed> --reason "..."` | リーダーエージェントが毎ターン終了時に記録 |
`--leader` はエージェント名または UUID を受け付けます。それ以外の ID は `multica agent list --output json`、`multica workspace member list --output json`、`multica squad list --output json` から取得します。
## 次に
- [エージェントにイシューを割り当てる](/assigning-issues) — 同じフローで、スクワッド担当者にも適用されます
- [コメントでエージェントを `@` でメンションする](/mentioning-agents) — `@` ピッカーにはスクワッドも表示されます
- [エージェント](/agents) — エージェントとは何か、すべてのスクワッドの構成要素
- [メンバーとロール](/members-roles) — owner / admin / member の完全な権限マトリクス

View File

@@ -0,0 +1,117 @@
---
title: タスク
description: すべてのエージェント実行の作業単位であり、明確なステートマシン、タイムアウト、リトライルールを備えています。
---
import { Callout } from "fumadocs-ui/components/callout";
import { Mermaid } from "@/components/mermaid";
**タスク**はすべての[エージェント](/agents)実行の単位です — [エージェントへのイシューの割り当て](/assigning-issues)、[コメントでのエージェントの @-メンション](/mentioning-agents)、[チャット](/chat)でのメッセージ送信、または[オートパイロット](/autopilots)が予定時刻に発火することは、いずれもタスクを生成します。Multica はそれをキューに入れ、[デーモン](/daemon-runtimes)が取得して対応する [AI コーディングツール](/providers)に引き渡し、完了するとその結果をサーバーに書き戻します。
タスクと[イシュー](/issues)は異なる 2 つのオブジェクトです。1 つのイシューは何度も割り当てられたり、@-メンションされたり、手動で再実行されたりでき — そのたびに**新しい**タスクが生成されます。
## タスクが経るステート
<Mermaid chart={`
graph LR
Q["Queued<br/>queued"] -->|daemon picks up| D["Dispatched<br/>dispatched"]
D -->|agent starts| R["Running<br/>running"]
R -->|success| C["Completed<br/>completed"]
R -->|error or timeout| F["Failed<br/>failed"]
Q -->|user cancels| X["Cancelled<br/>cancelled"]
D -->|user cancels| X
R -->|user cancels| X
F -.retryable reason.-> Q
`} />
- **Queuedキュー待ち** — タスクが作成されたばかりで、デーモンが取得するのを待っている状態
- **Dispatchedディスパッチ済み** — デーモンがタスクを占有し、AI コーディングツールを起動中
- **Running実行中** — AI コーディングツールが実際に作業を実行中
- **Completed完了** — 正常に終了し、成果物(コメント、コードコミット、ステータス変更)がサーバーに書き戻されます
- **Failed失敗** — エラーまたはタイムアウトで中断。失敗理由がリトライ可能な場合、タスクは自動的に `queued` 状態に戻り、再試行されます
- **Cancelledキャンセル済み** — ユーザーがキャンセルした場合
## タスクがタイムアウトしたときに起きること
Multica サーバーは 30 秒ごとにスキャンします。2 種類のタイムアウトが失敗を引き起こします。
| 状況 | タイムアウト |
|---|---|
| ディスパッチされたが開始されない(デーモンが取得したが AI ツールを起動しなかった) | **5 分** |
| 実行が長すぎる | **2.5 時間** |
どちらのタイムアウトも失敗理由として `timeout` を使用し、**自動的にリトライされます**(次のセクション)。関連するランタイム欠落チェックについては、[デーモンとランタイム → ランタイムがオフラインとマークされるタイミング](/daemon-runtimes#when-a-runtime-is-marked-offline)を参照してください。
## どの失敗が自動的にリトライされ、どの失敗がされないか
失敗は 2 つのカテゴリに分かれます: **リトライ可能**と**リトライ不可**です。
**リトライ可能**Multica が自動的に再キューイング):
- `runtime_offline` — タスクがディスパッチされた後にデーモンがいなくなった
- `runtime_recovery` — デーモンがクラッシュして再起動し、終わらせなかったタスクを回収した
- `timeout` — ランタイムまたはディスパッチのタイムアウト
**リトライ不可**(タスクは失敗状態のまま):
- `agent_error` — AI コーディングツール自体がエラーを報告したAPI エラー、クォータ超過、内部バグ)。根本的な問題はリトライされません — 無限ループになってしまうためです。
自動リトライにはさらに 2 つの追加条件もあります。
1. **最大 2 回の試行** — オリジナル 1 回 + リトライ 1 回。リトライも失敗した場合は、理由がリトライ可能であってもそれ以上リトライしません。
2. **イシューおよびチャットでトリガーされたタスクのみ** — オートパイロットでトリガーされたタスクは自動的にリトライ**されません**。
<Callout type="warning">
**オートパイロットのタスクは自動的にリトライされません** — 意図された設計です。オートパイロットは独自の発火サイクル(例: 毎日)を持っており、失敗時に自動リトライが起きると次の予定実行と重なってしまいます。失敗後すぐに再実行が必要なら、手動の再実行を使用してください(次のセクション)。
**オートパイロットのタスクが失敗したことを知る方法**: [インボックス](/inbox)に通知が届き、関連するイシューのステータスが `in_progress` から `todo` に戻ります。[オートパイロット](/autopilots)ページでも、オートパイロットごとの最新の実行結果を確認できます。
</Callout>
## 手動の再実行 vs. 自動リトライ
**手動の再実行**は、CLI または API`POST /api/issues/{id}/rerun`)から自分でトリガーするものです。
```bash
multica issue rerun <issue-id>
```
動作:
- デフォルトでは、イシューの**現在のエージェント担当者**を対象とします — 以前のタスクを誰が実行したかに関わらず、再実行が現在の割り当てに従うようにしたいときに便利です。
- 実行ログの特定の行にあるリトライボタンは、その行のタスク ID も一緒に送信するため、再実行は**現在の担当者ではなく、まさにそのタスクを実行したエージェント**を対象とします。これにより、スクワッドワーカー、並列の @-メンションエージェント、または再割り当てによってエージェントが入れ替わった行に対しても、行単位のリトライが意味を持つようになります。
- このイシューに対する対象エージェントのキュー待ちまたは実行中のタスクを**キャンセルします**(ある場合)。同じイシューで他のエージェントが所有するタスク(例: 並列の @-メンション実行)はそのまま残します。
- **まったく新しい**タスクを作成します — オリジナルのタスクが試行回数の上限に達していても、試行回数は 1 にリセットされます。
- **新しいエージェントセッション**を開始します — 以前のセッション ID は**継承されません**。手動の再実行は、以前の成果物が悪かったと判断したことを意味するため、同じ会話を続けると汚染された状態をそのまま再生してしまいます。(一方、自動リトライはセッションを継承します — そのパスは悪い成果物ではなくインフラ障害のためのものです。)
比較:
| 項目 | 自動リトライ | 手動の再実行 |
|---|---|---|
| トリガー | システム、失敗理由に基づく | ユーザー、手動 |
| 上限 | 2 回の試行 | 制限なし |
| 適用できるソース | イシュー、チャット | エージェント担当者があるイシュー |
| 選択されるエージェント | 失敗したタスクと同じエージェント | ソースタスクのエージェントUI 行単位リトライまたはイシューの現在の担当者CLI / task_id なし) |
| セッション継承 | あり(以前のセッションを再開) | なし(新しいセッション) |
## 失敗したタスクがイシューのステータスに与える影響
イシューがエージェントに割り当てられていてトリガーされたタスクが失敗すると(そして自動リトライが成功しないと)、**イシューのステータスが `in_progress` から `todo` に自動的に戻ります** — そのため、ボードを開くと「これはもう一度見る必要がある」とすぐに分かります。[イシューとプロジェクト](/issues)を参照してください。
## タスクが以前のコンテキストから続行できるか
できます — AI コーディングツールがセッション再開をサポートしている限りは。
Multica はタスク中にセッション ID を**2 回**固定します: 開始時に 1 回AI ツールが最初のシステムメッセージを返したとき)、終了時に 1 回完了または失敗時。1 回目はデーモンが実行の途中でクラッシュしても復旧できるようにし、2 回目は次の**自動リトライ**のために予約され、その ID を渡し返すことでエージェントが以前の会話とファイル状態を引き継げるようにします。**手動の再実行は意図的にこのステップをスキップし**、新しいセッションを開始します — [手動の再実行 vs. 自動リトライ](#manual-rerun-vs-automatic-retry)を参照してください。
ただし、**実際にどの AI コーディングツールがこれをサポートするか**は大きく異なります。
- ✅ **実際にサポート** — Antigravity, Claude Code, Copilot, Hermes, Kimi, Kiro CLI, OpenCode, OpenClaw, Pi
- ⚠️ **コードはあるが使用不可** — Codex, Cursor
- ❌ **サポートなし** — Gemini
[プロバイダー対応表 → セッション再開](/providers#session-resumption-who-really-supports-it)を参照してください。
## 次へ
- [プロバイダー対応表](/providers) — 12 個の AI コーディングツール間の機能差(正確なセッション再開の状態を含む)
- [エージェントへのイシューの割り当て](/assigning-issues) / [コメントでのエージェントの @-メンション](/mentioning-agents) / [チャット](/chat) / [オートパイロット](/autopilots) — タスクをトリガーする 4 つの方法

View File

@@ -0,0 +1,279 @@
---
title: トラブルシューティング
description: Multica をセルフホストする際によく遭遇する問題 — 症状、原因、診断方法、解決方法。
---
import { Callout } from "fumadocs-ui/components/callout";
症状から問題を探してください。各項目では**症状 / 考えられる原因 / 診断方法 / 解決方法**を提供します。お使いの状況が一覧にない場合は、[GitHub](https://github.com/multica-ai/multica/issues) にイシューを登録してください。
## デーモンがサーバーに接続できない
**症状**: [`multica daemon`](/cli) の `status` コマンドが `offline` または `connection refused` を表示します。サーバーログに `/api/daemon/register` や `/api/daemon/heartbeat` のリクエストが見当たりません。デーモンの仕組みについては[デーモンとランタイム](/daemon-runtimes)を参照してください。
**考えられる原因**:
1. **`MULTICA_SERVER_URL` が誤ったアドレスを指している** — デフォルト値は `ws://localhost:8080/ws` で、セルフホスト時は自分のサーバーアドレスに変更する必要があります
2. **ネットワーク / ファイアウォールによるブロック** — デーモンとサーバーが同じネットワークにいない、またはアウトバウンドトラフィックがブロックされている
3. **トークンが期限切れまたは無効** — `multica login` を一度も実行していない、または PAT が取り消された
4. **サーバーが登録を拒否した** — ログインしたアカウントが対象のワークスペースに所属していないregister が 403 を返す)
5. **DNS 解決の失敗** — デーモンのマシンでホスト名が解決されない
**診断方法**:
```bash
multica daemon logs --lines 100 # look for daemon-side errors
echo $MULTICA_SERVER_URL # confirm the address is set
curl -i http://<server-host>:8080/health # hit the server directly
curl -i http://<server-host>:8080/readyz # include DB + migration readiness
cat ~/.multica/config.json # verify api_token exists
multica workspace list # confirm you're a member of the target workspace
```
**解決方法**: 上記の各原因を 1 つずつ対処してください。最もよくある 2 つの解決策は、**`MULTICA_SERVER_URL` を変更してデーモンを再起動する**こと(`multica daemon restart`)と、**ログインし直す**こと(`multica logout && multica login`)です。
## タスクが `queued` で止まる
**症状**: エージェントにイシューを割り当てた後、イシューの状態はすぐに `in_progress` に変わりますが、長時間経ってもページにエージェント実行の兆候が見えません。`multica daemon status` はデーモンを `online` と表示しています。
**考えられる原因**(頻度順):
1. **エージェントの同時実行上限に到達** — このエージェントの `max_concurrent_tasks`(デフォルト 6が、他の実行中タスクですでに埋まっている
2. **同じイシューで同じエージェントの別タスクがまだ実行中** — 同じエージェント × 同じイシューは順次実行が強制されます(重複実行の防止)
3. **エージェントがアーカイブされている** — アーカイブ後も新しいタスクはキューに入りますが、クレームできず、5 分後にタイムアウトしますcode-issue G-01
4. **デーモンが現在のワークスペースにこのランタイムを登録していない** — デーモンを再起動するか、UI でランタイムを選択し直してください
5. **デーモンの接続が切れた** — 直近 45 秒間ハートビートがありません。`daemon status` が `online` と表示されるのは、ごく最近切断された状態を反映している可能性があります
**診断方法**:
```bash
multica daemon status --output json # runtime list + last_seen_at
multica agent list # check agent archived state
multica issue show <issue-id> # inspect task history
```
サーバー側(セルフホスト)では、`"no_tasks"` / `"no_capacity"` を grep してクレームの結果を確認できます。
**解決方法**:
- 同時実行が満杯 → 実行中のタスクが終わるのを待つか、`multica agent update <id> --max-concurrent-tasks 10` で上限を引き上げてください
- 同一イシューの順次実行 → 前のタスクが終わるのを待つか、別のエージェントに割り当て直してください
- エージェントがアーカイブされている → `multica agent restore <id>`
- ランタイム未登録 → `multica daemon restart` するとデーモンが再登録します
## WebSocket が接続できない
**症状**: ブラウザのコンソールに `WebSocket is closed` が記録されます。ページにリアルタイム更新(タスクの進捗、コメント、インボックス)が表示されず、再読み込みしないと見えません。バックエンドのタスクは引き続き実行されます。
**考えられる原因**:
1. **Origin チェックの失敗** — フロントエンドのドメインがサーバーの CORS 許可リストにありません。デフォルトの許可リストには `localhost:3000/5173/5174` のみが含まれ、公開インターネットでセルフホストするには `FRONTEND_ORIGIN` が必要です
2. **プロトコルの不一致** — `https://` のフロントエンドには `wss://` が必要で、HTTP は `ws://` を使います
3. **リバースプロキシが WebSocket アップグレードを有効にしていない** — Nginx / Envoy / HAProxy はデフォルトでは `Upgrade` ヘッダーを転送しません
4. **JWT クッキーの期限切れまたは欠落** — 30 日の有効期限後にログインし直していない
**診断方法**:
- ブラウザの DevTools → Network → 「WS」でフィルタリングし、接続状態とステータスコードを確認してください
- サーバーログで `"rejected origin"` / `"websocket"` を grep してください — origin の問題であれば明示的に表示されます
- `curl -i http://<server-host>:8080/ws` は(`Upgrade` ヘッダー付きで)`101 Switching Protocols` を返すはずです
**解決方法**:
- Origin エラー → サーバーの `.env` に `FRONTEND_ORIGIN=https://multica.yourdomain.com` を設定(またはカンマ区切りの `CORS_ALLOWED_ORIGINS`)し、サーバーを再起動してください
- プロトコルの不一致 → `FRONTEND_ORIGIN` のプロトコルがフロントエンドと一致しているか確認してください
- リバースプロキシ → Nginx に `proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";` を追加してください
- クッキーの期限切れ → ページを再読み込みしてログインし直してください
## メールが届かない
**症状**: ログインまたは招待の受諾中にメールアドレスを送信したのに、インボックスにもスパムフォルダにも認証コードがありません。
**まず、サーバーがどのプロバイダーをアクティブと認識しているかを確認してください。** 起動時にバックエンドは次のいずれかを出力します。
- `EmailService: SMTP relay <host>:<port> from=<addr>` — SMTP を使用(`SMTP_HOST` が空でなければ Resend より優先)
- `EmailService: Resend API from=<addr>` — Resend を使用
- `EmailService: DEV mode — codes printed to stdout …` — プロバイダーが構成されていない
```bash
docker compose -f docker-compose.selfhost.yml logs backend | grep "EmailService:"
```
期待していた行が見当たらない場合は、環境変数がプロセスに届いていません。`.env` と `docker compose -f docker-compose.selfhost.yml exec backend env | grep -E 'RESEND_|SMTP_'` を確認してください。この起動ログの行には認証情報は一切記録されません。
### Resend がアクティブなプロバイダーの場合
**考えられる原因**:
1. **`RESEND_API_KEY` が設定されていない** — サーバーは静かにフォールバックし、エラーを出さずに**コードを自身の stdout に書き込みます**。プロダクションで陥りやすい落とし穴です
2. **Resend API キーが無効、またはクォータ超過** — サーバーログに `"failed to send verification code"` が表示されます
3. **`RESEND_FROM_EMAIL` のドメインが Resend で検証されていない** — Resend が送信を拒否します
4. **メールは送信されたが受信者の ISP にスパムと判定された** — Resend ダッシュボードとスパムフォルダを確認してください
**診断方法**:
- サーバーログで `"[DEV] Verification code for"` を grep してください — これがある場合、Resend が構成されておらず、コードが stdout に書き込まれたことを意味します
- [Resend ダッシュボード](https://resend.com/) → Emails で送信履歴を確認してください
- `RESEND_FROM_EMAIL` のドメインが Resend コンソールの「Verified Domains」リストに表示されるか確認してください
**解決方法**:
- API キーの欠落 → [サインインとサインアップの構成 → メールの仕組み](/auth-setup#how-email--verification-code-sign-in-works)に従って構成し、サーバーを再起動してください
- ドメイン未検証 → Resend コンソールで DNS 検証フローを実行してくださいSPF / DKIM レコードを追加)
- 緊急時(内部テスト)→ サーバーログの `[DEV]` の下に出力されたコードをコピーしてください
### SMTP がアクティブなプロバイダーの場合
SMTP の経路はすべての失敗を失敗した段階とともにラップするため、サーバーログがすでにどの段階で relay がセッションを拒否したかを教えてくれます。`"failed to send verification email"` / `"failed to send invitation email"` を grep し、ラップされたエラーを確認してください。
| 記録されたエラー | 意味 | 解決方法 |
|---|---|---|
| `smtp dial <host>:<port>: dial tcp …: connect: connection refused` / `i/o timeout` | バックエンドコンテナが relay に到達できない — host が誤っている、port が誤っている、ファイアウォール、または relay が待ち受けていない | コンテナ内部から `SMTP_HOST` / `SMTP_PORT` が解決されるか確認してください(`docker compose -f docker-compose.selfhost.yml exec backend nslookup <host>` および `nc -vz <host> <port>`。Multica を実行するホストから relay へのファイアウォールを開放してください |
| `smtp starttls: x509: certificate signed by unknown authority`(または `certificate is not valid for any names` | relay がプライベート CA / 自己署名証明書を使用しており、コンテナの信頼ストアがそれを拒否している | CA をコンテナにインストールするか、relay が信頼できるネットワークセグメント上で到達可能であることを確認したうえでのみ `SMTP_TLS_INSECURE=true` を設定してください |
| `smtp auth: 535 5.7.8 Authentication credentials invalid`(または `534`/`530` | `SMTP_USERNAME` / `SMTP_PASSWORD` が誤っている、または relay が `PLAIN` 以外の認証方式を要求している | メール管理者にサービスアカウントの認証情報を再確認してください。Exchange の匿名内部 relay の場合は両方を空のままにします(`SMTP_USERNAME=`、`SMTP_PASSWORD=` |
| `smtp MAIL FROM: 550 5.7.1 Client does not have permissions to send as this sender` | relay が `RESEND_FROM_EMAIL` をエンベロープ送信者として受け入れない — 典型的な Exchange の「anonymous users not allowed」または DMARC アラインメントの問題 | `RESEND_FROM_EMAIL` を relay が受け入れるドメインに設定してください。Exchange では receive connector で送信元 IP に `ms-Exch-SMTP-Accept-Any-Sender` を付与してください |
| `smtp RCPT TO <addr>: 550 5.7.1 Unable to relay` | relay の receive connector が、あなたのサブネットから外部の受信者への中継を許可していない(外部ドメインと通信する匿名内部 relay で最も多い) | 招待を内部の受信者に制限するか、Multica ホストのサブネットを Exchange の「Anonymous Users → Relay」権限リストに追加してください |
| `smtp DATA` / `smtp write body` / `smtp end data` | セッションは受け入れられたが relay が本文を破棄した — 通常はメッセージサイズ制限、コンテンツフィルタリング、または送信途中の接続リセットが原因 | relay のログで同じ `Message-ID`(ログには `<unixnano>@<host>` 形式)を確認してください。必要であればメッセージサイズの上限を引き上げてください |
`MAIL FROM`、`RCPT TO`、`DATA` のエラーは常に relay の応答コードとともに記録されるため、反対側の Exchange / Postfix のログと突き合わせることができます。認証コードと招待トークンは、ラップされたエラーに**決して**含まれません。
**診断方法**:
- 起動時に `"EmailService: SMTP relay"` を一度 grep し、ランタイムの失敗については `"failed to send"` を grep してください
- バックエンドコンテナ内部から接続性を点検してください: `docker compose -f docker-compose.selfhost.yml exec backend sh -c 'nc -vz $SMTP_HOST $SMTP_PORT'`
- 環境変数がプロセスに届いたか確認してください: `docker compose -f docker-compose.selfhost.yml exec backend env | grep SMTP_`(出力にパスワードが含まれるため、信頼できるシェルでのみ実行してください)
**解決方法**:
- host / port の誤り → `SMTP_HOST` / `SMTP_PORT` を調整してバックエンドを再起動してください。サポートされる relay モードは[認証設定 → Option B: SMTP relay](/auth-setup)を参照してください
- 証明書の不一致 → relay の CA をコンテナにインストールするか、信頼できるネットワークセグメントで一時的に `SMTP_TLS_INSECURE=true` を設定してください
- 認証の失敗 → 認証情報を再確認してください。匿名内部 relay の場合は `SMTP_USERNAME` と `SMTP_PASSWORD` を空のままにしてください
- `Unable to relay` → 内部の受信者に制限するか、Exchange の receive connector で Multica ホストの IP に中継権限を付与してください
## 固定のローカルテストコードが動作しない
**症状**: セルフホストのインスタンスで `888888` のような固定のローカルテストコードでログインしようとしたところ、`invalid or expired code` で拒否されます。
**考えられる原因**(相互に排他的):
1. **`MULTICA_DEV_VERIFICATION_CODE` が空** — 固定コードはデフォルトで無効です
2. **`APP_ENV=production`** — これは**正しい**プロダクション構成です。固定のローカルテストコードはプロダクションでは無視されます
3. **構成されたコードが 6 桁でない** — このショートカットは 6 桁の値のみを受け付けます
**診断方法**:
```bash
cat .env | grep -E 'APP_ENV|MULTICA_DEV_VERIFICATION_CODE'
docker exec <container> env | grep -E 'APP_ENV|MULTICA_DEV_VERIFICATION_CODE'
```
インボックス(スパムを含む)で実際の認証コードを確認してください。
**解決方法**:
- プロダクションでは `MULTICA_DEV_VERIFICATION_CODE` を空のままにし、Resend を構成して実際のコードを使用してください
- ローカル開発や内部テストの場合は、サーバーログから生成されたコードをコピーするか、`APP_ENV=development` と `MULTICA_DEV_VERIFICATION_CODE=888888` を設定してください — 公開インスタンスでは固定コードを絶対に有効にしないでください(詳細は[サインインとサインアップの構成 → 固定のローカルテストコード](/auth-setup#fixed-local-testing-codes)を参照)
## 使用量ダッシュボードが 0 のままになる
**症状**: エージェントはタスクを完了し、生のトークン使用量はデータベースに記録されていますが、**設定 → 使用量**と**設定 → ランタイム**で入力 / 出力 / コストがすべて 0 と表示されます。これは静かに発生する現象で、バックエンドログにエラーはありません。
**考えられる原因**:
1. **`rollup_task_usage_hourly()` が一切スケジュールされていない** — 使用量 / ランタイムのダッシュボードは派生テーブル `task_usage_hourly` から読み取り、このテーブルはその関数によって埋められます。同梱の `pgvector/pgvector:pg17` イメージには `pg_cron` が含まれておらず、バックエンドもプロセス内で rollup を実行しません。外部スケジューラのない新規セルフホストインストールでは、これがデフォルトの状態です。
2. **`pg_cron` はインストールされているが誤ったデータベースを指している** — `pg_cron.database_name` のデフォルト値は `postgres` です。Multica のデータベース名が異なる場合、スケジュールされたジョブは `rollup_task_usage_hourly()` を一切見つけられません。
3. **スケジューラは動作しているが rollup が静かにエラーを出している** — 例えば cron エントリ内部の DB ロール / search_path が誤っている。
**診断方法**:
```sql
-- Confirm raw events exist but the hourly table is empty.
SELECT count(*) AS raw_rows FROM task_usage;
SELECT count(*) AS hourly_rows FROM task_usage_hourly;
-- Confirm pg_cron is (or isn't) available.
SELECT * FROM pg_available_extensions WHERE name = 'pg_cron';
SHOW shared_preload_libraries;
-- If pg_cron is installed, check the schedule + last run.
SELECT jobname, schedule, database, active FROM cron.job;
SELECT jobname, status, return_message, start_time, end_time
FROM cron.job_run_details ORDER BY start_time DESC LIMIT 10;
-- Watermark — if this is 1970-01-01, the rollup has never run.
SELECT watermark_at FROM task_usage_hourly_rollup_state;
```
**解決方法**:
- rollup を手動で一度呼び出して動作するか確認してください: `SELECT rollup_task_usage_hourly();` — ダッシュボードを再読み込みしてください。数値が表示されれば、欠けているのはスケジューラだけです。
- [セルフホストクイックスタート → 使用量 rollup のスケジューリング](/self-host-quickstart#7-schedule-the-usage-rollup-required-for-the-usage-dashboard)からサポートされる方式のいずれかを選んでください: 外部 cron / systemd-timer / Kubernetes CronJob、または Postgres を `pg_cron` を含むイメージに置き換える。
- スケジュール設定より前の履歴がすでにある場合は、バックエンドコンテナ内部で `backfill_task_usage_hourly` を実行し、ウォーターマーク以前のバケットを埋めてください。
## マイグレーション `103` が `refusing to drop legacy daily rollups` で失敗する
**症状**: `v0.3.4` から `v0.3.5+` にアップグレードする際、バックエンドコンテナが起動しない(または `migrate up` が中断する)とともに、次のエラーが発生します。
```text
ERROR: refusing to drop legacy daily rollups:
task_usage_hourly_rollup_state.watermark_at (1970-01-01 ...) trails
task_usage latest event (...) by more than 01:00:00 — backfill is
incomplete or pg_cron is not running. Run cmd/backfill_task_usage_hourly
(and let pg_cron catch up) before re-running migrate
```
**考えられる原因**: これはマイグレーション `103` の fail-closed ガードです。`task_usage_hourly` が生の `task_usage` に追いつくまで、レガシーの daily rollup の削除を拒否します。既存の行が存在し、rollup のウォーターマークがまだ epoch に留まっているとき — つまり、まだどの履歴も hourly テーブルに rollup されていないとき — にこのガードが発動します。
**解決方法**:
1. 同じデータベースに対して backfill を実行してください(冪等であり、中断しても安全で、再実行しても安全です):
```bash
# Docker Compose
docker compose -f docker-compose.selfhost.yml exec backend \
./backfill_task_usage_hourly --sleep-between-slices=2s
# Kubernetes
kubectl -n multica exec deploy/multica-backend -- \
./backfill_task_usage_hourly --sleep-between-slices=2s
```
2. アップグレードを再実行してください — バックエンドコンテナを再起動するだけで十分で、マイグレーションは起動時に実行されます。これでガードが最新のウォーターマークを確認し、`103` の適用を許可します。
3. ウォーターマークが進み続けるように、継続的な rollup スケジュールcron / `pg_cron`)を設定してください — [セルフホストクイックスタート → 使用量 rollup のスケジューリング](/self-host-quickstart#7-schedule-the-usage-rollup-required-for-the-usage-dashboard)を参照してください。
`--sleep-between-slices=2s` は、数年分の履歴を持つプロダクションデータベースにとって控えめなデフォルト値です。直近 N か月のみを保持し、それより古いバケットを永久に放棄してもかまわない場合は `--months-back N --force-partial` を使用してください。
## ポートの競合
**症状**: `multica server` や `multica daemon start` が `address already in use` で失敗します。
**考えられる原因**:
1. **サーバーポートが使用中**(デフォルト `8080`
2. **デーモンの health ポートが使用中**(デフォルト `19514`、プロファイルごとにハッシュでオフセット)
3. **Web 開発サーバーのポート競合**`3000` / `5173`
4. **ポートに対する権限不足**`< 1024` の特権ポートのバインドには sudo が必要)
**診断方法**:
```bash
lsof -i :8080 # macOS / Linux
netstat -ano | findstr :8080 # Windows
```
**解決方法**:
- 競合しているプロセスを終了する(`kill -9 <PID>`)か、`PORT=9000` でポートを変更してください
- 80 / 443 を使うには → 直接バインドせず、前段にリバースプロキシNginx / Caddyを置いて高位ポートへ転送してください
## ログの場所
| 構成要素 | 場所 | コマンド |
|---|---|---|
| **デーモン** | `~/.multica/daemon.log`(バックグラウンドモード)またはフォアグラウンドの stdout | `multica daemon logs -f --lines 100` |
| **サーバーDocker** | コンテナの stdout | `docker logs -f <container>` |
| **サーバーsystemd** | journal | `journalctl -u multica-server -f` |
| **フロントエンドdev** | `pnpm dev` を実行中のターミナル | 直接確認 |
| **フロントエンド(ブラウザ)** | DevTools → Console | `F12` を押す |
より詳細なデーモンログが必要な場合は、デーモンをバックグラウンドからフォアグラウンドに移してください: `multica daemon stop && multica daemon start --foreground`。

View File

@@ -0,0 +1,56 @@
---
title: ワークスペース
description: ワークスペースはグループが協働する独立した空間で、すべてのイシュー、メンバー、コメント、エージェントが 1 つのワークスペースに属します。
---
import { Callout } from "fumadocs-ui/components/callout";
ワークスペースは **Multica でグループが協働する独立した空間**で、すべての[イシュー](/issues)、[メンバー](/members-roles)、[コメント](/comments)、[エージェント](/agents)が 1 つのワークスペースに属します。ログイン後に表示されるイシュー一覧、メンバー名簿、エージェント設定はすべて現在のワークスペースに限定されており、**ワークスペースを切り替えると画面全体が入れ替わります**。
## ワークスペースの作成
ワークスペースを作成するとき、3 つのことが決まります。
- **ワークスペース名** — メンバーに表示される表示名です。空白や非 ASCII 文字を使用できます。後から変更できます。
- **Slug** — ワークスペース URL に使われる文字列です。小文字と数字のみが使用でき(`-` で連結)、**作成後は変更できないため**、慎重に選んでください。slug がすでに使用中だったり、システム予約語と重なったりする場合、作成画面で別の値を選ぶよう求められます。
- **イシュー接頭辞** — ワークスペース内のすべてのイシュー番号の接頭辞です(`MUL-123` の `MUL`)。大文字と数字のみが使用でき、最大 10 文字です。
<Callout type="warning">
**イシュー接頭辞は変更しないでください。** イシュー番号は現在の接頭辞でレンダリングされるため、接頭辞を変更すると `MUL-5` がただちに `NEW-5` になります。すべての外部リンク、Slack のメンション、コメント内の過去の参照が古い番号と合わなくなります。イシュー接頭辞は「作成時に決め、決して触らない」値として扱ってください。
</Callout>
ワークスペースは Web UI から作成することも、コマンドラインから作成することもできます。
```bash
multica workspace create
```
## イシュー番号
ワークスペースで作成されるすべてのイシューには、`<接頭辞>-<数字>` 形式の番号が自動的に割り当てられます — `MUL-1`、`MUL-2`、`MUL-3`。いくつかの特性は次のとおりです。
- **ワークスペース内で連番かつ一意** — 各ワークスペースは独自のカウンターを保持し、ワークスペース同士は互いに干渉しません。
- **手動で指定できない** — イシューを作成するときはタイトルのみを入力し、番号はシステムが割り当てます。
- **削除しても再利用されない** — `MUL-5` を削除しても、次の新しいイシューは `MUL-5` ではなく `MUL-6` です。
## ワークスペースの削除
ワークスペースの owner のみが、ワークスペース全体を削除できます。削除は**取り消せません**。
<Callout type="warning">
ワークスペースを削除すると、次の項目が一度にすべて消去されます。
- すべてのイシュー、プロジェクト、コメント、リアクション
- すべての添付ファイル
- すべてのメンバーシップと保留中の招待
- すべてのエージェント設定とそのタスク履歴
**データは復旧できません。** 削除する前に、保管しておきたい項目をエクスポートしてください。
</Callout>
ワークスペースの最後の owner であり、そのワークスペースから手を引きたい場合は、まず owner の役割を別のメンバーに移譲したうえで、新しい ownerまたは本人が削除するかどうかを決定するようにしてください。[メンバーと役割](/members-roles)を参照してください。
## 次へ
- [メンバーと役割](/members-roles) — ワークスペースに人を追加する方法と、3 つの役割がそれぞれ何をできるか
- [イシューとプロジェクト](/issues) — ワークスペース内部の中核となる作業オブジェクト

View File

@@ -1,11 +1,11 @@
import { defineI18n } from "fumadocs-core/i18n";
// English is the default; Chinese (/zh/) and Korean (/ko/) are available.
// hideLocale: 'default-locale' keeps English URLs prefix-free
// English is the default; Chinese (/zh/), Korean (/ko/), and Japanese (/ja/)
// are available. hideLocale: 'default-locale' keeps English URLs prefix-free
// (`/docs/`) while translated locales live under `/docs/<lang>/...`.
// parser: 'dot' picks up `page.zh.mdx` / `page.ko.mdx` and `meta.<lang>.json`.
// parser: 'dot' picks up `page.zh.mdx` / `page.ko.mdx` / `page.ja.mdx` and `meta.<lang>.json`.
export const i18n = defineI18n({
languages: ["en", "zh", "ko"],
languages: ["en", "zh", "ko", "ja"],
defaultLanguage: "en",
hideLocale: "default-locale",
parser: "dot",

View File

@@ -5,6 +5,7 @@ describe("prefixLocale", () => {
it("prefixes root-relative paths with the active non-default locale", () => {
expect(prefixLocale("/workspaces", "zh")).toBe("/zh/workspaces");
expect(prefixLocale("/workspaces", "ko")).toBe("/ko/workspaces");
expect(prefixLocale("/workspaces", "ja")).toBe("/ja/workspaces");
expect(prefixLocale("/agents-create", "zh")).toBe("/zh/agents-create");
});
@@ -30,6 +31,7 @@ describe("prefixLocale", () => {
expect(prefixLocale("/zh/workspaces", "zh")).toBe("/zh/workspaces");
expect(prefixLocale("/en/workspaces", "zh")).toBe("/en/workspaces");
expect(prefixLocale("/ko/workspaces", "zh")).toBe("/ko/workspaces");
expect(prefixLocale("/ja/workspaces", "zh")).toBe("/ja/workspaces");
});
it("leaves external URLs alone", () => {

View File

@@ -13,9 +13,11 @@ const pages = new Map<string, { url: string }>([
["en:", { url: "/" }],
["zh:", { url: "/zh" }],
["ko:", { url: "/ko" }],
["ja:", { url: "/ja" }],
["en:agents", { url: "/agents" }],
["zh:agents", { url: "/zh/agents" }],
["ko:agents", { url: "/ko/agents" }],
["ja:agents", { url: "/ja/agents" }],
]);
vi.mock("@/lib/source", () => ({
@@ -69,6 +71,21 @@ describe("docsAlternates", () => {
});
});
it("includes Japanese hreflang when a real *.ja.mdx page exists", async () => {
existingDocs.add("agents.ja.mdx");
const { docsAlternates } = await import("./site");
expect(docsAlternates(["agents"])).toEqual({
canonical: "https://www.multica.ai/docs/agents",
languages: {
en: "https://www.multica.ai/docs/agents",
zh: "https://www.multica.ai/docs/zh/agents",
ja: "https://www.multica.ai/docs/ja/agents",
"x-default": "https://www.multica.ai/docs/agents",
},
});
});
it("keeps the locale root alternates limited to real localized MDX pages", async () => {
const { docsAlternates } = await import("./site");

View File

@@ -19,6 +19,8 @@ describe("docsSlugStaticParams", () => {
{ lang: "zh", slug: ["agents"] },
{ lang: "ko", slug: ["agents"] },
{ lang: "ko", slug: ["cli", "reference"] },
{ lang: "ja", slug: ["agents"] },
{ lang: "ja", slug: ["cli", "reference"] },
];
expect(docsSlugStaticParams(params)).toEqual([
@@ -27,6 +29,8 @@ describe("docsSlugStaticParams", () => {
{ lang: "zh", slug: ["agents"] },
{ lang: "ko", slug: ["agents"] },
{ lang: "ko", slug: ["cli", "reference"] },
{ lang: "ja", slug: ["agents"] },
{ lang: "ja", slug: ["cli", "reference"] },
]);
});

View File

@@ -28,6 +28,18 @@ export const uiTranslations: Partial<Record<Lang, Partial<Translations>>> = {
chooseTheme: "테마 변경",
editOnGithub: "GitHub에서 편집",
},
ja: {
search: "検索",
searchNoResult: "結果が見つかりません",
toc: "このページの内容",
tocNoHeadings: "見出しなし",
lastUpdate: "最終更新",
chooseLanguage: "言語を選択",
nextPage: "次のページ",
previousPage: "前のページ",
chooseTheme: "テーマを変更",
editOnGithub: "GitHub で編集",
},
};
// Display name shown in the LanguageToggle dropdown.
@@ -35,6 +47,7 @@ export const localeLabels: Record<Lang, string> = {
en: "English",
zh: "简体中文",
ko: "한국어",
ja: "日本語",
};
// Copy for the welcome page (Hero + Byline). Pages are translated as MDX;
@@ -58,4 +71,10 @@ export const homeCopy = {
titleAccent: "한곳에서.",
byline: ["시작하기", "2026년 4월 업데이트", "약 6분 읽기"],
},
ja: {
eyebrow: "Multica ドキュメント",
titleLead: "人とエージェントが、",
titleAccent: "一つの場所に。",
byline: ["はじめに", "2026年4月更新", "約6分で読めます"],
},
} as const satisfies Record<Lang, unknown>;

View File

@@ -5,6 +5,7 @@ import { describe, expect, it } from "vitest";
const repoRoot = resolve(process.cwd(), "../..");
const chineseFonts = ["PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC"];
const koreanFonts = ["Apple SD Gothic Neo", "Malgun Gothic", "Noto Sans CJK KR"];
const japaneseFonts = ["Hiragino Sans", "Yu Gothic", "Noto Sans CJK JP"];
function expectChineseFontsBeforeKoreanFonts(source: string) {
const chineseIndexes = chineseFonts.map((font) => source.indexOf(font));
@@ -20,14 +21,41 @@ function expectChineseFontsBeforeKoreanFonts(source: string) {
}
}
// Japanese Kanji share the Han Unicode block with Chinese, so the Korean
// "append after Chinese" tactic would render Japanese with Chinese glyph
// shapes. The Japanese CJK chain must therefore be (a) gated behind a lang
// selector so zh/en keep Chinese-first ordering, and (b) ordered Japanese
// fonts BEFORE the Chinese families inside that scoped stack.
function expectJapaneseScopedOverride(source: string) {
expect(source).toContain('html[lang|="ja"]');
const japaneseIndexes = japaneseFonts.map((font) => source.indexOf(font));
expect(japaneseIndexes).not.toContain(-1);
const firstJapanese = Math.min(...japaneseIndexes);
const lastChinese = Math.max(
...chineseFonts.map((font) => source.lastIndexOf(font)),
);
expect(firstJapanese).toBeLessThan(lastChinese);
}
describe("CJK font fallback order", () => {
it("keeps web Chinese font fallbacks before Korean font fallbacks", () => {
const layoutSource = readFileSync(
resolve(repoRoot, "apps/web/app/layout.tsx"),
const cssSource = readFileSync(
resolve(repoRoot, "apps/web/app/globals.css"),
"utf8",
);
expectChineseFontsBeforeKoreanFonts(layoutSource);
expectChineseFontsBeforeKoreanFonts(cssSource);
});
it("scopes the Japanese-first CJK stack to html[lang|='ja'] (web)", () => {
const cssSource = readFileSync(
resolve(repoRoot, "apps/web/app/globals.css"),
"utf8",
);
expectJapaneseScopedOverride(cssSource);
});
it("keeps desktop Chinese font fallbacks before Korean font fallbacks", () => {
@@ -38,4 +66,13 @@ describe("CJK font fallback order", () => {
expectChineseFontsBeforeKoreanFonts(desktopCss);
});
it("scopes the Japanese-first CJK stack to html[lang|='ja'] (desktop)", () => {
const desktopCss = readFileSync(
resolve(repoRoot, "apps/desktop/src/renderer/src/globals.css"),
"utf8",
);
expectJapaneseScopedOverride(desktopCss);
});
});

View File

@@ -10,3 +10,36 @@
@source "../../../packages/ui/**/*.{ts,tsx}";
@source "../../../packages/core/**/*.{ts,tsx}";
@source "../../../packages/views/**/*.{ts,tsx}";
/* Font stack. `--font-inter` is the next/font Inter family (+ its synthetic
size-adjusted fallback), set on <html> by inter.variable in app/layout.tsx.
We compose `--font-sans` here in static CSS — rather than baking the CJK tail
into next/font's `fallback` — so it can be overridden per `<html lang>` and
stays CSP-safe (no inline <style>). Tailwind's `font-sans` utility resolves
`var(--font-sans)` (see packages/ui/styles/tokens.css `@theme inline`).
Default (en / zh / ko): Latin chars render with Inter; CJK chars fall through
to the platform Chinese fonts, then Korean. Chinese MUST stay before Korean so
zh users never get Korean Hanja glyph shapes (Hangul is a separate Unicode
block, so ko users still get Korean fonts for Hangul). Kept in sync with
apps/desktop/src/renderer/src/globals.css. */
:root {
--font-sans: var(--font-inter), -apple-system, BlinkMacSystemFont, "Segoe UI",
"PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", "Apple SD Gothic Neo",
"Malgun Gothic", "Noto Sans CJK KR", sans-serif;
}
/* Japanese: Kanji are Han ideographs sharing the same Unicode block as Chinese,
and CSS font-fallback order is NOT affected by `<html lang>` — so the
Chinese-first default above would hand Japanese users Chinese glyph shapes
for shared ideographs. Promote a Japanese-first CJK chain only for Japanese.
`[lang|="ja"]` is the BCP-47 language-range selector: it matches exactly `ja`
or `ja-<region>` (layout.tsx emits `ja-JP`), never unrelated 3-letter subtags
such as `jam`. Inter still leads for Latin; zh/ko remain as a deep fallback. */
html[lang|="ja"] {
--font-sans: var(--font-inter), "Hiragino Sans", "Hiragino Kaku Gothic ProN",
"Yu Gothic", "YuGothic", "Meiryo", "Noto Sans CJK JP", "Noto Sans JP",
-apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
"Microsoft YaHei", "Noto Sans CJK SC", "Apple SD Gothic Neo", "Malgun Gothic",
"Noto Sans CJK KR", sans-serif;
}

View File

@@ -9,30 +9,19 @@ import { RESOURCES } from "@multica/views/locales";
import { getRequestLocale } from "@/lib/request-locale";
import "./globals.css";
// Font stack: Inter for Latin UI text + system CJK fonts for localized content.
// Desktop app uses the same stack via apps/desktop/src/renderer/src/globals.css
// keep the CJK fallback tail in sync across both files. The Inter primary family
// differs by design: next/font produces `__Inter_xxx` (with a synthetic size-adjusted
// fallback face to prevent FOUT layout shift); desktop uses fontsource's "Inter Variable".
// Both resolve to Inter glyphs, so rendering is identical in practice.
// Per-character fallback: Latin chars render with Inter, CJK chars render with the
// platform-native Chinese/Korean fallback when needed. Chinese fonts must stay before
// Korean fonts so zh users do not receive Korean Hanja glyph shapes.
// Inter is the Latin UI face. next/font produces a hashed family (`__Inter_xxx`)
// plus a synthetic size-adjusted fallback face to prevent FOUT layout shift
// both are exposed under the `--font-inter` CSS variable.
//
// The full `--font-sans` stack (Inter + the per-locale CJK fallback chain) is
// assembled in static CSS in ./globals.css, not here: it must be overridable per
// `<html lang>` (Japanese Kanji are Han ideographs and need a Japanese-first CJK
// stack), and a hashed family name can only be referenced from CSS via a variable.
// Keeping the CJK chain in CSS also keeps it CSP-safe and in sync with the desktop
// app, which defines the same chain in apps/desktop/src/renderer/src/globals.css.
const inter = Inter({
subsets: ["latin"],
variable: "--font-sans",
fallback: [
"-apple-system",
"BlinkMacSystemFont",
"Segoe UI",
"PingFang SC",
"Microsoft YaHei",
"Noto Sans CJK SC",
"Apple SD Gothic Neo",
"Malgun Gothic",
"Noto Sans CJK KR",
"sans-serif",
],
variable: "--font-inter",
});
// Mono font has no explicit CJK fallback: CJK chars in code blocks are inherently
// non-aligned with a mono grid (Chinese is proportional), so listing CJK fonts
@@ -109,6 +98,7 @@ const HTML_LANG: Record<SupportedLocale, string> = {
en: "en",
"zh-Hans": "zh-CN",
ko: "ko-KR",
ja: "ja-JP",
};
export default async function RootLayout({

View File

@@ -0,0 +1,102 @@
---
title: Multica に24時間体制のシニアデータアナリストを置いた方法
description: db-boy は私たちのワークスペースの24時間体制のシニアデータアナリストです。毎週月曜に週次メトリクスを自動投稿し、アドホックな質問に数分で答え、データが欠けていれば自分でトラッキング用の Pull request を作ってフロントエンドエージェントに割り当てます。
category: 分析の自動化
updated_at: 2026-05-22
hero_image: /usecases/auto-data-analysis/hero.png
---
db-boy は私たちのワークスペースの中にいる24時間体制のシニアデータアナリストです。
毎週月曜の午前9時、db-boy は先週の数字を表にまとめて `#weekly-metrics` イシューに貼り付け、各項目の担当者を @メンションします。
<Screenshot
src="/usecases/auto-data-analysis/hero.png"
alt="db-boy が月曜の週次メトリクスを @メンション付きで投稿した Multica のイシューコメント"
width={2098}
height={1548}
caption="月曜9:00 — db-boy が先週の主要な数字をイシューに残します(デモデータ)。"
priority
/>
勤務時間中は常に待機しています。データに関する質問が @メンションで飛んでくると、数分以内に Markdown の表や HTML のチャートを添えて答えます。トラッキングされていないイベントや曖昧な定義に途中でぶつかると、待つのではなく、適切な担当者を巻き込むためのイシューをその場で作ります。
[CTA: 無料で始める →]
---
## Multica とは
Multica は AI エージェントを従業員として扱うワークスペースプラットフォームです。一般的なコラボレーションツールと違う点は大きく2つあります。
**エージェントはツールではなく、ワークスペースのメンバーです。** db-boy はメンバー一覧の中に自分のアバターとプロフィールページ、オープン中のイシューのキューを持っています。イシューを割り当てられ、@メンションされ、プロジェクトのオーナーに指名されることもあり、自分でイシューを作って他の人に渡すこともできます。
**コンテキストはワークスペース全体で共有されます。** イシューのコメント、添付ファイル、HTML レポートを、人もエージェントも検索してリンクできます。スキルはワークスペース全体で使うプレイブックです。一度書いておけば、そのスキルを身につけたすべてのエージェントが同じ定義を共有するので、db-boy も DAU の計算方法や決済データがどのテーブルにあるかを毎回覚え直す必要がありません。
---
## どう組み上げたか
オフィスには Multica デーモンをインストールした Mac mini が1台あります。デーモンは起動時にローカルの AI コーディングツール(Claude Code、Codex などの系統)をスキャンし、それぞれを利用可能なランタイムとして登録します。そのうえでワークスペースに新しいエージェントを作り、@db-boy という名前を付けました。
この Mac mini には db-boy が仕事をするのに必要なものがあらかじめ揃っています。EKS の認証情報が入った `kubectl`、`posthog-cli`、そして読み取り専用アカウントで接続する `psql` です。ホストマシンで実行できるものなら、db-boy もそのまま呼び出せます。データベース接続は分析用のリードレプリカ(分析用に切り出したプロダクションの読み取り専用コピー)を向いており、`reader` アカウントには SELECT 権限しかありません。レプリカを分離してあるおかげでクエリがプロダクションのトラフィックに触れることはなく、読み取り専用なのでプロンプトインジェクションがあっても何も書き込めません。
最後に「データ分析」スキルを彼に紐付けました。このスキルには、DAU の定義、ファネルの各ステップの数え方、アプリケーションの状態は PG に・ユーザー行動は PostHog にあること、決済データが入っているテーブル、HTML レポートを残すイシュー、計測が欠けているときに @メンションする担当者が書かれています。一度書いてワークスペース全体で共有します。定義を変えたいときはスキルの1行を直すだけです。次の実行から反映され、デプロイもコード変更も要りません。
<Screenshot
src="/usecases/auto-data-analysis/db-boy-profile.png"
alt="Multica の db-boy エージェントのプロフィールページ。左にランタイムとスキル、右に system prompt と読み取り専用の警告が書かれた指示があります。"
width={2596}
height={1712}
caption="db-boy のプロフィール — アイデンティティ、データ定義、安全装置がすべて指示の中にあります。"
/>
---
## 仕事を任せる方法と、彼が自分で拾う仕事
いちばんよく使うのはイシューを割り当てる方法です。質問を書いて Assign を押し、@db-boy を選びます。数秒で Claude Code が起動し、スキルに書かれた経路(posthog-cli と HogQL、または psql)をたどって作業し、数分後にはイシューに Markdown の表と HTML レポートが添付されます。
毎回新しいイシューを開く必要はありません。既存のスレッドで続きの質問があれば、その場で @メンションしてください。同じスレッドの中で文脈をそのまま保ったまま返してくれます。ちょっとした数字が欲しいだけなら、同僚に聞くように直接チャットを送れば大丈夫です。繰り返しのレポート(週次メトリクス、月次の投資家向け資料、日次のトークン使用量トップ10など)はオートパイロットに一度設定しておけば、スケジュールどおりに実行され、該当するイシューに結果を残し、購読者にも通知が届きます。
最初に詰まったところで手を止めることもありません。トラッキングされていないイベントを見つけると、自分で新しいイシューを開きます。たとえば `Y ページの X ボタンのクリックにトラッキングを追加` のようなタイトルで、フィールド、イベント名、必要な理由を埋めて @frontend-agent に割り当てます。フロントエンドエージェントが Pull request を出し、エンジニアがレビューしてマージすれば、次に同じ質問が来たときにはもうデータが揃っています。
<Screenshot
src="/usecases/auto-data-analysis/ad-hoc-question.png"
alt="@naiyuan がコメントで db-boy に North Star 指標の質問をし、db-boy が分析結果と、frontend-agent のために作ったトラッキング用 Pull request のリンクで答えています。"
width={1726}
height={840}
caption="naiyuan がスレッドで db-boy を @メンションします。db-boy は答えを残し、フロントエンドエージェントに割り当てたトラッキングの後続作業をそっと開きます(デモデータ)。"
/>
誰もチケットを別に切りません。誰も他人を追い回しません。エージェント同士が仕事を渡し合い、人とエージェントが同じイシューで議論し、イシューそのものが共有の作業単位になります。
---
## チームで変わったこと
db-boy を迎えてから、データを見るリズムそのものが変わりました。
**即時性。** どんな質問でも @メンションすれば数分で答えが返ってきます。深夜2時に retention curve が必要でも大丈夫です。db-boy はいつもそこにいます。「メモしておいて来週アナリストに聞こう」といった遅れがなくなりました。
**自動化。** 月曜の週次レポート、月次の投資家向け資料、日次のトークン使用量トップ10が、すべてオートパイロットの上で回っています。結果は該当イシューのコメントに残り、購読者にも通知が届きます。繰り返しのレポートに人の時間がもうかかりません。
**可視化。** 既定の成果物は文章の段落ではなく、チャート入りの HTML ダッシュボードです。数分でチャートが返ってくるので、トレンドグラフ1つのために sprint を丸ごと待つことはありません。議論も「なんとなく X な気がする」から抜け出します。
**主体性。** 分析の流れで詰まった仕事を自分で拾います。欠けている計測はフロントエンドエージェントに割り当てたイシューになり、曖昧な定義は適切な担当者とのスレッドになり、コンパイルできないクエリは別のアプローチでの再試行になります。「誰かを待っている」列に何も残りません。
---
## あなたのワークスペースにも1人迎える
Multica をダウンロードし、エージェントを登録し、データ分析スキルを与えて、最初のイシューを割り当てましょう。
[CTA: 無料で始める →] [Secondary CTA: セットアップガイドを読む →]
---
## 関連リンク
- [エージェント](/docs/ja/agents)
- [オートパイロット](/docs/ja/autopilots)
- [スキル](/docs/ja/skills)

View File

@@ -6,12 +6,14 @@ describe("changelog date labels", () => {
expect(monthYearLabel(2026, 1, "en")).toBe("January 2026");
expect(monthYearLabel(2026, 1, "zh-Hans")).toBe("2026年1月");
expect(monthYearLabel(2026, 1, "ko")).toBe("2026년 1월");
expect(monthYearLabel(2026, 1, "ja")).toBe("2026年1月");
});
it("formats full dates for each landing locale", () => {
expect(fullDateLabel("2026-01-15", "en")).toBe("January 15, 2026");
expect(fullDateLabel("2026-01-15", "zh-Hans")).toBe("2026年1月15日");
expect(fullDateLabel("2026-01-15", "ko")).toBe("2026년 1월 15일");
expect(fullDateLabel("2026-01-15", "ja")).toBe("2026年1月15日");
});
it("keeps invalid release dates unchanged", () => {

View File

@@ -12,6 +12,7 @@ import { useRouter } from "next/navigation";
import { useConfigStore } from "@multica/core/config";
import { createBrowserCookieLocaleAdapter } from "@multica/core/i18n/browser";
import { createEnDict } from "./en";
import { createJaDict } from "./ja";
import { createKoDict } from "./ko";
import { createZhDict } from "./zh";
import {
@@ -26,6 +27,7 @@ const dictionaryFactories: Record<
(allowSignup: boolean) => LandingDict
> = {
en: createEnDict,
ja: createJaDict,
ko: createKoDict,
zh: createZhDict,
};

File diff suppressed because it is too large Load Diff

View File

@@ -2,20 +2,22 @@ import type { SupportedLocale } from "@multica/core/i18n";
export { docsHrefForLocale } from "@/lib/docs-href";
export type Locale = SupportedLocale;
export type LandingDictionaryLocale = "en" | "zh" | "ko";
export type LandingDictionaryLocale = "en" | "zh" | "ko" | "ja";
export const locales: Locale[] = ["en", "zh-Hans", "ko"];
export const locales: Locale[] = ["en", "zh-Hans", "ko", "ja"];
export const localeLabels: Record<Locale, string> = {
en: "EN",
"zh-Hans": "\u4e2d\u6587",
ko: "\ud55c\uad6d\uc5b4",
ja: "\u65e5\u672c\u8a9e",
};
export function toLandingDictionaryLocale(
locale: Locale,
): LandingDictionaryLocale {
if (locale === "ko") return "ko";
if (locale === "ja") return "ja";
return locale === "zh-Hans" ? "zh" : "en";
}

View File

@@ -6,5 +6,6 @@ describe("docsHrefForLocale", () => {
expect(docsHrefForLocale("en")).toBe("/docs");
expect(docsHrefForLocale("zh-Hans")).toBe("/docs/zh");
expect(docsHrefForLocale("ko")).toBe("/docs/ko");
expect(docsHrefForLocale("ja")).toBe("/docs/ja");
});
});

View File

@@ -3,5 +3,6 @@ import type { SupportedLocale } from "@multica/core/i18n";
export function docsHrefForLocale(locale: SupportedLocale): string {
if (locale === "zh-Hans") return "/docs/zh";
if (locale === "ko") return "/docs/ko";
if (locale === "ja") return "/docs/ja";
return "/docs";
}

View File

@@ -9,6 +9,7 @@ describe("locale routing", () => {
expect(isSupportedLocale("en")).toBe(true);
expect(isSupportedLocale("zh-Hans")).toBe(true);
expect(isSupportedLocale("ko")).toBe(true);
expect(isSupportedLocale("ja")).toBe(true);
expect(isSupportedLocale("zh")).toBe(false);
expect(isSupportedLocale(null)).toBe(false);
});
@@ -46,4 +47,12 @@ describe("locale routing", () => {
}),
).toBe("ko");
});
it("matches Japanese browser language signals", () => {
expect(
resolveLocaleFromSignals({
acceptLanguage: "ja-JP,ja;q=0.9,en;q=0.8",
}),
).toBe("ja");
});
});

View File

@@ -93,6 +93,31 @@ describe("use case source locale fallback", () => {
).toEqual(["localized", "english-only"]);
});
it("maps the ja locale to the ja use-case lang and keeps the English fallback", () => {
const localizedPage = {
slugs: ["localized"],
data: { title: "ローカライズ済み" },
};
const englishOnly = {
slugs: ["english-only"],
data: { title: "English only" },
};
vi.mocked(useCasesSource.getPages).mockImplementation((lang?: string) => {
if (lang === "ja") {
return [localizedPage] as ReturnType<typeof useCasesSource.getPages>;
}
if (lang === "en") {
return [englishOnly] as ReturnType<typeof useCasesSource.getPages>;
}
return [] as ReturnType<typeof useCasesSource.getPages>;
});
expect(
getUseCasePagesForLocale("ja").map((page) => page.slugs.join("/")),
).toEqual(["localized", "english-only"]);
});
it("falls back to English-only detail pages in the production detail wrapper", () => {
const localizedPage = {
slugs: ["localized"],

View File

@@ -43,4 +43,14 @@ export const useCaseText: Record<SupportedLocale, UseCaseText> = {
cardReadMore: "읽기 →",
tableOfContents: "이 페이지에서",
},
ja: {
indexTitle: "ユースケース",
indexSubtitle:
"チームが Multica で人とエージェントをどう組み合わせて動かしているかをご覧ください。",
indexMetadataTitle: "ユースケース",
indexMetadataDescription:
"チームが Multica で人とエージェントを一緒に働かせる方法をご覧ください。",
cardReadMore: "続きを読む →",
tableOfContents: "このページの内容",
},
};

View File

@@ -5,10 +5,10 @@ import { useCases } from "@/.source";
import { mergeUseCasePagesWithEnglishFallback } from "./use-case-locale-fallback";
// Use-case content uses dot-suffixed MDX files (`<slug>.en.mdx`,
// `<slug>.zh.mdx`, and `<slug>.ko.mdx`). The public route remains prefix-free; request locale is
// `<slug>.zh.mdx`, `<slug>.ko.mdx`, and `<slug>.ja.mdx`). The public route remains prefix-free; request locale is
// resolved through the same cookie/header path as the rest of the web app.
export const i18n = defineI18n({
languages: ["en", "zh", "ko"],
languages: ["en", "zh", "ko", "ja"],
defaultLanguage: "en",
hideLocale: "default-locale",
parser: "dot",
@@ -19,6 +19,7 @@ export type UseCaseLang = (typeof i18n.languages)[number];
export function getUseCaseLangForLocale(locale: SupportedLocale): UseCaseLang {
if (locale === "zh-Hans") return "zh";
if (locale === "ko") return "ko";
if (locale === "ja") return "ja";
return "en";
}

View File

@@ -21,6 +21,7 @@ describe("matchLocale", () => {
it("matches a clean supported tag", () => {
expect(matchLocale(["zh-Hans"])).toBe("zh-Hans");
expect(matchLocale(["ko"])).toBe("ko");
expect(matchLocale(["ja"])).toBe("ja");
expect(matchLocale(["en"])).toBe("en");
});
@@ -28,10 +29,11 @@ describe("matchLocale", () => {
expect(matchLocale(["en-US"])).toBe("en");
expect(matchLocale(["zh-Hans-CN"])).toBe("zh-Hans");
expect(matchLocale(["ko-KR"])).toBe("ko");
expect(matchLocale(["ja-JP"])).toBe("ja");
});
it("falls back to DEFAULT_LOCALE when no candidate matches", () => {
expect(matchLocale(["fr", "ja"])).toBe("en");
expect(matchLocale(["fr", "de"])).toBe("en");
});
it("zh-Hant (traditional) collapses to zh-Hans — same base subtag, better UX than English fallback", () => {
@@ -41,6 +43,7 @@ describe("matchLocale", () => {
it("uses the first supported candidate when multiple appear", () => {
expect(matchLocale(["fr", "zh-Hans", "en"])).toBe("zh-Hans");
expect(matchLocale(["fr", "ko-KR", "en"])).toBe("ko");
expect(matchLocale(["fr", "ja-JP", "en"])).toBe("ja");
});
it("returns DEFAULT_LOCALE for malformed BCP-47 tags rather than throwing", () => {
@@ -68,7 +71,7 @@ describe("pickLocale", () => {
it("returns DEFAULT_LOCALE when neither choice nor preference yields a match", () => {
const adapter = makeAdapter({
getUserChoice: () => null,
getSystemPreferences: () => ["fr", "ja"],
getSystemPreferences: () => ["fr", "de"],
});
expect(pickLocale(adapter)).toBe("en");
});

View File

@@ -1,6 +1,6 @@
export type SupportedLocale = "en" | "zh-Hans" | "ko";
export type SupportedLocale = "en" | "zh-Hans" | "ko" | "ja";
export const SUPPORTED_LOCALES: SupportedLocale[] = ["en", "zh-Hans", "ko"];
export const SUPPORTED_LOCALES: SupportedLocale[] = ["en", "zh-Hans", "ko", "ja"];
export const DEFAULT_LOCALE: SupportedLocale = "en";
export type LocaleResources = Record<string, Record<string, unknown>>;

View File

@@ -11,7 +11,7 @@ import "i18next";
// the two augmentations compose: views contributes common/auth/... and ui
// contributes `ui`. No properties overlap, so the merge is conflict-free.
//
// The resource shape is mirrored from packages/views/locales/{en,zh-Hans,ko}/ui.json.
// The resource shape is mirrored from packages/views/locales/{en,zh-Hans,ko,ja}/ui.json.
// Drift between the JSON and these types is not caught by the locale parity
// test — if you add a key to ui.json, mirror it here.
declare global {

View File

@@ -11,6 +11,7 @@
"english": "English",
"chinese": "中文",
"korean": "한국어",
"japanese": "日本語",
"sync_failed": "Language saved on this device, but failed to sync to your account. Other devices may show the previous language."
},
"timezone": {

View File

@@ -74,6 +74,31 @@ import koUsage from "./ko/usage.json";
import koUi from "./ko/ui.json";
import koSquads from "./ko/squads.json";
import koBilling from "./ko/billing.json";
import jaCommon from "./ja/common.json";
import jaAuth from "./ja/auth.json";
import jaSettings from "./ja/settings.json";
import jaIssues from "./ja/issues.json";
import jaAgents from "./ja/agents.json";
import jaEditor from "./ja/editor.json";
import jaOnboarding from "./ja/onboarding.json";
import jaInvite from "./ja/invite.json";
import jaLabels from "./ja/labels.json";
import jaMembers from "./ja/members.json";
import jaMyIssues from "./ja/my-issues.json";
import jaSearch from "./ja/search.json";
import jaInbox from "./ja/inbox.json";
import jaWorkspace from "./ja/workspace.json";
import jaProjects from "./ja/projects.json";
import jaAutopilots from "./ja/autopilots.json";
import jaSkills from "./ja/skills.json";
import jaChat from "./ja/chat.json";
import jaModals from "./ja/modals.json";
import jaRuntimes from "./ja/runtimes.json";
import jaLayout from "./ja/layout.json";
import jaUsage from "./ja/usage.json";
import jaUi from "./ja/ui.json";
import jaSquads from "./ja/squads.json";
import jaBilling from "./ja/billing.json";
// Single source of truth for the resource bundle. Both apps (web layout +
// desktop App.tsx) import from here so adding a locale or namespace happens
@@ -160,4 +185,31 @@ export const RESOURCES: Record<SupportedLocale, LocaleResources> = {
squads: koSquads,
billing: koBilling,
},
ja: {
common: jaCommon,
auth: jaAuth,
settings: jaSettings,
issues: jaIssues,
agents: jaAgents,
editor: jaEditor,
onboarding: jaOnboarding,
invite: jaInvite,
labels: jaLabels,
members: jaMembers,
"my-issues": jaMyIssues,
search: jaSearch,
inbox: jaInbox,
workspace: jaWorkspace,
projects: jaProjects,
autopilots: jaAutopilots,
skills: jaSkills,
chat: jaChat,
modals: jaModals,
runtimes: jaRuntimes,
layout: jaLayout,
usage: jaUsage,
ui: jaUi,
squads: jaSquads,
billing: jaBilling,
},
};

View File

@@ -0,0 +1,430 @@
{
"page": {
"title": "エージェント",
"tagline": "イシューを引き受け、コメントし、ステータスを更新する AI チームメイトです。",
"learn_more": "詳細はこちら →",
"new_agent": "新規エージェント",
"search_placeholder": "エージェントを検索...",
"show_archived": "アーカイブ済みを表示 ({{count}}) →",
"of_total": "{{total}} 件中 {{visible}} 件",
"list_load_failed": "エージェントを読み込めませんでした",
"list_load_failed_default": "エージェント一覧の取得中に問題が発生しました。",
"try_again": "再試行"
},
"scope": {
"mine": "自分のもの",
"all": "すべて"
},
"sort": {
"label_recent": "最近のアクティビティ",
"label_name": "名前",
"label_runs": "実行回数の多い順",
"label_created": "最近作成"
},
"availability": {
"all": "すべて",
"online": "オンライン",
"unstable": "不安定",
"offline": "オフライン",
"archived": "アーカイブ済み"
},
"workload": {
"working": "作業中",
"queued": "待機中",
"idle": "アイドル"
},
"archived": {
"active_link": "アクティブなエージェント",
"title": "アーカイブ済みエージェント"
},
"empty": {
"title": "まだエージェントがいません",
"description": "チームメイトと同じように、エージェントを作成してイシューを割り当てましょう。ローカルエージェントは自分のマシンで、クラウドエージェントは Multica のランタイムで実行されます。"
},
"no_matches": {
"title": "一致する結果なし",
"search_archived": "\"{{query}}\" に一致するアーカイブ済みエージェントがありません。",
"no_archived": "まだアーカイブ済みのエージェントはありません。",
"search_active": "\"{{query}}\" に一致するエージェントがありません。",
"search_active_filtered": "このフィルターで \"{{query}}\" に一致するエージェントがありません。",
"no_filter_match": "このフィルターに一致するエージェントがありません。",
"search_runtime_filtered": "\"{{machine}}\" 上に \"{{query}}\" に一致するエージェントがありません。",
"runtime_filtered": "\"{{machine}}\" 上にエージェントがありません。"
},
"columns": {
"agent": "エージェント",
"status": "ステータス",
"workload": "作業量",
"runtime": "ランタイム",
"activity_7d": "アクティビティ7日",
"runs": "実行"
},
"row": {
"you": "あなた",
"archived": "アーカイブ済み",
"no_description": "説明なし",
"fallback_runtime_cloud": "クラウド",
"fallback_runtime_local": "ローカル",
"actions_aria": "行の操作"
},
"activity_tooltip": {
"created_today": "今日作成",
"created_days_ago_other": "{{count}} 日前に作成",
"last_7_days": "過去7日",
"no_activity": "アクティビティなし",
"runs_other": "{{count}} 回実行",
"failed_suffix": " · {{count}} 回失敗({{percent}}%"
},
"row_actions": {
"cancel_all_tasks": "すべてのタスクをキャンセル",
"duplicate": "複製",
"restore": "復元",
"archive": "アーカイブ",
"agent_archived_toast": "エージェントをアーカイブしました",
"archive_failed_toast": "エージェントをアーカイブできませんでした",
"agent_restored_toast": "エージェントを復元しました",
"restore_failed_toast": "エージェントを復元できませんでした",
"no_tasks_to_cancel_toast": "キャンセルできるアクティブなタスクがありません",
"cancelled_tasks_toast_other": "タスク {{count}} 件をキャンセルしました",
"cancel_failed_toast": "タスクをキャンセルできませんでした",
"cancel_dialog_title": "\"{{name}}\" のすべてのタスクをキャンセルしますか?",
"cancel_dialog_no_tasks": "キャンセルできるアクティブなタスクがありません。",
"cancel_dialog_running_one": "実行中 {{count}} 件",
"cancel_dialog_queued_one": "待機中 {{count}} 件",
"cancel_dialog_impact_other": "{{summary}} のタスクがキャンセルされます。",
"cancel_dialog_running_note": " 実行中のタスクが完全に停止するまで最大5秒かかる場合があります。",
"cancel_dialog_irreversible": " キャンセルしたタスクは再開できません。",
"cancel_dialog_keep": "そのままにする",
"cancel_dialog_confirm": "すべてのタスクをキャンセル",
"archive_dialog_title": "\"{{name}}\" をアーカイブしますか?",
"archive_dialog_description": "このエージェントは割り当てやメンションができなくなり、アクティブなタスクはすべてキャンセルされます。履歴はすべて保持され、後で復元できます。",
"archive_dialog_cancel": "キャンセル",
"archive_dialog_confirm": "アーカイブ"
},
"detail": {
"back_to_agents": "エージェント",
"back_to_agents_full": "エージェントに戻る",
"not_found_title": "エージェントが見つかりません",
"not_found_default": "このエージェントはアーカイブまたは削除された可能性があります。",
"no_access_title": "このエージェントにアクセスできません",
"no_access_hint": "この非公開エージェントは、エージェントのオーナーまたはワークスペースの admin のみが閲覧できます。",
"try_again": "再試行",
"archived_banner": "このエージェントはアーカイブされています。割り当てやメンションはできません。",
"restore": "復元",
"archive_dialog_title": "エージェントをアーカイブしますか?",
"archive_dialog_description": "\"{{name}}\" がアーカイブされます。割り当てやメンションはできなくなりますが、履歴はすべて保持されます。後で復元できます。",
"archive_dialog_cancel": "キャンセル",
"archive_dialog_confirm": "アーカイブ",
"more_archive": "エージェントをアーカイブ",
"agent_updated_toast": "エージェントを更新しました",
"update_failed_toast": "エージェントを更新できませんでした",
"agent_archived_toast": "エージェントをアーカイブしました",
"archive_failed_toast": "エージェントをアーカイブできませんでした",
"agent_restored_toast": "エージェントを復元しました",
"restore_failed_toast": "エージェントを復元できませんでした"
},
"inspector": {
"section_properties": "プロパティ",
"section_details": "詳細",
"section_skills": "スキル",
"prop_runtime": "ランタイム",
"prop_model": "モデル",
"prop_thinking": "思考",
"prop_visibility": "公開範囲",
"prop_concurrency": "同時実行数",
"prop_owner": "オーナー",
"prop_created": "作成日",
"prop_updated": "更新日",
"no_description_placeholder": "説明なし",
"change_avatar_aria": "アバターを変更",
"avatar_updated_toast": "アバターを更新しました",
"avatar_upload_failed_toast": "アバターをアップロードできませんでした",
"rename_title": "エージェント名を変更",
"rename_placeholder": "エージェント名",
"rename_required": "名前は必須です",
"edit_description_title": "説明を編集",
"description_placeholder": "このエージェントは何をしますか?",
"save": "保存",
"cancel": "キャンセル"
},
"skill_attach": {
"trigger_aria": "ワークスペースのスキルを追加",
"trigger_label": "追加"
},
"pickers": {
"concurrency_tooltip": "同時実行数 · 最大 {{value}} 件の同時タスク",
"concurrency_range": "最大同時タスク数({{min}}{{max}}",
"runtime_none": "ランタイムなし",
"runtime_tooltip": "ランタイム · {{name}} · {{status}}",
"runtime_tooltip_none": "ランタイム · 未選択",
"runtime_online": "オンライン",
"runtime_offline": "オフライン",
"runtime_owned_by": "{{name}} が所有",
"runtime_empty": "ランタイムなし",
"model_default": "デフォルト",
"model_tooltip": "モデル · {{value}}",
"model_managed_by_runtime": "ランタイムで管理",
"model_search_placeholder": "モデル ID を検索または入力",
"model_discovering": "モデルを検出中...",
"model_empty": "利用可能なモデルがありません",
"model_empty_with_dot": "利用可能なモデルがありません。",
"model_custom_tooltip": "\"{{value}}\" をカスタムモデル ID として使用",
"model_custom_use": "\"{{value}}\" を使用",
"model_clear": "クリア(プロバイダーのデフォルトを使用)",
"model_clear_title": "選択をクリアし、ランタイムのプロバイダーのデフォルトに戻します",
"thinking_default": "CLI 設定に従う",
"thinking_tooltip": "思考 · {{value}}",
"thinking_clear": "CLI 設定に従う",
"thinking_clear_title": "上書きをクリアし、推論レベルをローカルの CLI 設定claude/codexに任せます"
},
"model_dropdown": {
"label": "モデル",
"select_runtime_first": "先にランタイムを選択してください",
"default_provider": "デフォルト(プロバイダー)",
"runtime_offline_manual": "ランタイムがオフライン — 手動で入力",
"managed_by_runtime_title": "このランタイムがモデル選択を管理します。",
"managed_by_runtime_hint": "ランタイムホストでモデルを設定してください(例: Hermes は自身の設定ファイルから読み込みます)。",
"discovery_failed": "検出に失敗しました",
"clear_full": "選択をクリア(プロバイダーのデフォルトを使用)"
},
"tabs": {
"activity": "アクティビティ",
"tasks": "タスク",
"instructions": "指示",
"skills": "スキル",
"environment": "環境",
"custom_args": "カスタム引数",
"mcp_config": "MCP",
"discard_dialog_title": "保存していない変更を破棄しますか?",
"discard_dialog_description": "このタブに保存していない変更があります。今移動すると変更は破棄されます。",
"discard_keep": "編集を続ける",
"discard_confirm": "変更を破棄"
},
"create_dialog": {
"title_create": "エージェントを作成",
"title_duplicate": "エージェントを複製",
"description_create": "ワークスペースに新しい AI エージェントを作成します。",
"description_duplicate": "\"{{name}}\" を基に新しいエージェントを作成します。指示、環境変数、スキルがコピーされます。",
"name_label": "名前",
"name_placeholder": "例: ディープリサーチエージェント",
"description_label": "説明",
"description_placeholder": "このエージェントは何をしますか?",
"visibility_label": "公開範囲",
"runtime_label": "ランタイム",
"runtime_filter_mine": "自分のもの",
"runtime_filter_all": "すべて",
"runtime_loading": "ランタイムを読み込み中...",
"runtime_none": "利用可能なランタイムがありません",
"runtime_cloud_badge": "クラウド",
"runtime_private_badge": "非公開",
"runtime_private_locked_tooltip": "非公開ランタイムです。オーナーまたはワークスペースの admin のみがこのランタイム上にエージェントを作成できます。共有するには、オーナーに公開へ切り替えるよう依頼してください。",
"duplicate_copy_suffix": " (コピー)",
"create": "作成",
"creating": "作成中...",
"cancel": "キャンセル",
"create_failed_toast": "エージェントを作成できませんでした",
"skill_attach_failed_toast": "エージェントは作成されましたが、スキルを追加できませんでした: {{error}}",
"squad_join_failed_toast": "エージェント \"{{name}}\" は作成されましたが、スクワッドに参加できませんでした: {{error}}。メンバーから手動で追加できます。",
"instructions": {
"label": "指示",
"placeholder_blank": "クリックして指示を作成...",
"placeholder_duplicate": "クリックして複製された指示を表示または編集",
"collapse": "折りたたむ",
"editor_placeholder": "このエージェントが何をすべきか、何に集中すべきか、何を避けるべきかを記述してください..."
},
"skills_section": {
"label": "スキル",
"placeholder": "ワークスペースからスキルを追加",
"selected_other": "{{count}} 件選択中 — クリックして編集",
"collapse": "折りたたむ",
"list_empty_multi": "このワークスペースにはまだスキルがありません。まず作成またはインポートしてください。",
"list_loading": "読み込み中...",
"list_empty_default": "利用可能なスキルがありません。",
"list_no_match": "一致するスキルがありません。",
"search_placeholder": "スキルを検索..."
},
"avatar": {
"change_aria": "アバターを変更",
"upload_aria": "アバターをアップロード",
"remove_aria": "アバターを削除",
"select_image_toast": "画像ファイルを選択してください。",
"upload_failed_toast": "アバターのアップロードに失敗しました"
}
},
"tab_body": {
"common": {
"save": "保存",
"add": "追加",
"unsaved_changes": "保存していない変更"
},
"instructions": {
"intro": "このエージェントのアイデンティティと作業スタイルを定義します。すべてのタスクでエージェントのコンテキストに注入されます。Markdown に対応しています。",
"placeholder": "このエージェントの役割、専門分野、作業スタイルを定義してください。\n\n# 例\nあなたは React と TypeScript を専門とするフロントエンドエンジニアです。\n\n## 作業スタイル\n- 小さく焦点を絞った PR を作成する — 論理的な変更ごとに1コミット\n- 継承よりコンポジションを優先する\n- 新しいコンポーネントには必ずユニットテストを追加する\n\n## 制約\n- 明示的な承認なしに shared/ の型を変更しない\n- features/ の既存のコンポーネントパターンに従う"
},
"env": {
"intro_readonly": "エージェントプロセスの起動時に注入されます。値の読み取りや編集ができるのはワークスペースのオーナーと admin のみで、すべての表示と編集はワークスペースの監査ログに記録されます。",
"empty_readonly": "設定された環境変数はありません。",
"intro_prefix": "エージェントプロセスの起動時に注入されます(例: ",
"intro_separator": ", ",
"intro_suffix": ")。",
"key_placeholder": "KEY",
"value_placeholder": "value",
"show_value_aria": "値を表示",
"hide_value_aria": "値を非表示",
"remove_aria": "変数を削除",
"duplicate_keys_toast": "環境変数のキーが重複しています",
"saved_toast": "環境変数を保存しました",
"save_failed_toast": "環境変数を保存できませんでした",
"not_revealed_title_other": "変数 {{count}} 件を設定済み",
"not_revealed_empty": "設定された環境変数はありません。",
"not_revealed_hint": "値は表示するまでマスクされます。すべての表示と編集はワークスペースの監査ログに記録されます。",
"reveal_action": "表示して編集",
"revealing": "表示中...",
"reveal_failed_toast": "環境変数の値を読み込めませんでした",
"empty_editable": "設定された環境変数はありません。起動時にエージェントへ注入する変数を追加してください。"
},
"custom_args": {
"intro": "起動時にエージェントコマンドの末尾に追加される CLI 引数です。複数トークンのフラグは1行にまとめられ、CLI に渡される前に空白で分割されます。",
"launch_mode_prefix": "起動モード: ",
"launch_mode_args_placeholder": "<引数>",
"input_placeholder": "--flag value",
"remove_aria": "引数を削除",
"saved_toast": "カスタム引数を保存しました",
"save_failed_toast": "カスタム引数を保存できませんでした"
},
"mcp_config": {
"intro": "ランタイム CLI に転送される MCP server configuration ですClaude は --mcp-config、Codex は $CODEX_HOME/config.toml、Hermes/Kimi/Kiro は ACP mcpServers、OpenClaw はタスクごとの config wrapper 経由。そのまま保存され、secret が含まれる場合があるため、エージェントのオーナーとワークスペースの admin のみが読み取れます。空のままにすると CLI 自身のデフォルトが使用されます。OpenClaw の HTTP/SSE エントリには、Claude の \"type\" の代わりに OpenClaw 独自のフィールド名(例: \"transport\": \"streamable-http\")を使用してください。",
"placeholder": "{\n \"mcpServers\": {\n \"fetch\": {\n \"command\": \"uvx\",\n \"args\": [\"mcp-server-fetch\"]\n }\n }\n}",
"editor_aria": "MCP config JSON editor",
"clear_action": "クリア",
"invalid_json": "無効な JSON: {{error}}",
"invalid_not_object": "MCP config は JSON object である必要があります(例: {\"mcpServers\": …})。",
"saved_toast": "MCP config を保存しました",
"save_failed_toast": "MCP config を保存できませんでした",
"redacted_title": "設定済み — 現在の表示では非表示",
"redacted_hint": "この config を読み取れるのは、エージェントのオーナーまたはワークスペースの admin のみです。"
},
"skills": {
"intro": "このエージェントに割り当てられたワークスペースのスキルです。ローカルランタイムのスキルは常に自動的に利用できます。",
"add_action": "スキルを追加",
"empty_title": "割り当てられたスキルがありません",
"empty_hint": "ワークスペースのスキルを追加して、チームの知識をこのエージェントと共有しましょう。",
"remove_failed_toast": "スキルを削除できませんでした",
"add_dialog_title": "スキルを追加",
"add_dialog_description": "このエージェントに割り当てるワークスペースのスキルを選択してください。",
"add_dialog_search_placeholder": "スキルを検索",
"add_dialog_empty": "すべてのワークスペースのスキルがすでに割り当てられています。",
"add_dialog_no_match": "検索条件に一致するスキルがありません。",
"add_dialog_empty_partial": "追加できるスキルがありません。このエージェントにはすでにすべてのスキルが割り当てられています。",
"add_dialog_saving": "追加中...",
"add_dialog_confirm_default": "追加",
"add_dialog_confirm_other": "スキル {{count}} 件を追加",
"add_dialog_cancel": "キャンセル",
"add_failed_toast": "スキルを追加できませんでした"
},
"activity": {
"section_now": "現在",
"section_last_30d": "過去30日",
"section_recent": "最近の作業",
"subtitle_no_active": "アクティブな作業なし",
"subtitle_active_other": "アクティブなタスク {{count}} 件",
"subtitle_performance": "パフォーマンス",
"subtitle_no_recent": "まだ完了した作業はありません",
"subtitle_recent_progress": "{{total}} 件中 {{shown}} 件",
"subtitle_recent_latest": "最新 {{count}} 件",
"empty_now": "このエージェントは現在何も実行していません。",
"empty_30d": "過去30日間に完了した作業はありません。",
"empty_recent": "このエージェントはまだ何も完了していません。",
"show_more": "もっと見る →",
"runs_other": "回実行",
"success_pct": "成功率 {{percent}}%",
"avg_duration": "平均 {{value}}",
"failed_count": "{{count}} 回失敗",
"source_issue": "イシュー",
"source_chat": "チャット",
"source_autopilot": "オートパイロット",
"source_untracked": "未追跡",
"source_quick_create": "クイック作成",
"source_creating_issue": "イシューを作成中",
"source_chat_session": "チャットセッション",
"source_autopilot_run": "オートパイロット実行",
"issue_short_fallback": "イシュー {{prefix}}...",
"triggered_by": "トリガーした人",
"open_issue_aria": "イシューを開く",
"open_issue_tooltip": "イシューを開く",
"transcript_tooltip": "トランスクリプトを表示",
"cancel_task_aria": "タスクをキャンセル",
"cancel_task_tooltip": "タスクをキャンセル",
"cancelling_tooltip": "キャンセル中...",
"cancel_failed_toast": "タスクをキャンセルできませんでした",
"started_prefix": "{{when}} に開始",
"dispatched_prefix": "{{when}} にディスパッチ",
"queued_prefix": "{{when}} に待機開始"
}
},
"char_counter": {
"over_limit": " · 制限を {{count}} 文字超過"
},
"presence": {
"queue_badge": "+{{count}} 待機中"
},
"visibility": {
"private": {
"label": "個人",
"tooltip": "個人 · 本人とワークスペースの admin のみがこのエージェントを使用できます"
},
"workspace": {
"label": "ワークスペース",
"tooltip": "ワークスペース · このワークスペースの全員がこのエージェントを使用できます"
}
},
"profile_card": {
"unavailable": "エージェントを利用できません",
"detail_link": "詳細 →",
"runtime_label": "ランタイム",
"skills_label": "スキル",
"owner_label": "オーナー",
"unknown_runtime": "不明なランタイム"
},
"live_peek": {
"current_issue_label": "現在の作業",
"no_current_issue": "タスクなし",
"last_activity_label": "最終アクセス",
"no_recent_activity": "最近のアクティビティなし",
"failed_indicator": "失敗"
},
"transcript": {
"dialog_title": "エージェント実行トランスクリプト",
"status_running": "実行中",
"status_completed": "完了",
"status_failed": "失敗",
"filter": "フィルター",
"clear_filters": "フィルターをクリア",
"tool_calls_other": "ツール呼び出し {{count}} 回",
"events_other": "イベント {{count}} 件",
"events_filtered": "イベント {{total}} 件中 {{shown}} 件",
"copy_all": "すべてコピー",
"copy_filtered": "フィルター結果をコピー",
"copied": "コピーしました",
"waiting_events": "イベントを待機中...",
"no_data": "記録された実行データがありません。",
"sort_label": "並び替え",
"sort_chronological": "古い順",
"sort_newest_first": "新しい順"
},
"task_failure": {
"agent_error": "エージェント実行エラー",
"timeout": "タスクがタイムアウトしました",
"runtime_offline": "デーモンがオフライン",
"runtime_recovery": "デーモンが再起動しました",
"manual": "ユーザーがキャンセルしました"
},
"runtime_filter": {
"all": "すべてのランタイム",
"section_local": "ローカル",
"section_remote": "リモート",
"section_cloud": "クラウド",
"agent_count_other": "エージェント {{count}} 件",
"empty": "まだマシンがありません"
}
}

View File

@@ -0,0 +1,48 @@
{
"signin": {
"title": "Multicaにログイン",
"description": "ログインコードを受け取るメールアドレスを入力してください",
"continue": "続ける",
"sending": "コードを送信中...",
"divider": "または",
"google": "Googleで続ける"
},
"verify": {
"title": "メールを確認してください",
"description": "{{email}}に確認コードを送信しました",
"resend": "コードを再送信",
"resend_cooldown": "{{seconds}}秒後に再送信"
},
"cli": {
"title": "CLIを承認",
"description": "CLIが{{email}}としてMulticaにアクセスすることを許可します",
"authorize": "承認",
"authorizing": "承認中...",
"different_account": "別のアカウントを使用"
},
"common": {
"back": "戻る",
"email": "メールアドレス",
"email_placeholder": "you@example.com",
"email_required": "メールアドレスは必須です"
},
"errors": {
"server_unreachable": "サーバーが実行中であることを確認してください。",
"send_failed": "コードを送信できませんでした。",
"resend_failed": "コードを再送信できませんでした",
"code_invalid": "コードが無効または期限切れです",
"cli_auth_failed": "CLIを承認できませんでした。もう一度ログインしてください。"
},
"web": {
"prefer_desktop": "デスクトップアプリをご利用ですか?",
"download": "ダウンロード",
"desktop_handoff": {
"preparing": "デスクトップのログインを準備中...",
"opening_title": "Multicaを開いています",
"opening_description": "Multicaデスクトップアプリを開くための確認が表示されます。何も起きない場合は、下のボタンをクリックしてください。",
"open_button": "Multica Desktopを開く",
"failed_title": "ログインに失敗しました",
"prepare_failed": "デスクトップのログインを準備できませんでした"
}
}
}

View File

@@ -0,0 +1,349 @@
{
"page": {
"title": "オートパイロット",
"new_autopilot": "新規オートパイロット",
"start_blank": "ゼロから始める",
"table": {
"name": "名前",
"agent": "エージェント",
"mode": "モード",
"status": "ステータス",
"last_run": "最終実行"
},
"last_run_empty": "--",
"empty": {
"title": "まだオートパイロットがありません",
"hint": "AI エージェントの繰り返しタスクをスケジュールしましょう。テンプレートを選ぶか、ゼロから始められます。"
}
},
"status": {
"active": "アクティブ",
"paused": "一時停止中",
"archived": "アーカイブ済み"
},
"execution_mode": {
"create_issue": "イシューを作成",
"run_only": "実行のみ"
},
"relative_date": {
"today": "今日",
"one_day_ago": "1 日前",
"days_ago": "{{count}} 日前",
"months_ago": "{{count}} か月前"
},
"templates": {
"daily_news": {
"title": "日次ニュースダイジェスト",
"summary": "今日のニュースを検索し、チーム向けに要約します"
},
"pr_review": {
"title": "PR レビューのリマインダー",
"summary": "レビューが必要な滞留中の Pull request を表示します"
},
"bug_triage": {
"title": "バグのトリアージ",
"summary": "新しいバグレポートを評価し、優先順位を付けます"
},
"weekly_progress": {
"title": "週次進捗レポート",
"summary": "チームの進捗を週次でまとめます"
},
"dependency_audit": {
"title": "依存関係の監査",
"summary": "セキュリティ脆弱性と古いパッケージをスキャンします"
},
"documentation_check": {
"title": "ドキュメントの点検",
"summary": "最近の変更にドキュメントの不足がないか確認します"
}
},
"detail": {
"not_found": "オートパイロットが見つかりません",
"pause_aria": "オートパイロットを一時停止",
"activate_aria": "オートパイロットを有効化",
"edit": "編集",
"run_now": "今すぐ実行",
"running": "実行中...",
"toast_triggered": "オートパイロットを実行しました",
"toast_trigger_failed": "オートパイロットを実行できませんでした",
"section_properties": "プロパティ",
"section_triggers": "トリガー",
"section_run_history": "実行履歴",
"section_danger": "危険な操作",
"field_agent": "エージェント",
"field_output_mode": "出力モード",
"field_project": "プロジェクト",
"no_project": "プロジェクトなし",
"project_unavailable": "プロジェクトを利用できません",
"field_prompt": "プロンプト",
"add_trigger": "トリガーを追加",
"no_triggers": "設定されたトリガーがありません。自動で実行するスケジュールを追加してください。",
"no_runs": "まだ実行履歴がありません。手動で実行するには「今すぐ実行」をクリックしてください。",
"delete_button": "オートパイロットを削除",
"toast_deleted": "オートパイロットを削除しました",
"toast_delete_failed": "オートパイロットを削除できませんでした",
"delete_dialog": {
"title": "オートパイロットを削除",
"description": "「{{title}}」を、そのトリガーと実行履歴ごと完全に削除します。この操作は元に戻せません。",
"cancel": "キャンセル",
"confirm": "削除",
"deleting": "削除中..."
}
},
"run_status": {
"issue_created": "イシュー作成済み",
"running": "実行中",
"completed": "完了",
"failed": "失敗",
"skipped": "スキップ済み"
},
"run_source": {
"schedule": "スケジュール",
"manual": "手動",
"webhook": "Webhook",
"api": "API"
},
"run": {
"issue_linked": "イシューをリンク済み",
"view_log": "実行ログを表示",
"skipped_group": {
"label": "スキップ済み",
"summary": "スキップされた実行 {{count}} 件"
}
},
"webhook_payload": {
"label": "Webhook イベント:",
"unknown_event": "webhook.received",
"payload": "Payload",
"content_type": "Content-Type: {{type}}",
"copy": "コピー",
"copied": "Webhook payload をコピーしました",
"copied_short": "コピーしました",
"copy_failed": "コピーできませんでした",
"truncated_marker": "[切り詰め — 全体の payload を取得するにはコピーをクリック]"
},
"trigger_kind": {
"schedule": "スケジュール",
"webhook": "Webhook",
"api": "API"
},
"trigger_row": {
"disabled_badge": "無効",
"deprecated_badge": "非推奨",
"next_label": "次回: {{date}}",
"webhook_url_label": "Webhook URL",
"copy_url": "URL をコピー",
"url_copied": "Webhook URL をコピーしました",
"url_copy_failed": "URL をコピーできませんでした",
"rotate_url": "URL を再生成",
"rotate_confirm_title": "Webhook URL を再生成",
"rotate_confirm_description": "現在の URL は直ちに動作を停止します。この URL を呼び出している外部システムは新しい URL に更新する必要があります。続けますか?",
"rotate_confirm_cancel": "キャンセル",
"rotate_confirm_action": "URL を再生成",
"rotate_in_progress": "再生成中...",
"toast_rotated": "Webhook URL を再生成しました",
"toast_rotate_failed": "URL を再生成できませんでした",
"toast_deleted": "トリガーを削除しました",
"toast_delete_failed": "トリガーを削除できませんでした",
"delete_dialog": {
"title": "トリガーを削除",
"description": "このトリガーは削除され、オートパイロットはこのスケジュールでは実行されなくなります。この操作は元に戻せません。",
"cancel": "キャンセル",
"confirm": "削除",
"deleting": "削除中..."
}
},
"deliveries": {
"section_title": "Webhook の配信",
"empty": "まだ Webhook の配信がありません。Webhook URL に POST を送ると、ここに表示されます。",
"row": {
"attempts": "{{count}} 回の試行",
"replay_badge": "再実行"
},
"status": {
"queued": "キュー待ち",
"dispatched": "ディスパッチ済み",
"rejected": "拒否",
"ignored": "無視",
"failed": "失敗"
},
"signature": {
"not_required": "署名なし",
"valid": "署名は有効",
"invalid": "署名が無効",
"missing": "署名がありません"
},
"detail": {
"title": "配信",
"received_at": "受信",
"last_attempt_at": "最終試行",
"attempt_count": "試行回数",
"response_status": "レスポンス",
"dedupe_key": "重複排除キー",
"dedupe_source": "重複排除ソース",
"content_type": "Content-Type",
"replayed_from": "再実行元",
"error_label": "エラー",
"raw_body": "生の本文",
"selected_headers": "ヘッダー",
"response_body": "レスポンス本文"
},
"replay": {
"action": "再実行",
"in_progress": "再実行中...",
"toast_success": "配信を再実行しました",
"toast_failed": "再実行に失敗しました",
"disabled_invalid_signature": "署名が無効だったため再実行できません",
"disabled_rejected": "拒否された配信は再実行できません",
"disabled_queued": "まだキュー待ちです。処理が落ち着いてから再実行してください"
}
},
"add_trigger_dialog": {
"title": "トリガーを追加",
"type_label": "種類",
"type_schedule": "スケジュール",
"type_webhook": "Webhook",
"label_field": "ラベル(任意)",
"label_placeholder": "例: 平日の朝",
"webhook_help": "保存すると Multica が Webhook URL を生成します。その URL に任意の JSON を POST すると、このオートパイロットが実行されます。",
"submit": "トリガーを追加",
"submitting": "追加中...",
"toast_added_schedule": "スケジュールトリガーを追加しました",
"toast_added_webhook": "Webhook トリガーを追加しました",
"toast_add_failed": "トリガーを追加できませんでした"
},
"dialog": {
"sr_create": "新規オートパイロット",
"sr_edit": "オートパイロットを編集",
"header_create": "新規オートパイロット",
"header_edit": "オートパイロットを編集",
"subtitle": "繰り返し実行される AI タスク",
"expand": "展開",
"collapse": "折りたたむ",
"close": "閉じる",
"title_placeholder": "オートパイロット名",
"runbook_label": "ランブック",
"runbook_hint": "実行のたびにエージェントが読みます",
"description_placeholder": "# 目標\nエージェントは何を達成すべきですか?\n\n# コンテキスト\n誰のための作業ですか? 制約はありますか?\n\n# 手順\n1. …\n2. …",
"auto_run_hint": "保存すると、一時停止するまで自動で実行されます。",
"cancel": "キャンセル",
"create": "オートパイロットを作成",
"save": "保存",
"creating": "作成中...",
"saving": "保存中...",
"toast_created": "オートパイロットを作成しました",
"toast_create_partial": "オートパイロットは作成しましたが、スケジュールを保存できませんでした",
"toast_create_partial_with_reason": "オートパイロットは作成しましたが、スケジュールを保存できませんでした: {{reason}}",
"toast_create_failed": "オートパイロットを作成できませんでした",
"toast_updated": "オートパイロットを更新しました",
"toast_update_partial": "オートパイロットは更新しましたが、スケジュールを保存できませんでした",
"toast_update_partial_with_reason": "オートパイロットは更新しましたが、スケジュールを保存できませんでした: {{reason}}",
"toast_update_failed": "オートパイロットを更新できませんでした",
"section_agent": "エージェント",
"section_assignee": "担当者",
"select_agent": "エージェントを選択",
"select_assignee": "エージェントまたはスクワッドを選択",
"section_project": "プロジェクト",
"no_project": "プロジェクトなし",
"section_output_mode": "出力モード",
"section_schedule": "スケジュール",
"section_trigger_kind": "トリガー",
"trigger_kind_schedule": "スケジュール",
"trigger_kind_webhook": "Webhook",
"section_webhook": "Webhook",
"webhook_help_create": "このオートパイロットを作成すると、Multica が Webhook URL を生成します。その URL に任意の JSON を POST すると実行されます。",
"webhook_help_edit": "このオートパイロットは Webhook で実行されます。URL の管理(コピー / 再生成)はオートパイロットの詳細ページで行ってください。",
"webhook_created_title": "Webhook オートパイロットの準備が完了しました",
"webhook_created_description": "下の URL に任意の JSON を POST すると、オートパイロットが実行されます。今コピーしておいてください — オートパイロットの詳細ページでも確認・再生成できます。",
"webhook_created_warning": "この URL はパスワードのように扱ってください。URL を持っている人は誰でもオートパイロットを実行できます。",
"webhook_created_done": "完了",
"event_filter_label": "イベントフィルター",
"event_filter_docs_link_label": "イベントフィルターの仕組みを学ぶ",
"event_filter_event_placeholder": "例: workflow_run",
"event_filter_actions_placeholder": "completed, failed",
"event_filter_hint": "これらのイベントに一致する Webhook のみを処理します。空にするとすべて許可します。",
"schedule_disabled_reason": "このオートパイロットには複数のスケジュールがあります。詳細ページで編集してください。",
"next_run_label": "次回実行:",
"output_modes": {
"create_issue": {
"label": "イシューを作成",
"description": "実行のたびに追跡可能なイシューを作成します"
},
"run_only": {
"label": "実行のみ",
"description": "イシューを作成せず、静かに実行します"
}
},
"frequency_long": {
"hourly": "毎時",
"daily": "毎日",
"weekdays": "平日ごと",
"weekly": "毎週",
"custom": "カスタム cron"
},
"days": {
"sunday": "日曜日",
"monday": "月曜日",
"tuesday": "火曜日",
"wednesday": "水曜日",
"thursday": "木曜日",
"friday": "金曜日",
"saturday": "土曜日"
}
},
"trigger_config": {
"frequencies": {
"hourly": "毎時",
"daily": "毎日",
"weekdays": "平日",
"weekly": "曜日",
"custom": "カスタム"
},
"days_short": {
"sun": "日",
"mon": "月",
"tue": "火",
"wed": "水",
"thu": "木",
"fri": "金",
"sat": "土"
},
"cron_label": "Cron 式",
"cron_hint": "標準の 5 フィールド cron(分 時 日 月 曜日)",
"minute_label": "分",
"time_label": "時刻",
"timezone_label": "タイムゾーン",
"days_label": "曜日",
"summary": {
"hourly": "毎時 · :{{min}}",
"daily": "毎日 {{time}}",
"weekdays": "平日 {{time}}",
"weekly": "{{days}} {{time}}",
"custom": "カスタム cron",
"no_days": "—"
},
"describe": {
"hourly": "毎時 :{{min}} に実行",
"daily": "毎日 {{time}} {{offset}} に実行",
"weekdays": "平日 {{time}} {{offset}} に実行",
"weekly": "毎週 {{days}} {{time}} {{offset}} に実行",
"custom": "カスタムスケジュール: {{cron}}"
},
"countdown": {
"days_hours": "{{days}} 日 {{hours}} 時間",
"hours_minutes": "{{hours}} 時間 {{minutes}} 分",
"minutes": "{{minutes}} 分",
"less_than_minute": "1 分未満"
}
},
"agent_picker": {
"filter_placeholder": "エージェントまたはスクワッドを絞り込み...",
"select_agent": "エージェントを選択",
"select_assignee": "エージェントまたはスクワッドを選択",
"agents_group": "エージェント",
"squads_group": "スクワッド"
},
"timezone_picker": {
"search_placeholder": "タイムゾーンを検索..."
}
}

View File

@@ -0,0 +1,75 @@
{
"title": "請求(テストページ)",
"subtitle": "multica-cloud の /api/v1/billing/* に直接パススルーします。完成した UI ではなく、proxy と Stripe フローを検証するためにすべての endpoint を 1 つのページにまとめたものです。",
"endpoints": {
"balance": "GET /api/cloud-billing/balance",
"transactions": "GET /api/cloud-billing/transactions",
"batches": "GET /api/cloud-billing/batches",
"topups": "GET /api/cloud-billing/topups",
"buy": "GET /price-tiers · POST /checkout-sessions · POST /portal-sessions"
},
"balance": {
"title": "残高",
"credits_suffix": "credits",
"meta": "raw micro: {{micro}} · owner: {{owner}}… · updated {{updated}}"
},
"buy": {
"title": "クレジット購入 / 請求の管理",
"no_tiers": "設定された価格 tier がありません。Cloud に Stripe key が設定されていない可能性があり、checkout は 503 を返します。",
"tier_money_to_credits": "{{money}} → {{credits}} credits",
"tier_bonus": " + ボーナス {{credits}}",
"tier_bonus_with_expiry": " + ボーナス {{credits}}{{expiry}}",
"tier_id": "id: {{id}}",
"open_portal": "Stripe Billing Portal を開く",
"portal_hint": "まだ支払いをしていないユーザーには 400 が想定されますStripe customer record がまだ存在しません)。",
"toast_no_url": "Cloud が checkout URL を返しませんでした",
"toast_checkout_failed": "Checkout に失敗しました",
"toast_no_portal_url": "Portal URL が返されませんでした",
"toast_portal_failed": "Portal を開けませんでした"
},
"checkout": {
"session_label": "Checkout session {{prefix}}…",
"loading": "注文ステータスを読み込み中…",
"fetch_failed": "ステータスの取得に失敗しました: {{error}}",
"fetch_failed_unknown": "不明なエラー",
"final_status": "最終ステータス: {{status}}",
"polling_status": "ステータスを確認中… 現在: {{status}}",
"status_unknown": "unknown",
"label_order": "注文",
"label_tier": "Tier",
"label_charged": "請求済み",
"charged_value": "{{money}} · {{credits}} credits",
"charged_with_bonus": "{{money}} · {{credits}} credits + ボーナス {{bonus}}",
"clear_url": "URL から消去"
},
"transactions": {
"title": "取引履歴",
"empty": "取引履歴はまだありません。",
"credits_value": "{{value}} credits",
"row_meta": "{{date}} · balance after: {{balance}} credits · ref: {{ref}}",
"ref_empty": "—"
},
"batches": {
"title": "クレジット batch",
"empty": "batch はまだありません。",
"remaining_over_total": "{{remaining}} / {{total}} credits",
"id_suffix": "{{id}}…",
"consumed": "使用済み: {{value}} credits",
"expires_suffix": " · 有効期限 {{value}}",
"never_expires_suffix": " · 有効期限なし"
},
"topups": {
"title": "Topup 注文",
"empty": "topup 注文はまだありません。",
"amount_to_credits": "{{money}} → {{credits}} credits",
"amount_to_credits_with_bonus": "{{money}} → {{credits}} credits + ボーナス {{bonus}}",
"row_meta": "{{date}} · stripe: {{checkout}}",
"stripe_empty": "—"
},
"shared": {
"request_failed": "リクエストに失敗しました",
"refresh": "更新",
"paging": "{{page}} / {{totalPages}} ページ · 合計 {{total}}件",
"date_dash": "—"
}
}

View File

@@ -0,0 +1,129 @@
{
"fab": {
"running": "Multica が作業中です...",
"unread_other": "未読のチャット {{count}}件",
"default": "Multica に質問"
},
"input": {
"placeholder_no_agent": "チャットを始めるにはエージェントを作成してください",
"placeholder_archived": "このセッションはアーカイブされています",
"placeholder_named": "{{name}} に指示してください…",
"placeholder_default": "やってほしいことを入力してください…",
"send_tooltip": "送信",
"stop_tooltip": "停止"
},
"message_list": {
"show_details": "詳細を表示",
"replied_in": "{{elapsed}}で返信",
"failed_after": "{{elapsed}}後に失敗",
"task_failed_fallback": "タスクが失敗しました",
"tools_other": "ツール {{count}}個",
"tool_result_named": "{{tool}} の結果: ",
"tool_result_unnamed": "結果: ",
"process_steps_other": "ステップ {{count}}個",
"copy_action": "コピー",
"copied_toast": "コピーしました",
"copy_failed_toast": "コピーに失敗しました"
},
"session_history": {
"untitled": "無題",
"time": {
"just_now": "たった今",
"minutes": "{{count}}分前",
"hours": "{{count}}時間前",
"days": "{{count}}日前"
},
"row_delete_aria": "チャットセッションを削除",
"row_rename_aria": "チャットセッションの名前を変更",
"delete_dialog": {
"title": "チャットセッションを削除",
"description_with_title": "\"{{title}}\" とそのメッセージが完全に削除されます。この操作は取り消せません。",
"description_default": "このチャットセッションとそのメッセージが完全に削除されます。この操作は取り消せません。",
"cancel": "キャンセル",
"confirm": "削除",
"confirming": "削除中..."
},
"row_stop_aria": "現在の実行を停止",
"stop_action": "停止",
"row_subtitle": {
"working": "作業中",
"completed": "完了",
"new_reply": "新しい返信"
},
"stop_dialog": {
"title": "この実行を停止しますか?",
"description_with_title": "\"{{title}}\" の現在のエージェントタスクをキャンセルします。生成済みの内容はチャットに残ります。",
"description_default": "現在のエージェントタスクをキャンセルします。生成済みの内容はチャットに残ります。",
"cancel": "実行を続ける",
"confirm": "実行を停止",
"confirming": "停止中..."
}
},
"window": {
"new_chat_tooltip": "新規チャット",
"restore_tooltip": "復元",
"expand_tooltip": "展開",
"minimize_tooltip": "最小化",
"another_running": "別のチャットが実行中です",
"another_unread": "別のチャットに未読の返信があります",
"running": "実行中",
"unread": "未読",
"no_previous": "以前のチャットはありません",
"untitled": "新規チャット",
"my_agents": "マイエージェント",
"others": "その他",
"no_agents": "エージェントなし",
"history_group": "チャット履歴"
},
"empty_state": {
"first_time_title": "エージェントとチャット",
"first_time_intro": "✨ エージェントはあなたのワークスペースを把握しています —",
"first_time_pillars": "イシュー、プロジェクト、スキル",
"first_time_pillars_suffix": "。",
"first_time_actions": "要約を頼んだり、今日の予定を立てたり、簡単なタスクを任せたりしてみましょう。",
"returning_title_named": "こんにちは、{{name}} です",
"returning_title_default": "Multica へようこそ",
"returning_subtitle": "こう聞いてみましょう"
},
"starter_prompts": {
"list_open": "オープンなタスクを優先度順にまとめて",
"summarize_today": "今日やったことを要約して",
"plan_next": "次に取り組むことを計画して"
},
"context_anchor": {
"tooltip_disabled": "このページに Multica へ共有できる内容はありません",
"tooltip_off": "Multica に現在表示中の内容を知らせる",
"tooltip_on_issue": "Multica は {{label}} を表示中だと把握しています · クリックでオフ",
"tooltip_on_project": "Multica はプロジェクト \"{{label}}\" を表示中だと把握しています · クリックでオフ",
"card_tooltip_issue_with_subtitle": "Multica は {{label}} を表示中だと把握しています — {{subtitle}}",
"card_tooltip_issue": "Multica は {{label}} を表示中だと把握しています",
"card_tooltip_project": "Multica はプロジェクト \"{{label}}\" を表示中だと把握しています",
"aria_stop": "現在のページの共有を停止",
"aria_start": "現在のページを Multica に共有"
},
"no_agent_banner": "チャットを始めるにはエージェントが必要です。",
"offline_banner": {
"fallback_name": "エージェント",
"unstable": "{{name}} の接続が不安定です。返信が遅れる場合があります。",
"offline": "{{name}} はオフラインです。再接続されたらメッセージが届きます。"
},
"status_pill": {
"stages": {
"offline": "オフライン",
"reconnecting": "再接続中",
"queued": "待機中",
"waiting_local_directory": "ローカルディレクトリを待機中",
"starting_up": "起動中",
"thinking": "考え中",
"typing": "入力中"
},
"tools": {
"running_command": "コマンドを実行中",
"reading_files": "ファイルを読み込み中",
"searching_code": "コードを検索中",
"making_edits": "編集中",
"searching_web": "ウェブを検索中",
"fallback": "作業中"
}
}
}

View File

@@ -0,0 +1,13 @@
{
"save": "保存",
"cancel": "キャンセル",
"delete": "削除",
"confirm": "確認",
"loading": "読み込み中...",
"time": {
"just_now": "たった今",
"minutes_ago": "{{count}}分前",
"hours_ago": "{{count}}時間前",
"days_ago": "{{count}}日前"
}
}

View File

@@ -0,0 +1,76 @@
{
"bubble_menu": {
"bold": "太字",
"italic": "斜体",
"strikethrough": "取り消し線",
"code": "コード",
"link": "リンク",
"list": "リスト",
"quote": "引用",
"url_aria_label": "URL",
"heading_dropdown": {
"text": "テキスト",
"normal_text": "標準テキスト",
"heading_1": "見出し 1",
"heading_2": "見出し 2",
"heading_3": "見出し 3"
},
"list_dropdown": {
"bullet_list": "箇条書きリスト",
"ordered_list": "番号付きリスト"
},
"sub_issue": {
"tooltip": "選択範囲からサブイシューを作成",
"created": "{{identifier}} を作成しました",
"create_failed": "サブイシューを作成できませんでした"
}
},
"image": {
"view": "画像を表示",
"download": "ダウンロード",
"copy_link": "リンクをコピー",
"delete": "削除",
"link_copied": "リンクをコピーしました",
"copy_link_failed": "リンクをコピーできませんでした"
},
"attachment": {
"download_failed": "ダウンロードリンクを取得できませんでした。しばらくしてからもう一度お試しください。",
"preview": "プレビュー",
"preview_loading": "プレビューを読み込み中…",
"preview_failed": "プレビューを読み込めませんでした",
"preview_too_large": "ファイルが大きすぎてプレビューできません。ダウンロードしてください。",
"preview_unsupported": "このファイル形式はプレビューできません。",
"close": "閉じる",
"open_in_new_tab": "新しいタブで開く",
"remove": "添付ファイルを削除"
},
"link_hover": {
"copy_link": "リンクをコピー",
"open_link": "リンクを開く",
"link_copied": "リンクをコピーしました",
"copy_failed": "コピーできませんでした"
},
"mention": {
"group_users": "ユーザー",
"group_issues": "イシュー",
"all_members": "すべてのメンバー",
"searching": "検索中...",
"no_results": "結果なし"
},
"code_block": {
"copy_code": "コードをコピー",
"show_preview": "プレビューを表示",
"show_source": "ソースを表示",
"fullscreen": "全画面"
},
"file_card": {
"uploading": "{{filename}} をアップロード中"
},
"title_editor": {
"title_aria_label": "タイトル"
},
"mermaid": {
"render_error": "Mermaid ダイアグラムを描画できません。",
"rendering": "ダイアグラムを描画中…"
}
}

View File

@@ -0,0 +1,71 @@
{
"page": {
"title": "インボックス",
"back": "インボックス"
},
"menu": {
"mark_all_read": "すべて既読にする",
"archive_all": "すべてアーカイブ",
"archive_all_read": "既読の項目をすべてアーカイブ",
"archive_completed": "完了した項目をアーカイブ"
},
"list": {
"empty": "通知はありません",
"mark_done_tooltip": "完了にする",
"archive_tooltip": "アーカイブ",
"time": {
"just_now": "たった今",
"minutes": "{{count}}分",
"hours": "{{count}}時間",
"days": "{{count}}日"
}
},
"detail": {
"select_prompt": "詳細を表示する通知を選択してください",
"empty": "インボックスは空です",
"original_input": "元の入力",
"edit_advanced": "詳細フォームで編集",
"archive": "アーカイブ"
},
"types": {
"issue_assigned": "割り当て済み",
"unassigned": "割り当て解除",
"assignee_changed": "担当者を変更",
"status_changed": "ステータスを変更",
"priority_changed": "優先度を変更",
"start_date_changed": "開始日を変更",
"due_date_changed": "期限を変更",
"new_comment": "新しいコメント",
"mentioned": "メンションされました",
"review_requested": "レビューを依頼",
"task_completed": "タスク完了",
"task_failed": "タスク失敗",
"agent_blocked": "エージェントがブロック",
"agent_completed": "エージェントが完了",
"reaction_added": "リアクションあり",
"quick_create_done": "エージェントで作成",
"quick_create_failed": "エージェントでの作成に失敗"
},
"labels": {
"set_status_to": "ステータスを変更:",
"set_priority_to": "優先度を変更:",
"assigned_to": "{{name}} に割り当て",
"removed_assignee": "担当者を削除",
"set_start_date_to": "開始日: {{date}}",
"removed_start_date": "開始日を削除",
"set_due_date_to": "期限: {{date}}",
"removed_due_date": "期限を削除",
"reacted_to_comment": "あなたのコメントに {{emoji}} のリアクションをしました",
"created_with_agent": "エージェントで作成: {{identifier}}",
"failed_with_detail": "失敗: {{detail}}"
},
"errors": {
"mark_read_failed": "既読にできませんでした",
"archive_failed": "アーカイブできませんでした",
"mark_done_failed": "完了にできませんでした",
"mark_all_read_failed": "すべて既読にできませんでした",
"archive_all_failed": "すべてアーカイブできませんでした",
"archive_all_read_failed": "既読の項目をアーカイブできませんでした",
"archive_completed_failed": "完了した項目をアーカイブできませんでした"
}
}

View File

@@ -0,0 +1,53 @@
{
"header": {
"back": "戻る",
"log_out": "ログアウト"
},
"not_found": {
"title": "招待が見つかりません",
"description": "この招待は期限切れか取り消されたか、お使いのアカウントに属していない可能性があります。",
"go_to_dashboard": "ダッシュボードへ移動"
},
"accepted": {
"title": "{{workspace_name}}に参加しました!",
"redirecting": "ワークスペースへ移動中..."
},
"declined": {
"title": "招待を辞退しました",
"description": "このワークスペースには追加されません。",
"go_to_dashboard": "ダッシュボードへ移動"
},
"main": {
"join_title": "{{workspace_name}}に参加",
"fallback_workspace_name": "ワークスペース",
"invited_role_admin": "さんがあなたをadminとして招待しました。",
"invited_role_member": "さんがあなたをmemberとして招待しました。",
"already_handled_accepted": "この招待はすでに承認されています。",
"already_handled_declined": "この招待はすでに辞退されています。",
"expired": "この招待は期限切れです。",
"decline": "辞退",
"declining": "辞退中...",
"accept": "承認して参加",
"joining": "参加中..."
},
"errors": {
"accept_failed": "招待を承認できませんでした",
"decline_failed": "招待を辞退できませんでした"
},
"batch": {
"log_out": "ログアウト",
"empty_title": "保留中の招待はありません",
"empty_hint": "続けて自分のワークスペースを設定しましょう。",
"empty_continue": "セットアップを続ける",
"title": "招待を受け取りました",
"subtitle": "参加するワークスペースを選択してください。残りはいつでもサイドバーから処理できます。",
"submit_skip": "スキップして自分のワークスペースを設定",
"submit_join_other": "{{count}} 件のワークスペースに参加",
"joining": "参加中...",
"error_generic": "招待を処理できませんでした。もう一度お試しください。",
"row_workspace_fallback": "ワークスペース",
"row_inviter_fallback": "誰か",
"row_invited_admin": "{{inviter}}さんがあなたをadminとして招待しました",
"row_invited_member": "{{inviter}}さんがあなたをmemberとして招待しました"
}
}

View File

@@ -0,0 +1,445 @@
{
"page": {
"breadcrumb_title": "イシュー",
"breadcrumb_workspace_fallback": "ワークスペース",
"empty_title": "まだイシューがありません",
"empty_hint": "イシューを作成して始めましょう。",
"move_failed": "イシューを移動できませんでした"
},
"status": {
"backlog": "バックログ",
"todo": "未着手",
"in_progress": "進行中",
"in_review": "レビュー中",
"done": "完了",
"blocked": "ブロック中",
"cancelled": "キャンセル済み"
},
"priority": {
"urgent": "緊急",
"high": "高",
"medium": "中",
"low": "低",
"none": "優先度なし"
},
"scope": {
"all_label": "すべて",
"all_description": "このワークスペースのすべてのイシュー",
"members_label": "メンバー",
"members_description": "チームメンバーに割り当てられたイシュー",
"agents_label": "エージェント",
"agents_description": "AI エージェントに割り当てられたイシュー"
},
"filters": {
"tooltip": "フィルター",
"placeholder": "フィルター...",
"no_results": "結果なし",
"no_labels": "まだラベルがありません",
"no_assignee": "担当者なし",
"no_project": "プロジェクトなし",
"section_status": "ステータス",
"section_priority": "優先度",
"section_assignee": "担当者",
"section_creator": "作成者",
"section_project": "プロジェクト",
"section_label": "ラベル",
"members_group": "メンバー",
"agents_group": "エージェント",
"squads_group": "スクワッド",
"issue_count_other": "イシュー {{count}} 件",
"reset": "すべてのフィルターをリセット",
"active_count_other": "フィルター {{count}} 件"
},
"display": {
"tooltip": "表示設定",
"grouping_section": "グループ化",
"ordering_section": "並び替え",
"card_properties_section": "カードのプロパティ",
"ascending_title": "昇順",
"descending_title": "降順",
"group_status": "ステータス",
"group_assignee": "担当者",
"group_parent": "親イシュー",
"group_project": "プロジェクト",
"sort_manual": "手動",
"sort_priority": "優先度",
"sort_start_date": "開始日",
"sort_due_date": "期限",
"sort_created": "作成日",
"sort_title": "タイトル",
"card_priority": "優先度",
"card_description": "説明",
"card_assignee": "担当者",
"card_start_date": "開始日",
"card_due_date": "期限",
"card_project": "プロジェクト",
"card_labels": "ラベル",
"card_child_progress": "サブイシューの進捗"
},
"view": {
"tooltip_board": "ボード表示",
"tooltip_list": "リスト表示",
"tooltip_gantt": "ガント表示",
"tooltip_swimlane": "スイムレーン表示",
"section": "表示",
"board": "ボード",
"list": "リスト",
"gantt": "ガント",
"swimlane": "スイムレーン"
},
"gantt": {
"header_issue": "イシュー",
"zoom_day": "日",
"zoom_week": "週",
"zoom_month": "月",
"show_completed": "完了済みを表示",
"empty": "スケジュールされたイシューがまだありません。いずれかのイシューに開始日または期限を設定すると、タイムラインに表示されます。",
"inverted_dates_warning": "開始日が期限より後になっています。バーは早い日付から遅い日付まで表示されます。"
},
"actor_issues": {
"scope": {
"assigned": {
"label": "割り当て済み",
"description": "このメンバーまたはエージェントに割り当てられたイシュー"
},
"created": {
"label": "作成済み",
"description": "このメンバーまたはエージェントが作成したイシュー"
}
},
"empty": {
"assigned": {
"title": "割り当てられたイシューはありません",
"description": "ここに割り当てられたイシューがこの表示に表示されます。"
},
"created": {
"title": "作成したイシューはありません",
"description": "ここで作成したイシューがこの表示に表示されます。"
}
},
"search_placeholder": "イシューを検索...",
"search_empty": "検索条件に一致するイシューがありません。"
},
"list": {
"empty_status": "イシューなし",
"add_issue_tooltip": "イシューを追加"
},
"swimlane": {
"no_parent": "親イシューなし",
"other_parents": "その他の親イシュー",
"no_project": "プロジェクトなし",
"no_assignee": "未割り当て",
"open_parent": "親イシューを開く",
"toggle_collapse": "レーンの開閉"
},
"board": {
"hidden_columns_label": "非表示の列",
"hide_column": "列を非表示",
"show_column": "列を表示",
"add_issue_tooltip": "イシューを追加",
"empty_column": "イシューなし",
"empty_grouping": "一致するイシューがありません",
"ordered_by": "{{field}} 順に並べたボード"
},
"detail": {
"not_found": "このイシューはこのワークスペースに存在しないか、削除されています。",
"breadcrumb_project_unknown": "不明なプロジェクト",
"back_to_issues": "イシューに戻る",
"title_placeholder": "イシューのタイトル",
"desc_placeholder": "説明を追加...",
"sub_issues_label": "サブイシュー",
"sub_issue_of": "親イシュー",
"add_sub_issues": "サブイシューを追加",
"add_sub_issue_tooltip": "サブイシューを追加",
"add_sub_issue_aria": "サブイシューを追加",
"section_properties": "プロパティ",
"section_parent_issue": "親イシュー",
"section_pull_requests": "Pull requests",
"section_metadata": "メタデータ",
"section_details": "詳細",
"section_token_usage": "トークン使用量",
"pull_requests_loading": "読み込み中...",
"pull_requests_empty": "まだリンクされた Pull request がありません。PR のブランチ名、タイトル、または本文にこのイシューの識別子を入れると、自動的にリンクされます。",
"pull_request_state_open": "オープン",
"pull_request_state_draft": "ドラフト",
"pull_request_state_merged": "マージ済み",
"pull_request_state_closed": "クローズ",
"pull_request_checks_passed": "チェック成功",
"pull_request_checks_failed": "チェック失敗",
"pull_request_checks_pending": "チェック待機中",
"pull_request_conflicts_clean": "コンフリクトなし",
"pull_request_conflicts_dirty": "コンフリクトあり",
"pull_request_card_status_closed": "マージせずにクローズ",
"pull_request_card_status_merged": "マージ済み",
"pull_request_card_status_conflicts": "マージコンフリクトあり",
"pull_request_card_status_checks_failed": "一部のチェックが失敗しました",
"pull_request_card_status_checks_pending": "一部のチェックがまだ完了していません",
"pull_request_card_status_checks_passed": "すべてのチェックに成功しました",
"pull_request_card_status_ready": "マージ可能",
"pull_request_card_status_unknown": "まだチェック結果がありません",
"pull_request_card_draft_prefix": "ドラフト · {{status}}",
"pull_request_card_files_count_other": "{{count}} ファイル",
"pull_request_card_show_more": "他 {{count}} 件を表示",
"pull_request_card_show_less": "折りたたむ",
"prop_status": "ステータス",
"prop_priority": "優先度",
"prop_assignee": "担当者",
"prop_start_date": "開始日",
"prop_due_date": "期限",
"prop_project": "プロジェクト",
"prop_labels": "ラベル",
"add_property_action": "プロパティを追加",
"prop_created_by": "作成者",
"prop_created": "作成日",
"prop_updated": "更新日",
"prop_input": "入力",
"prop_output": "出力",
"prop_cache": "キャッシュ",
"prop_cache_value": "読み取り {{read}} / 書き込み {{write}}",
"prop_runs": "実行",
"activity_section": "アクティビティ",
"subscribe": "購読",
"unsubscribe": "購読解除",
"no_subscribers_results": "結果が見つかりません",
"change_subscribers_placeholder": "購読者を変更...",
"members_group": "メンバー",
"agents_group": "エージェント",
"mark_done_tooltip": "完了にする",
"archive_tooltip": "アーカイブ",
"pin_tooltip": "サイドバーにピン留め",
"unpin_tooltip": "サイドバーのピン留めを解除",
"sidebar_tooltip": "サイドバーの開閉",
"cmdf_toast_title": "ページ内検索は表示中の内容のみが対象です",
"cmdf_toast_description": "タイムラインは仮想化されているため、画面外のコメントは ⌘F で見つかりません。アプリ全体の検索は近日提供予定です。",
"update_failed": "イシューを更新できませんでした",
"link_copied": "リンクをコピーしました",
"link_copy_failed": "リンクをコピーできませんでした",
"workdir_path_copied": "作業ディレクトリのパスをコピーしました",
"workdir_path_copy_failed": "作業ディレクトリのパスをコピーできませんでした",
"workdir_path_unavailable": "まだローカルの作業ディレクトリがありません。ローカルエージェントがこのイシューを実行していません"
},
"timeline": {
"loading": "読み込み中..."
},
"activity": {
"created": "このイシューを作成しました",
"self_assigned": "このイシューを自分に割り当てました",
"assigned_to": "{{name}} に割り当てました",
"removed_assignee": "担当者を削除しました",
"changed_assignee": "担当者を変更しました",
"status_changed": "ステータスを {{from}} から {{to}} に変更しました",
"priority_changed": "優先度を {{from}} から {{to}} に変更しました",
"start_date_set": "開始日を {{date}} に設定しました",
"start_date_removed": "開始日を削除しました",
"due_date_set": "期限を {{date}} に設定しました",
"due_date_removed": "期限を削除しました",
"title_renamed": "このイシューのタイトルを \"{{from}}\" から \"{{to}}\" に変更しました",
"description_updated": "説明を更新しました",
"task_completed_other": "タスクを完了しました({{count}} 回)",
"task_failed_other": "タスクが失敗しました({{count}} 回)",
"squad_leader_evaluated": "スクワッドのトリガーを評価しました",
"squad_leader_action": "評価してアクションを実行しました",
"squad_leader_action_reason": "評価してアクションを実行しました: {{reason}}",
"squad_leader_no_action": "評価完了: 必要なアクションはありません",
"squad_leader_no_action_reason": "評価完了: 必要なアクションはありません({{reason}}",
"squad_leader_failed": "評価に失敗しました",
"squad_leader_failed_reason": "評価に失敗しました: {{reason}}",
"coalesced_badge": "×{{count}}",
"activity_count_other": "アクティビティ {{count}} 件",
"show_more_activities_other": "アクティビティをさらに {{count}} 件表示"
},
"comment": {
"delete_title": "コメントを削除",
"delete_desc": "このコメントは完全に削除されます。この操作は元に戻せません。",
"delete_desc_with_replies": "このコメントとすべての返信が完全に削除されます。この操作は元に戻せません。",
"delete_action": "削除",
"cancel_action": "キャンセル",
"edit_placeholder": "コメントを編集...",
"save_action": "保存",
"cancel_edit": "キャンセル",
"copy_action": "コピー",
"copied_toast": "コピーしました",
"edit_action": "編集",
"update_failed": "コメントを更新できませんでした",
"send_failed": "コメントを送信できませんでした",
"send_reply_failed": "返信を送信できませんでした",
"delete_failed": "コメントを削除できませんでした",
"reply_count_other": "返信 {{count}} 件",
"leave_comment_placeholder": "コメントを残す...",
"send_tooltip": "送信",
"expand_tooltip": "展開",
"collapse_tooltip": "折りたたむ",
"resolve": {
"resolve_action": "スレッドを解決",
"unresolve_action": "スレッドの解決を取り消す",
"collapse": "折りたたむ",
"bar_other": "{{authors}} による解決済みコメント {{count}} 件",
"bar_authors_more_other": "{{names}} 他 {{count}} 名",
"resolve_failed": "スレッドを解決できませんでした",
"unresolve_failed": "スレッドの解決を取り消せませんでした"
}
},
"reply": {
"placeholder": "返信を残す...",
"expand_tooltip": "展開",
"collapse_tooltip": "折りたたむ"
},
"agent_activity": {
"hover_header_other": "作業中のエージェント {{count}} 件",
"status_running": "作業中",
"status_queued": "待機中",
"chip_label": "作業中",
"empty_hover": "現在作業中のエージェントはありません",
"filter_active_label": "作業中のエージェントのみ表示中"
},
"agent_live": {
"is_working": "{{name}} が作業中",
"is_queued": "{{name}} が待機中",
"is_waiting_local_directory": "{{name}} がローカルディレクトリを待機中",
"queued_elapsed_prefix": "{{elapsed}} 待機中",
"fallback_name": "エージェント",
"tool_count_other": "ツール {{count}} 件",
"transcript_button": "トランスクリプトを表示",
"stop_button": "停止",
"stop_tooltip": "エージェントを停止",
"cancel_failed": "タスクをキャンセルできませんでした"
},
"execution_log": {
"section": "実行ログ",
"show_past": "過去の実行を表示 ({{count}})",
"hide_past": "過去の実行を非表示 ({{count}})",
"cancel_task_tooltip": "タスクをキャンセル",
"cancel_task_aria": "タスクをキャンセル",
"retry_task_tooltip": "タスクを再試行",
"retry_task_aria": "タスクを再試行",
"retry_failed": "タスクを再試行できませんでした",
"transcript_tooltip": "トランスクリプトを表示",
"cancel_failed": "タスクをキャンセルできませんでした",
"trigger_retry": "再試行",
"trigger_retry_attempt": "再試行 #{{attempt}}",
"trigger_retry_attempt_prefix": "再試行 #{{attempt}} · ",
"trigger_retry_prefix": "再試行 · ",
"trigger_autopilot": "オートパイロット実行",
"trigger_comment": "コメントトリガー",
"trigger_initial": "初回実行",
"status_queued": "待機中",
"status_dispatched": "開始中",
"status_waiting_local_directory": "ローカルディレクトリ待機中",
"status_running": "作業中",
"status_completed": "完了",
"status_failed": "失敗",
"status_cancelled": "キャンセル済み"
},
"terminate_dialog": {
"title": "このタスクを停止しますか?",
"body": "タスクはキャンセルされ、再開できません。",
"running_note": " 実行中の処理が完全に停止するまで数秒かかる場合があります。",
"keep": "実行を続ける",
"confirm": "タスクを停止"
},
"batch": {
"selected": "{{count}} 件選択中",
"status": "ステータス",
"priority": "優先度",
"assignee": "担当者",
"delete": "削除",
"update_success_other": "イシュー {{count}} 件を更新しました",
"update_failed": "イシューを更新できませんでした",
"delete_success_other": "イシュー {{count}} 件を削除しました",
"delete_failed": "イシューを削除できませんでした",
"delete_dialog_title_other": "イシュー {{count}} 件を削除しますか?",
"delete_dialog_desc_other": "この操作は元に戻せません。選択したイシューと関連データがすべて完全に削除されます。",
"delete_dialog_warning": "ワークスペースのメンバーであれば誰でもイシューを削除できます。",
"cancel": "キャンセル"
},
"card": {
"update_failed": "イシューを更新できませんでした",
"updated_ago": "{{time}} に更新"
},
"actions": {
"status": "ステータス",
"priority": "優先度",
"assignee": "担当者",
"start_date": "開始日",
"start_today": "今日",
"start_tomorrow": "明日",
"start_next_week": "来週",
"start_clear": "日付をクリア",
"due_date": "期限",
"due_today": "今日",
"due_tomorrow": "明日",
"due_next_week": "来週",
"due_clear": "日付をクリア",
"unassigned": "未割り当て",
"pin_to_sidebar": "サイドバーにピン留め",
"unpin_from_sidebar": "サイドバーのピン留めを解除",
"copy_link": "リンクをコピー",
"copy_workdir_path": "ローカルの作業ディレクトリのパスをコピー",
"more": "その他",
"create_sub_issue": "サブイシューを作成",
"set_parent_issue": "親イシューを設定...",
"add_sub_issue": "サブイシューを追加...",
"delete_issue": "イシューを削除"
},
"pickers": {
"filter_options_aria": "フィルターオプション",
"no_results": "結果なし",
"assignee": {
"trigger_unassigned": "未割り当て",
"search_placeholder": "担当者を割り当て...",
"members_group": "メンバー",
"agents_group": "エージェント",
"squads_group": "スクワッド"
},
"start_date": {
"trigger_label": "開始日",
"clear_action": "日付をクリア"
},
"due_date": {
"trigger_label": "期限",
"clear_action": "日付をクリア"
},
"label": {
"trigger_label": "ラベルを追加",
"search_placeholder": "ラベルを検索または作成...",
"manage_action": "ラベルを管理...",
"manage_dialog_title": "ラベルを管理",
"create_action": "作成",
"create_failed": "ラベルを作成できませんでした"
}
},
"labels_panel": {
"intro": "ワークスペース全体でイシューを分類するラベルを作成・管理します。",
"new_placeholder": "新しいラベル名...",
"new_aria": "新しいラベル名",
"add_action": "追加",
"loading": "読み込み中...",
"empty": "まだラベルがありません。",
"name_required": "ラベル名は必須です。",
"color_label": "色",
"pick_color_aria": "色を選択",
"edit_aria": "{{name}} を編集",
"delete_aria": "{{name}} を削除",
"save_aria": "保存",
"cancel_aria": "キャンセル",
"delete_dialog_title": "ラベルを削除しますか?",
"delete_dialog_desc_prefix": "ラベル ",
"delete_dialog_desc_suffix": " がすべてのイシューから削除されます。この操作は元に戻せません。",
"delete_dialog_cancel": "キャンセル",
"delete_dialog_confirm": "削除",
"create_failed": "ラベルを作成できませんでした",
"update_failed": "ラベルを更新できませんでした",
"delete_failed": "ラベルを削除できませんでした"
},
"backlog_hint": {
"title": "バックログではエージェントが一時停止します",
"description": "このイシューは保留中のため、割り当てられたエージェントは待機します。エージェントを開始したいときは未着手に移動してください。",
"row_backlog_label": "バックログ",
"row_backlog_hint": "エージェントを一時停止のままにします",
"row_todo_label": "未着手",
"row_todo_hint": "エージェントを開始します",
"dont_show_again": "今後表示しない",
"keep_in_backlog": "バックログのままにする",
"move_to_todo": "未着手に移動"
}
}

View File

@@ -0,0 +1,3 @@
{
"remove_label": "ラベル{{name}}を削除"
}

View File

@@ -0,0 +1,41 @@
{
"nav": {
"inbox": "インボックス",
"my_issues": "マイイシュー",
"issues": "イシュー",
"projects": "プロジェクト",
"autopilots": "オートパイロット",
"agents": "エージェント",
"squads": "スクワッド",
"usage": "使用量",
"runtimes": "ランタイム",
"skills": "スキル",
"settings": "設定"
},
"help": {
"trigger": "ヘルプ",
"docs": "ドキュメント",
"changelog": "変更ログ",
"feedback": "フィードバック"
},
"workspace_loader": {
"loading_workspace": "ワークスペースを読み込み中…",
"loading_named_prefix": "読み込み中"
},
"sidebar": {
"unpin_tooltip": "ピン留めを解除",
"workspaces_label": "ワークスペース",
"create_workspace": "ワークスペースを作成",
"pending_invitations_label": "保留中の招待",
"invitation_workspace_fallback": "ワークスペース",
"invitation_join": "参加",
"invitation_decline": "辞退",
"log_out": "ログアウト",
"new_issue": "新規イシュー",
"new_issue_shortcut": "C",
"pinned_label": "ピン留め済み",
"workspace_group": "ワークスペース",
"configure_group": "設定",
"unread_overflow": "99+"
}
}

View File

@@ -0,0 +1,20 @@
{
"role": {
"owner": "オーナー",
"admin": "管理者",
"member": "メンバー"
},
"card": {
"unavailable": "メンバーを利用できません",
"agents_section": "エージェント ({{count}})",
"detail_link": "詳細 →",
"more_agents_other": "他 {{count}} 件のエージェント"
},
"detail": {
"workspace_fallback": "ワークスペース",
"members_breadcrumb": "メンバー",
"breadcrumb_fallback": "メンバー",
"not_found_title": "メンバーが見つかりません",
"not_found_description": "このメンバーはワークスペースから退出した可能性があります。"
}
}

View File

@@ -0,0 +1,190 @@
{
"common": {
"back": "戻る",
"close": "閉じる",
"cancel": "キャンセル",
"expand_tooltip": "展開",
"collapse_tooltip": "折りたたむ"
},
"create_workspace": {
"title": "新しいワークスペースを作成",
"description": "ワークスペースは、チームがプロジェクトやイシューに取り組む共有環境です。"
},
"delete_issue": {
"title": "イシューを削除",
"description": "このイシューとすべてのコメントが完全に削除されます。この操作は元に戻せません。",
"hint": "ワークスペースのメンバーであれば誰でもイシューを削除できます。",
"cancel": "キャンセル",
"confirm": "削除",
"deleting": "削除中...",
"toast_deleted": "イシューを削除しました",
"toast_delete_failed": "イシューを削除できませんでした"
},
"feedback": {
"title": "フィードバック",
"placeholder": "使用感、見つけたバグ、追加してほしい機能などをお聞かせください…",
"toast_uploading": "アップロードが完了するまでお待ちください…",
"toast_too_long": "メッセージが長すぎます",
"toast_sent": "フィードバックをありがとうございます!",
"toast_failed": "フィードバックを送信できませんでした",
"send": "フィードバックを送信",
"sending": "送信中…",
"github_hint_prefix": "より迅速な対応とオープンな議論をご希望ですか?こちらへ ",
"github_hint_link": "GitHub"
},
"issue_picker": {
"search_placeholder": "イシューを検索...",
"searching": "検索中...",
"no_results": "イシューが見つかりません。",
"prompt_to_search": "イシューを検索するには入力してください"
},
"set_parent": {
"title": "親イシューを設定",
"description": "このイシューの親に設定するイシューを検索してください",
"toast_failed": "イシューを更新できませんでした",
"toast_success": "{{identifier}} を親イシューに設定しました"
},
"add_child": {
"title": "サブイシューを追加",
"description": "サブイシューとして追加するイシューを検索してください",
"toast_failed": "サブイシューを追加できませんでした",
"toast_success": "{{identifier}} をサブイシューとして追加しました"
},
"backlog_hint": {
"toast_status_failed": "ステータスを更新できませんでした"
},
"create_squad": {
"title": "スクワッドを作成",
"description": "リーダーエージェントと任意の追加メンバーで協働スクワッドを作成します。",
"name_label": "名前",
"name_placeholder": "例: フロントエンドチーム",
"description_label": "説明",
"description_placeholder": "このスクワッドが担当する内容を説明してください...",
"leader_label": "リーダーエージェント",
"leader_hint": "リーダーはこのスクワッドに割り当てられたすべてのタスクを受け取り、チームを調整します。",
"leader_placeholder": "リーダーエージェントを選択",
"members_label": "追加メンバー",
"members_optional": "(任意)",
"members_hint": "リーダーがサブタスクを委任できるメンバーです。後から追加できます。",
"members_placeholder": "エージェントまたはワークスペースメンバーを追加",
"members_selected_count_other": "{{count}} 件選択中",
"members_more_count": "+{{count}}",
"members_remove_aria": "{{name}} を削除",
"picker_search_placeholder": "エージェントとメンバーを検索...",
"group_my_agents": "マイエージェント",
"group_workspace_agents": "ワークスペースエージェント",
"group_members": "メンバー",
"no_agents": "利用可能なアクティブエージェントがありません。先にエージェントを作成してください。",
"no_results": "結果なし",
"cancel": "キャンセル",
"submit": "スクワッドを作成",
"submitting": "作成中...",
"toast_created": "スクワッドを作成しました",
"toast_failed": "スクワッドを作成できませんでした",
"toast_member_add_failed": "{{name}} を追加できませんでした: {{error}}"
},
"create_project": {
"title": "新規プロジェクト",
"title_breadcrumb": "新規プロジェクト",
"icon_tooltip": "アイコンを選択",
"title_placeholder": "プロジェクトのタイトル",
"description_placeholder": "説明を追加...",
"lead": "リード",
"no_lead": "リードなし",
"lead_placeholder": "リードを指定...",
"members_group": "メンバー",
"agents_group": "エージェント",
"no_results": "結果なし",
"submit": "プロジェクトを作成",
"submitting": "作成中...",
"toast_created": "プロジェクトを作成しました",
"toast_failed": "プロジェクトを作成できませんでした",
"repos_pill": "リポジトリ",
"repos_pill_count_other": "{{count}} 個のリポジトリ",
"repos_heading": "このプロジェクトに GitHub リポジトリを接続",
"repos_empty": "まだワークスペースレベルのリポジトリがありません。下に URL を貼り付けてアドホックに接続してください。",
"repos_search_placeholder": "リポジトリを検索...",
"repos_search_empty": "検索に一致するリポジトリがありません。",
"repos_url_placeholder": "https://github.com/owner/repo または git@github.com:owner/repo.git",
"repos_add": "追加",
"repos_selected": "選択済み",
"source_pill_local": "ローカルディレクトリ",
"source_tab_repos": "GitHub リポジトリ",
"source_tab_local": "ローカルディレクトリ",
"local_heading": "このマシンのローカル作業ディレクトリを使用",
"local_on_device": "{{device}} にバインド済み",
"local_this_machine": "このマシン",
"local_daemon_offline": "デーモンがオフラインです。ローカルディレクトリをバインドするには起動してください。",
"local_pick": "ディレクトリを選択…",
"local_picking": "選択画面を開いています…",
"local_change": "ディレクトリを変更…",
"local_clear": "クリア",
"local_pick_failed": "ディレクトリ選択画面を開けませんでした。",
"local_invalid_dir": "このディレクトリは使用できません。別のものを選択してください。",
"local_hint": "他のマシンのエージェントはこのパスを参照できず、起動に失敗します。共有作業にはリポジトリを使用してください。"
},
"create_issue": {
"sr_manual": "新規イシュー",
"sr_agent": "イシューをクイック作成",
"manual_breadcrumb": "手動で作成",
"agent_breadcrumb": "エージェントで作成",
"title_placeholder": "イシューのタイトル",
"description_placeholder": "説明を追加...",
"more_options_aria": "その他のオプション",
"title_required": "作成するにはタイトルを入力してください",
"submit": "イシューを作成",
"submitting": "作成中...",
"toast_created": "イシューを作成しました",
"view_issue": "イシューを表示",
"toast_failed": "イシューを作成できませんでした",
"toast_duplicate_title": "重複イシュー",
"toast_duplicate_view": "既存のイシューを表示",
"toast_link_subissues_all_failed": "サブイシューをリンクできませんでした",
"toast_link_subissues_partial": "サブイシュー {{total}} 件中 {{failed}} 件をリンクできませんでした",
"switch_to_agent": "エージェントに切り替え",
"switch_to_agent_tooltip": "エージェントで作成に切り替えます。一行で説明すれば、エージェントがイシューを作成します",
"switch_to_manual": "手動に切り替え",
"switch_to_manual_tooltip": "手動作成に切り替えます。フィールドを自分で入力します",
"create_another": "もう 1 つ作成",
"remove_parent_aria": "親を削除",
"remove_subissue_aria": "サブイシュー {{identifier}} を削除",
"subissue_of": "{{identifier}} のサブイシュー",
"subissue_chip": "サブイシュー: {{identifier}}",
"parent_with_id": "親: {{identifier}}",
"set_start_date": "開始日を設定...",
"set_parent": "親イシューを設定...",
"add_subissue": "サブイシューを追加...",
"remove_parent": "親を削除",
"set_parent_picker": {
"title": "親イシューを設定",
"description": "新しいイシューの親に設定するイシューを検索してください"
},
"add_subissue_picker": {
"title": "サブイシューを追加",
"description": "新しいイシューのサブイシューとして追加するイシューを検索してください"
},
"agent": {
"created_by": "作成者",
"select_agent_aria": "エージェントを選択",
"pick_an_agent": "エージェントを選択…",
"no_agents": "利用可能なエージェントまたはスクワッドがありません。",
"search_placeholder": "エージェントとスクワッドを検索…",
"agents_group": "エージェント",
"squads_group": "スクワッド",
"version_missing": "このエージェントのデーモンは CLI バージョンを報告していません。エージェントで作成には multica CLI {{min}} 以上が必要です。デーモンをアップグレードして再接続するか、手動作成に切り替えてください。",
"version_below": "このエージェントのデーモン CLI は {{current}} です。エージェントで作成には {{min}} 以上が必要です。デーモンをアップグレードするか、手動作成に切り替えてください。",
"prompt_placeholder": "エージェントにやってほしいことを伝えてください。例: 「Bohan に Web プロジェクトのインボックス読み込みの遅さを直してもらう」",
"submit": "作成",
"sending": "送信中…",
"uploading": "アップロード中…",
"sent_label": "送信済み",
"sent_count": "{{count}} 件送信済み",
"version_blocked_tooltip": "デーモン CLI は {{min}} 以上である必要があります",
"toast_sent": "エージェントに送信しました。完了するとインボックス通知が届きます",
"error_agent_unavailable_fallback": "エージェントを利用できません。別のエージェントを選択してください。",
"error_daemon_version": "このエージェントのデーモン CLI{{current}})が必要なバージョン {{min}} を下回っています。エージェントで作成を使用するには、デーモンをアップグレードしてください。",
"error_unknown": "送信できませんでした。再試行してください。",
"sub_issue_of": "{{identifier}} のサブイシュー"
}
}
}

View File

@@ -0,0 +1,44 @@
{
"page": {
"breadcrumb": "マイイシュー",
"workspace_fallback": "ワークスペース",
"empty_title": "あなたに割り当てられたイシューはありません",
"empty_description": "あなたが作成したイシューや割り当てられたイシューがここに表示されます。"
},
"header": {
"scope": {
"all_label": "すべて",
"all_description": "自分に割り当て、自分が作成、または自分のエージェントやスクワッドが関わるイシュー",
"assigned_label": "割り当て済み",
"assigned_description": "自分に割り当てられたイシュー",
"created_label": "作成済み",
"created_description": "自分が作成したイシュー",
"agents_label": "自分のエージェントとスクワッド",
"agents_description": "自分のエージェントに割り当てられたイシュー"
},
"filter_button": "フィルター",
"filter_status": "ステータス",
"filter_priority": "優先度",
"issue_count_other": "{{count}} 件のイシュー",
"reset_filters": "すべてのフィルターをリセット",
"display_settings": "表示設定",
"grouping": "グループ化",
"group_status": "ステータス",
"group_assignee": "担当者",
"ordering": "並び順",
"ascending": "昇順",
"descending": "降順",
"card_properties": "カードのプロパティ",
"view_board": "ボード表示",
"view_list": "リスト表示",
"view_swimlane": "スイムレーン表示",
"view_label": "表示",
"view_board_short": "ボード",
"view_list_short": "リスト",
"view_swimlane_short": "スイムレーン",
"sort_manual": "手動"
},
"errors": {
"move_failed": "イシューを移動できませんでした"
}
}

View File

@@ -0,0 +1,375 @@
{
"step_header": {
"step_of": "ステップ {{current}} / {{total}}"
},
"welcome": {
"wordmark": "Multica へようこそ",
"headline_line1": "あなたの AI チームメイトを、",
"headline_line2": "ひとつの",
"headline_emphasis": "ワークスペースに。",
"lede": "同僚に仕事を任せるように作業を割り当てるだけ。エージェントがイシューを引き受け、ステータスを更新し、完了したらコメントします。",
"lede_web": "デスクトップ版にはランタイムが同梱されており、何もインストールする必要はありません。ご自身の CLI を接続するには、ウェブで続けてください。",
"lede_desktop": "完了するころには、実際のエージェントがあなたの最初のイシューに返信しています。",
"download_desktop": "デスクトップ版をダウンロード",
"continue_on_web": "ウェブで続ける",
"start_exploring": "探索を始める",
"skip_existing": "以前にやったことがあります",
"illustration_caption": "すべてのイシュー、すべてのスレッド、すべての判断を、チームとエージェントで共有。",
"illustration": {
"card1_actor_name": "あなた",
"card1_actor_initial": "N",
"card1_body_prefix": " 短いローンチ投稿の下書きをお願いできますか? ",
"card1_body_suffix": " のインタビュー結果を参考にしてください。",
"card1_mention_content": "@コンテンツエージェント",
"card1_mention_research": "@リサーチエージェント",
"card2_actor_name": "コンテンツエージェント",
"card2_body": "了解です。Research の引用をまとめ、「節約できた時間」の切り口で下書きを作成中です…",
"card3_actor_name": "リサーチエージェント",
"card3_body": "今週のユーザーインタビューをまとめました — 12 件の通話、4 つの繰り返し出たテーマ、3 つの引用候補。",
"card3_timestamp": "15 分前",
"card4_actor_name": "レビューエージェント",
"card4_body": "月曜の下書きをレビューし、トーンについて 4 件のメモを残しました。新しい下書きを待機中です。",
"card5_actor_name": "コーディングエージェント",
"card5_body_prefix": "エクスポート機能をリリースしました ",
"card5_body_suffix": " さんが指摘した点も対応済みです。プレビューリンクは PR にあります。",
"card5_mention_you": "@あなた",
"card5_timestamp": "たった今"
}
},
"common": {
"back": "戻る",
"continue": "続ける",
"skip": "スキップ",
"cancel": "キャンセル"
},
"questions": {
"eyebrow_about_you": "あなたについて",
"source": {
"question": "Multica をどこで知りましたか?",
"friends_colleagues": "友人または同僚",
"search": "Google / 検索",
"social_x": "X / Twitter",
"social_linkedin": "LinkedIn",
"social_youtube": "YouTube",
"social_misc": "その他の SNS",
"blog_newsletter": "ブログ / ニュースレター",
"ai_assistant": "ChatGPT / Claude / Cursor",
"from_work": "職場で",
"event_conference": "カンファレンス / ミートアップ",
"dont_remember": "覚えていない",
"other": "その他",
"other_placeholder": "例: よく聴くポッドキャスト",
"social_github": "GitHub"
},
"role": {
"question": "あなたに最も近いのはどれですか?",
"engineer": "エンジニア / 開発者",
"product": "プロダクトマネージャー",
"designer": "デザイナー",
"founder": "創業者 / 経営層",
"marketing": "マーケティング / グロース",
"writer": "ライター / コンテンツ",
"research": "リサーチャー / アナリスト",
"ops": "オペレーション / プロジェクト管理",
"student": "学生 / 個人利用",
"other": "その他",
"other_placeholder": "例: 教師、サポートリード"
},
"use_case": {
"question": "Multica を何に使いたいですか?",
"ship_code": "AI エージェントとコードをリリース",
"manage_team": "チームのタスクを管理",
"personal_tasks": "自分のタスクを整理",
"plan_research": "計画、ブレインストーミング、リサーチ",
"write_publish": "執筆、編集、公開",
"automate_ops": "運用とワークフローの自動化",
"evaluate": "とりあえず試してみる",
"other": "その他",
"other_placeholder": "例: スタディグループの運営"
}
},
"option_card": {
"other_label": "その他",
"other_aria": "別の内容を入力"
},
"step_question": {
"hint_pick": "ひとつ選んで続けてください。答えたくない場合はスキップできます。",
"hint_continue": "いい感じです。準備ができたら「続ける」を押してください。"
},
"runtime_aside": {
"what_eyebrow": "エージェントランタイムとは?",
"what_prefix": "接続する「コンピュータ」を、私たちは内部的に ",
"what_term": "エージェントランタイム",
"what_suffix": " と呼んでいます。Claude Code や Codex などの AI コーディングツール 1 つと組み合わさる、コンピュータ上の小さなバックグラウンドプロセスです。1 つのツールに 1 つのエージェントランタイム。エージェントランタイムが、エージェントの引き受けたタスクを実際に実行します。",
"good_eyebrow": "知っておくと便利",
"swap_title": "いつでも切り替え",
"swap_body": "各エージェントのランタイムは単なる設定です。いつでも変更できます。",
"add_more_title": "あとで追加",
"add_more_body": "チームメイト用に別のコンピュータを接続したり、エージェントごとに専用のものを用意したりできます。",
"learn_more": "エージェントランタイムについて学ぶ →"
},
"cli_install": {
"copy_aria": "コピー",
"intro": "エージェントを実行するには、このコンピュータにエージェントランタイム(Claude Code、Codex、Cursor など)が必要です。サーバーやリモート開発環境でも動作します。",
"step1_label": "Multica CLI をインストール",
"step2_label": "デーモンを起動"
},
"cloud_waitlist": {
"intro_main": "クラウドランタイムはまだ提供されていません。メールアドレスを残していただければ、準備ができ次第ご連絡します。",
"intro_warning": "注意: ランタイムがないとエージェントはタスクを実行できません。今スキップすると、戻ってきてインストールするまでワークスペースは読み取り専用になります。",
"email_label": "メールアドレス",
"email_placeholder": "you@work.com",
"reason_label": "クラウドを使いたい理由",
"optional": "任意",
"reason_placeholder": "例: エージェントを 24 時間稼働させたい、チームが複数のデバイスで作業している など。",
"join": "ウェイトリストに登録",
"on_list": "登録済みです",
"success_toast": "ウェイトリストに登録しました。クラウドランタイムが利用可能になったらメールでお知らせします。",
"failed_toast": "ウェイトリストに登録できませんでした"
},
"first_issue": {
"error_title": "問題が発生しました",
"retry": "再試行",
"retry_failed": "再試行に失敗しました",
"finishing": "仕上げ中",
"opening": "もうすぐです — ワークスペースを開いています。"
},
"step_agent": {
"eyebrow": "最初のエージェント",
"headline": "最初のチームメイトに会いましょう。",
"lede_prefix": "あなたの回答からは ",
"lede_suffix": " が合っていそうです。4 つの中から自分に合うものを選んでください。どのテンプレートも最初のイシューをすぐに引き受けられる状態で用意されています。指示はあとでエージェント設定ページから調整できます。",
"footer_hint": "始めるにはエージェント 1 つで十分です。あとでサイドバーから追加できます。",
"create_action": "{{name}} を作成",
"create_failed": "エージェントを作成できませんでした",
"recommended_badge": "おすすめ",
"templates": {
"coding": {
"label": "コーディングエージェント",
"blurb": "コードを書き、リファクタリングし、リリースします。リポジトリを読みます。",
"instructions": "あなたはプロダクトチームの Coding Agent です。コーディングのイシューを引き受け、機能を実装し、バグを修正し、テストを書き、Pull request を開いてください。始める前にリポジトリを読み、既存のコード規約に従い、diff は焦点を絞ったものに保ってください。受け入れ基準が曖昧なときは確認の質問をしてください。"
},
"planning": {
"label": "プランニングエージェント",
"blurb": "作業を分解し、仕様を起草し、ボードを整理します。",
"instructions": "あなたは Planning Agent です。漠然としたアイデアや未着手のイシューを、スコープが定まった実行可能な作業に変えてください。サブタスクに分解し、受け入れ基準を書き、担当者と順序を提案します。スピードより明確さを優先してください。コンテキスト不足で行き詰まったら、推測せずに具体的な質問を 1 つしてください。"
},
"writing": {
"label": "ライティングエージェント",
"blurb": "下書き、要約、リサーチを行います。長文も得意です。",
"instructions": "あなたは Writing Agent です。ドキュメントを起草し、長い内容を要約し、必要に応じてウェブでトピックをリサーチしてください。アウトラインではなく、読者がそのまま使える完成した文章として出力を構成してください。資料を参照した場合は出典を引用してください。イシューでユーザーが定めたトーンに合わせてください。"
},
"assistant": {
"label": "アシスタント",
"blurb": "汎用型。タスクが不明確なときに頼れるデフォルトです。",
"instructions": "あなたは汎用のチームメイトです。軽めのコーディング、執筆、リサーチ、計画など多様なタスクをこなし、スコープについては実用的に判断してください。タスクが曖昧なときは、取りかかる前に確認の質問を 1 つしてください。網羅的な出力より、短く役立つ出力を基本としてください。"
}
},
"about_eyebrow": "エージェントとは",
"about_headline": "ワークスペースの中に住む AI のチームメイトです。",
"about_body": "エージェントは、他の同僚と同じようにすべての担当者ピッカーに表示されます。違いは、与えたランタイムの上でなら 24 時間働けることです。",
"ways_eyebrow": "エージェントとの働き方",
"way_assign_title": "イシューを割り当てる",
"way_assign_body": "タスクを引き受け、スレッドで報告します。",
"way_mention_title": "コメントで @メンション",
"way_mention_body": "会話に呼んで、すばやく意見をもらえます。",
"way_chat_title": "1 対 1 でチャット",
"way_chat_body": "イシューを作らずに、すばやく質問できます。",
"way_autopilot_title": "オートパイロットに設定",
"way_autopilot_body": "毎日のトリアージ、週次ダイジェスト、月次監査などをスケジュールに沿って実行します。",
"add_more_hint": "エージェントはいつでも追加できます。1 人の万能型より、専門エージェントの小さなチームのほうが優れています。",
"docs_link": "最初のエージェントを作成する →"
},
"welcome_after_onboarding": {
"loading_helper": "Helper を準備中…",
"error_title": "セットアップを完了できませんでした",
"error_generic": "問題が発生しました。もう一度お試しください。",
"retry": "もう一度試す",
"dismiss_error": "閉じる",
"error_close": "閉じる",
"user_context_heading": "私について",
"user_context_role_label": "役割",
"user_context_use_case_label": "Multica でやりたいこと",
"runtime": {
"greeting": "こんにちは、Multica へようこそ",
"subtitle": "私はあなたの最初の Agent アシスタントです。",
"capabilities": "Multica の使い方について、何でも聞いてください。ワークスペースでの作業を任せることもできます — イシューの作成、cron タスクの設定、新しいエージェントの構築など…",
"section_label": "まず取り組むタスクを 1 つ以上選んでください:",
"assign_empty": "1 つ以上選択",
"assign_count": "{{count}} 件のタスクを私に割り当てる →",
"assign_count_plural": "{{count}} 件のタスクを私に割り当てる →",
"cards": {
"intro": {
"subtitle": "Multica とは何か、何ができるのかを 1〜2 段落で説明します。"
},
"tour": {
"subtitle": "イシュー、エージェント、スクワッド、オートパイロットがどう連携するかをご案内します。"
},
"welcome_page": {
"subtitle": "あなたの役割に合わせた単一ファイルの HTML スライドデックを作成します。コピーしてブラウザで開けます。"
}
},
"success": {
"title": "準備完了!",
"subtitle": "少々お待ちを — {{agentName}} が対応中です ☕",
"tip_inbox": "進捗があると、インボックスに表示されます。",
"tip_chat": "ライブでチャットしたいときは、右下のチャットバブルをクリックしてください。",
"got_it": "了解 →"
}
},
"skip": {
"loading": "ワークスペースを準備中…",
"title": "Multica へようこそ!",
"subtitle": "次のステップを助けるために、2 つのタスクを追加しました。",
"got_it": "了解",
"status_in_progress": "進行中",
"status_todo": "未着手",
"cards": {
"install_runtime": {
"title": "ランタイムを接続",
"subtitle": "Codex または Kimi をインストールして、エージェントをオンラインにしましょう。"
},
"create_agent": {
"title": "最初のエージェントを作成",
"subtitle": "ランタイムがオンラインになったら、最初の Multica エージェントを作りましょう。"
}
}
}
},
"step_workspace": {
"eyebrow_first": "最初のワークスペース",
"eyebrow_resume": "続きから、または新規作成",
"headline_first": "ワークスペースに名前を付けましょう。",
"headline_resume": "{{name}} で続けるか、別のワークスペースを始めましょう。",
"lede_first": "ワークスペースは、イシュー、エージェント、プロジェクトが集まる場所です。あとでチームメイトを招待したり、ワークスペースを増やしたりできます。",
"lede_resume": "すでにあるワークスペースでセットアップを続けるか、別に新しいワークスペースを作成してください。いくつでもワークスペースに所属できます。",
"name_label": "ワークスペース名",
"name_placeholder": "Acme Inc、My Lab、Side Projects…",
"url_label": "URL",
"slug_placeholder": "acme",
"issue_prefix_label": "イシュープレフィックス",
"issue_prefix_prefix": "イシューは ",
"issue_prefix_suffix": " のように表示されます。あとで設定から変更できます。",
"create_new_title": "新しいワークスペースを作成",
"create_new_subtitle": "新しく始めましょう — 別の業務領域のための独立した場所です。",
"hint_opening": "{{name}} を開いています。",
"hint_creating": "{{name}} を作成しています。",
"hint_creating_pending": "{{name}} を作成中…",
"hint_creating_fallback": "ワークスペース",
"hint_name_first": "ワークスペースを作成するには名前を入力してください。",
"hint_pick": "ワークスペースを選ぶか、新しく始めてください。",
"cta_open": "{{name}} を開く",
"cta_create_named": "{{name}} を作成",
"cta_create_workspace": "ワークスペースを作成",
"cta_creating": "作成中…",
"slug_format_error": "使用できるのは小文字、数字、ハイフンのみです",
"slug_taken_error": "そのワークスペース URL はすでに使われています。",
"slug_reserved_error": "そのワークスペース URL は予約済みのため使用できません。",
"slug_conflict_toast": "別のワークスペース URL を選んでください",
"create_failed_toast": "ワークスペースを作成できませんでした",
"side_create_eyebrow": "ワークスペースの中にあるもの",
"side_existing_eyebrow": "あなたのワークスペース",
"side_things_eyebrow": "ここでできること",
"side_next_eyebrow": "次のステップ",
"side_preview_name": "あなたのワークスペース",
"side_preview_slug": "workspace",
"perk_assign": "同僚に任せるようにイシューをエージェントに割り当てる",
"perk_chat": "イシューを作らずにどのエージェントともチャット",
"perk_invite": "チームメイトを招待 — 招待した人にはこのワークスペースだけが見えます",
"perk_switch": "左上からいつでも他のワークスペースに切り替え",
"next_runtime": "エージェントが動く場所を用意するためにコンピュータを接続",
"next_agent": "接続したランタイムから Multica Helper を作成",
"next_starter": "次のステップのためにオンボーディングイシューを 1 つ開く",
"preview": {
"inbox_label": "インボックス",
"inbox_meta": "あなたの通知",
"issues_label": "イシュー",
"issues_meta": "共有のタスクボード",
"agents_label": "エージェント",
"agents_meta": "あなたの AI チームメイト",
"projects_label": "プロジェクト",
"projects_meta": "関連するイシューをまとめる",
"autopilot_label": "オートパイロット",
"autopilot_meta": "スケジュールされた自動化",
"runtimes_label": "ランタイム",
"runtimes_meta": "エージェントが動く場所",
"skills_label": "スキル",
"skills_meta": "再利用できるプレイブック",
"more_label": "その他",
"more_meta": "さらに多くの機能"
},
"creation_disabled_eyebrow": "ワークスペースの作成は無効です",
"creation_disabled_headline": "管理者に招待を依頼してください。",
"creation_disabled_lede": "この Multica インスタンスでは新しいワークスペースを作成できません。管理者からワークスペースに招待されたら、招待を承諾して更新し、続けてください。",
"creation_disabled_logout": "ログアウト",
"creation_disabled_eyebrow_resume": "あなたのワークスペース",
"creation_disabled_headline_resume": "{{name}} で続けましょう。",
"creation_disabled_lede_resume": "このインスタンスではワークスペースの作成が無効になっているため、既存のワークスペースへ続けて移動します。"
},
"step_runtime": {
"scanning_headline": "このコンピュータを接続中…",
"scanning_lede_prefix": "エージェントは、あなたがすでに持っている AI コーディングツールを通じて作業します — たとえば ",
"scanning_lede_suffix": " など。このコンピュータにインストール済みのものを確認しています。",
"found_headline": "このコンピュータが接続されました。エージェントランタイムを選んでください。",
"found_lede": "このコンピュータで見つかったエージェントランタイムです。最初のエージェントに使うものを 1 つ選んでください。あとで切り替えたり追加したりできます。",
"runtime_count_other": "エージェントランタイム {{count}} 個",
"status_all_online": "すべてオンライン",
"status_none_online": "オンラインなし",
"status_n_online": "{{count}} 個オンライン",
"online_label": "オンライン",
"offline_label": "オフライン",
"empty_headline": "このコンピュータではまだエージェントランタイムが見つかりません。",
"empty_lede_prefix": "エージェントランタイムとは、私たちが接続する AI コーディングツールです — たとえば ",
"empty_lede_suffix": " など。1 つインストールして更新するか、下から進む方法を選んでください。",
"empty_skip_title": "今はスキップ",
"empty_skip_subtitle": "読み取り専用モードでワークスペースに入ります。このコンピュータにエージェントランタイムが接続されるまでエージェントはタスクを実行できませんが、閲覧、計画、チームメイトの招待は可能です。",
"empty_skip_action": "スキップ",
"empty_waitlist_title": "クラウドコンピュータを使う",
"empty_waitlist_subtitle": "クラウドでコンピュータを動かします。まだ提供されていません。",
"empty_waitlist_action": "近日公開",
"skip": "今はスキップ",
"refresh": "更新",
"refreshing": "更新中…",
"hint_selected": "選択中: {{name}}",
"hint_pick": "続けるには、上でエージェントランタイムを選んでください。",
"hint_waiting": "最初の結果を待っています…",
"hint_skip_or_refresh": "インストール後に更新するか、スキップしてワークスペースに入ってください。",
"start_exploring": "探索を始める"
},
"step_platform": {
"eyebrow": "コンピュータを接続",
"headline": "エージェントを実行するコンピュータを接続しましょう。",
"lede": "エージェントは、Multica に接続した実際のコンピュータで実行されます。どう接続するかを選んでください。",
"hint_default": "接続方法を選んでください。スキップしてあとでコンピュータを接続することもできます。",
"hint_downloaded": "ダウンロードページでセットアップを完了したら、このタブに戻ってください。",
"download_title": "このコンピュータを使う",
"download_title_after": "ダウンロードページを開いています…",
"download_subtitle": "デスクトップアプリをインストールして、このコンピュータを接続します。設定不要 — 次のページでプラットフォームを選ぶだけです。",
"download_subtitle_after": "新しいタブで開きました。そこでインストーラーを選び、デスクトップでセットアップを完了してください。",
"download_button": "ダウンロード",
"cli_title": "ターミナルから接続",
"cli_subtitle": "サーバー、リモート開発環境、ヘッドレスなコンピュータを接続します。ターミナルが必要です。",
"cli_action": "手順を表示",
"cloud_title": "クラウドコンピュータを使う",
"cloud_subtitle": "クラウドでコンピュータを動かします。まだ提供されていません。",
"cloud_action": "近日公開",
"cli_dialog_title": "ターミナルから接続",
"cli_dialog_description": "デスクトップと同じ接続を、ターミナルからセットアップします。サーバー、リモート開発環境、ヘッドレスなコンピュータに使ってください。",
"cli_dialog_pick_hint": "上でコンピュータを選んでください。",
"cli_dialog_connect": "接続して続ける",
"runtimes_connected_other": "コンピュータ {{count}} 台を接続済み",
"live_listening": "ライブ · あなたのコンピュータを待っています",
"stage_normal_prefix": "上のコマンドを実行してください。 ",
"stage_normal_suffix": " のブラウザでのサインインが終わると、コンピュータが自動でここに表示されます(通常 10〜30 秒)。",
"stage_midway_prefix": "まだ待っています。 ",
"stage_midway_suffix": " が開いたブラウザタブを完了したか確認してください — コンピュータが接続される前にサインインの承認が必要です。",
"stage_slow_prefix": "いつもより時間がかかっています。 ",
"stage_slow_suffix": " を実行したターミナルにエラーがないか確認してください。",
"stage_stalled_prefix": "まだ何も届いていません。ターミナルに不慣れな場合は、",
"stage_stalled_term": "デスクトップ",
"stage_stalled_suffix": "のほうがスムーズです — ワンクリックでこのコンピュータが接続されます。このダイアログを閉じてデスクトップを選ぶか、スキップを押して続けてください。"
},
"errors": {
"skip_failed": "オンボーディングを完了できませんでした"
}
}

View File

@@ -0,0 +1,120 @@
{
"page": {
"title": "プロジェクト",
"new_project": "新規プロジェクト",
"empty": "プロジェクトはまだありません",
"create_first": "最初のプロジェクトを作成",
"view_compact": "コンパクト",
"view_comfortable": "ゆったり",
"search_placeholder": "プロジェクトを検索...",
"no_search_results": "検索条件に一致する結果はありません"
},
"table": {
"name": "名前",
"priority": "優先度",
"status": "ステータス",
"progress": "進捗",
"lead": "リード",
"created": "作成日"
},
"status": {
"planned": "計画中",
"in_progress": "進行中",
"paused": "一時停止",
"completed": "完了",
"cancelled": "キャンセル"
},
"priority": {
"urgent": "緊急",
"high": "高",
"medium": "中",
"low": "低",
"none": "優先度なし"
},
"lead": {
"no_lead": "リードなし",
"assign_placeholder": "リードを割り当て...",
"members_group": "メンバー",
"agents_group": "エージェント",
"no_results": "結果なし"
},
"relative_date": {
"today": "今日",
"one_day_ago": "1日前",
"days_ago": "{{count}}日前",
"months_ago": "{{count}}か月前"
},
"detail": {
"not_found": "プロジェクトが見つかりません",
"breadcrumb_fallback": "プロジェクト",
"title_placeholder": "プロジェクトのタイトル",
"icon_tooltip": "アイコンを変更",
"pin_tooltip": "サイドバーに固定",
"unpin_tooltip": "サイドバーの固定を解除",
"sidebar_tooltip": "サイドバーの開閉",
"copy_link": "リンクをコピー",
"delete_action": "プロジェクトを削除",
"section_properties": "プロパティ",
"section_progress": "進捗",
"section_description": "説明",
"description_placeholder": "説明を追加...",
"empty_issues_title": "リンクされたイシューはありません",
"empty_issues_hint": "新しいイシューを作成するか、既存のイシューをこのプロジェクトに割り当ててください。",
"empty_issues_new_button": "新規イシュー",
"no_issues_yet": "イシューはまだありません",
"toast_link_copied": "リンクをコピーしました",
"toast_project_deleted": "プロジェクトを削除しました",
"toast_move_issue_failed": "イシューを移動できませんでした"
},
"resources": {
"section_header": "リソース",
"empty": "添付されたリソースはありません。",
"add_button": "リソースを追加",
"popover_title": "GitHub リポジトリを添付",
"repos_search_placeholder": "リポジトリを検索...",
"repos_search_empty": "検索条件に一致するリポジトリはありません。",
"attached_badge": "添付済み",
"remove_tooltip": "削除",
"url_placeholder": "https://github.com/owner/repo or git@github.com:owner/repo.git",
"url_submit": "追加",
"toast_attached": "リポジトリを添付しました",
"toast_attach_failed": "添付できませんでした",
"toast_removed": "リソースを削除しました",
"toast_remove_failed": "リソースを削除できませんでした",
"add_local_directory_button": "ローカルディレクトリを追加",
"local_daemon_offline_hint": "このマシンのディレクトリを添付するには、ローカルデーモンを起動してください。",
"local_daemon_already_attached_hint": "このマシンにはすでにローカルディレクトリが添付されています。新しく追加するには、先に既存のものを削除してください。",
"local_rename_tooltip": "名前を変更",
"local_rename_label": "ローカルディレクトリのラベル",
"local_no_daemon_tooltip": "ローカルデーモンがまだ ID を報告していないため、エージェントはこのディレクトリを開けません。",
"local_other_machine_tooltip": "このディレクトリを登録したマシンでのみ利用できます。",
"chat_hint_prefix": "エージェントは次の場所で直接作業します:",
"toast_local_attached": "ローカルディレクトリを添付しました",
"toast_local_renamed": "名前を変更しました",
"toast_local_rename_failed": "名前を変更できませんでした",
"toast_local_pick_failed": "ディレクトリを選択できませんでした",
"toast_local_already_attached": "このディレクトリはすでにこのマシンのプロジェクトに添付されています。",
"toast_local_daemon_already_attached": "このマシンにはすでにこのプロジェクトのローカルディレクトリが添付されています。新しく追加するには、先に既存のものを削除してください。",
"toast_local_daemon_not_running": "ローカルデーモンが実行されていません。",
"local_validate_not_absolute": "絶対パスを選択してください。",
"local_validate_not_found": "パスが存在しません。",
"local_validate_not_a_directory": "パスはディレクトリではありません。",
"local_validate_not_readable": "ディレクトリを読み取れません。",
"local_validate_not_writable": "ディレクトリに書き込めません。",
"local_validate_unsupported": "ローカルディレクトリはデスクトップアプリでのみ選択できます。"
},
"delete_dialog": {
"title": "プロジェクトを削除",
"description": "プロジェクトが削除されます。イシューは削除されませんが、リンクが解除されます。",
"confirm": "削除",
"cancel": "キャンセル"
},
"picker": {
"no_project": "プロジェクトなし",
"remove": "プロジェクトから削除",
"empty": "プロジェクトはまだありません"
},
"chip": {
"fallback_label": "プロジェクト"
}
}

View File

@@ -0,0 +1,315 @@
{
"page": {
"title": "ランタイム",
"tagline": "エージェントの CLI セッションを実行するマシンとクラウドワーカーです。",
"learn_more": "詳しく見る →",
"connect_remote": "コンピュータを追加",
"search_placeholder": "ランタイムを検索…",
"scope_mine": "自分のもの",
"scope_all": "すべて",
"live": "ライブ",
"live_tooltip": "リアルタイム更新 · オフライン検出は最大 75 秒",
"filter_all": "すべて",
"filter_all_description": "このビューのすべてのランタイム",
"empty": {
"title": "まだランタイムがありません",
"hint": "デスクトップ版はこのコンピュータを自動でスキャンします。別のマシン — サーバー、開発用マシン、ターミナルのあるコンピュータ — を使うには、ここに追加してください。"
},
"no_matches": {
"title": "一致する結果なし",
"with_query": "「{{query}}」に一致するランタイムがありません{{filterSuffix}}。",
"with_query_filter_suffix": "(このフィルター内)",
"no_query": "このフィルターに一致するランタイムがありません。",
"try_widening": " 範囲を広げるか、フィルターをクリアしてみてください。"
},
"bootstrapping": {
"title": "ローカルランタイムを起動中…",
"hint": "通常は数秒かかります。デーモンがワークスペースに登録しています。"
}
},
"machine": {
"search_placeholder": "マシンを検索…",
"filters": {
"all": "すべて",
"online": "オンライン",
"issues": "問題"
},
"section_local": "ローカル",
"section_remote": "リモート",
"section_cloud": "クラウド",
"this_machine": "このデバイス",
"local_badge": "ローカル · このマシン",
"runtime_count_other": "ランタイム {{count}} 個",
"busy_count_other": "使用中 {{count}} 個",
"no_matches_title": "マシンなし",
"no_matches_hint": "現在の検索またはフィルターに一致するマシンがありません。",
"select_machine": "マシンを選択して、そのランタイムを確認してください。",
"metrics": {
"runtimes": "ランタイム",
"runtimes_hint_other": "オンライン {{count}} 個",
"health": "状態",
"health_clear": "問題なし",
"health_issues_other": "問題 {{count}} 件",
"workload": "作業量",
"workload_value_idle": "アイドル",
"workload_idle": "すべてアイドル",
"workload_hint": "実行中 {{running}} 件 · キュー待ち {{queued}} 件",
"cli": "CLI",
"cloud_worker": "クラウドワーカー",
"local_daemon": "ローカルデーモン"
}
},
"health": {
"online": {
"label": "オンライン",
"description": "直近 45 秒以内に heartbeat を受信しました。タスクをディスパッチする準備ができています。"
},
"recently_lost": {
"label": "最近接続が切れました",
"description": "5 分以内に接続が切れました。短いネットワークの乱れであることが多いです。"
},
"offline": {
"label": "オフライン",
"description": "5 分以上 heartbeat がありません。デーモンを再起動するか、ホストを調べてください。"
},
"about_to_gc": {
"label": "まもなく削除",
"description": "6 日以上オフラインです。再接続しない限り、7 日目に自動削除されます。"
}
},
"detail": {
"all_runtimes": "すべてのランタイム",
"read_only": "読み取り専用",
"delete_button": "ランタイムを削除",
"delete_disabled_tooltip": "このランタイムは実行中のローカルデーモンが管理しており、数秒以内に自分で再登録します。完全に削除するには、デーモンプロセスを停止してください。",
"last_seen": "最終確認 {{when}}",
"fact_owner": "所有者",
"fact_device": "デバイス",
"fact_runtime": "ランタイム",
"technical_details": "技術的な詳細",
"fact_daemon_cli": "デーモン CLI",
"fact_daemon_id": "デーモン ID",
"serving_title": "提供中",
"serving_count_other": "エージェント {{count}} 個",
"no_agents": "まだこのランタイムに紐づいたエージェントがありません。",
"diagnostics_title": "診断",
"diagnostics_cli": "CLI",
"diagnostics_visibility": "公開範囲",
"visibility_label": {
"private": "非公開",
"public": "公開"
},
"visibility_hint": {
"private": "あなたとワークスペース管理者のみが、このランタイムでエージェントを作成できます。",
"public": "ワークスペースのメンバーなら誰でも、このランタイムでエージェントを作成できます。"
},
"visibility_toast_updated": "公開範囲を {{visibility}} に設定しました",
"visibility_toast_failed": "公開範囲を更新できませんでした",
"delete_dialog": {
"light": {
"title": "ランタイムを削除しますか?",
"description": "「{{name}}」を削除してもよろしいですか? この操作は元に戻せません。",
"cancel": "キャンセル",
"confirm": "ランタイムを削除",
"submitting": "削除中..."
},
"cascade": {
"title_other": "エージェント {{count}} 個をアーカイブして、このランタイムを削除しますか?",
"description": "「{{name}}」を削除します。下のエージェントはアーカイブされてアクティブなワークフローから除外され、キュー待ちまたは実行中のタスクはキャンセルされ、その後ランタイムが削除されます。",
"warning": "これは破壊的な操作です。アーカイブされたエージェントはアクティブなワークフローから除外され、キュー待ちまたは実行中のタスクはキャンセルされます。",
"notice_runtime_has_active_agents": "このダイアログを開いてからアクティブなエージェントが追加されました。新しい計画を確認して承認してください。",
"notice_runtime_delete_plan_changed": "このダイアログを開いている間にアクティブなエージェントの一覧が変わりました。新しい計画を確認して承認してください。",
"checkbox_other": "エージェント {{count}} 個がアーカイブされ、キュー待ちまたは実行中のタスクがキャンセルされることを理解しました。",
"cancel": "キャンセル",
"confirm_other": "エージェント {{count}} 個をアーカイブしてランタイムを削除",
"submitting": "アーカイブして削除中...",
"self_healing_blocked_toast": "このランタイムは実行中のローカルデーモンが管理しており、自分で再登録します。",
"delete_failed_toast": "ランタイムを削除できませんでした",
"table": {
"header_agent": "エージェント",
"header_owner": "所有者",
"header_status": "ステータス",
"header_visibility": "公開範囲",
"header_model": "モデル",
"owner_self": "あなた",
"owner_unassigned": "—",
"model_unset": "—",
"presence_unknown": "—",
"workload_idle": "アイドル",
"workload_working": "作業中",
"workload_queued": "キュー待ち",
"visibility_workspace": "ワークスペース",
"visibility_private": "非公開"
}
}
},
"toast_deleted": "ランタイムを削除しました",
"toast_delete_failed": "ランタイムを削除できませんでした",
"running_chip_other": "· 実行中 {{count}} 件",
"queued_chip_other": "· キュー待ち {{count}} 件"
},
"detail_page": {
"not_found_title": "ランタイムが見つかりません",
"not_found_hint": "削除されたか、アクセス権がない可能性があります。"
},
"running_other": "実行中 {{count}} 件",
"queued_other": "キュー待ち {{count}} 件",
"connect": {
"title": "コンピュータを追加",
"description": "追加したいコンピュータで、この 2 つのコマンドを実行してください。デーモンがオンラインになった瞬間に検出します。",
"step1_label": "Multica CLI をインストール",
"step2_label": "デーモンを起動",
"step2_hint": "サインインのためにブラウザを開き、その後デーモンをバックグラウンドで実行し続けます。",
"live_listening": "あなたのコンピュータを待っています",
"live_listening_hint": "デーモンが起動するとすぐに検出します — 通常は 1 分以内です。",
"troubleshooting": "そのコンピュータでブラウザを開けませんか?",
"trouble_intro": "ブラウザでのサインインの代わりにトークンを使ってください。手順 2 を置き換え、ターミナルがある場所ならどこでも動作します。",
"trouble_token_hint_prefix": "トークンは ",
"trouble_token_hint_destination": "設定 → トークン",
"trouble_token_hint_suffix": " で作成できます。デーモンは外向きの接続のみを行うため、インバウンドポートは不要です。",
"trouble_check_status": "ステータスを確認",
"trouble_view_logs": "ログを表示",
"copy_aria": "コピー",
"cancel": "キャンセル",
"success_title": "コンピュータを接続しました",
"success_description": "コンピュータがオンラインになり、準備ができました。エージェントを作成すると、ここでタスクを引き受け始められます。",
"view_runtime": "ランタイムを表示",
"create_agent": "エージェントを作成"
},
"cloud_runtime": {
"action": "クラウドランタイム",
"title": "クラウドランタイム",
"description": "マネージドなクラウドノードを起動し、その Fleet ステータスを確認します。",
"create_title": "新規ノード",
"create_hint": "名前、インスタンスタイプ、ディスクサイズを選んでください。残りは Fleet が適用します。",
"nodes_title": "Fleet ノード",
"refresh": "更新",
"nodes_empty": "クラウドノードなし",
"nodes_failed": "クラウドランタイムを利用できません",
"nodes_failed_hint": "Fleet がノード一覧を返しませんでした。",
"node_fallback_name": "クラウドノード",
"create": "ノードを作成",
"creating": "作成中...",
"cancel": "キャンセル",
"toast_created": "クラウドランタイムノードを作成しました",
"toast_create_failed": "クラウドランタイムノードを作成できませんでした",
"delete": "ノードを削除",
"delete_confirm": "このクラウドノードを削除してもよろしいですか? この操作は元に戻せません。",
"toast_deleted": "クラウドノードを削除しました",
"toast_delete_failed": "クラウドノードを削除できませんでした",
"fields": {
"name": "名前",
"instance_type": "インスタンスタイプ",
"region": "リージョン",
"disk_size": "ディスクサイズ GiB",
"image_id": "AMI ID",
"subnet_id": "Subnet ID",
"key_name": "キーペア",
"bootstrap_pat": "Bootstrap PAT"
},
"placeholders": {
"name": "cloud-dev-01",
"key_name": "dev-key"
},
"validation": {
"instance_type_required": "インスタンスタイプは必須です",
"disk_size_invalid": "ディスクサイズは正の整数である必要があります"
}
},
"update": {
"cli_version_label": "CLI バージョン:",
"version_unknown": "不明",
"managed_by_desktop": "デスクトップで管理",
"managed_by_desktop_title": "CLI バイナリは Multica Desktop で管理されています。CLI をアップグレードするには Desktop を更新してください。",
"latest": "最新",
"available": "利用可能",
"action": "更新",
"retry": "再試行",
"unknown_error": "不明なエラー",
"initiate_failed": "更新を開始できませんでした",
"status": {
"pending": "デーモンを待っています...",
"running": "更新中...",
"completed": "更新が完了しました。デーモンを再起動しています...",
"failed": "更新に失敗しました",
"timeout": "タイムアウト"
}
},
"charts": {
"heatmap_less": "少ない",
"heatmap_more": "多い",
"tooltip_total": "合計"
},
"list": {
"col_runtime": "ランタイム",
"col_health": "状態",
"col_owner": "所有者",
"col_agents": "エージェント",
"col_workload": "作業量",
"col_cost": "コスト · 7 日",
"col_cli": "CLI",
"cost_delta_flat": "変化なし",
"cli_managed_badge": "デスクトップ",
"cli_update_available_aria": "更新あり",
"cli_update_available_tooltip": "更新あり: {{version}}",
"row_actions_aria": "行の操作",
"delete_action": "削除",
"delete_permission_hint": "ランタイムの所有者とワークスペース管理者のみが、このランタイムを削除できます",
"delete_admin_hint": "ランタイムの所有者とワークスペース管理者のみが、ランタイムを削除できます。"
},
"usage": {
"period_label": "期間",
"dimension_label": "ディメンション",
"kpi_cost_label": "コスト · {{days}} 日",
"kpi_cost_delta": "前期比 {{sign}}{{pct}}%",
"kpi_cache_label": "キャッシュによる節約 · {{days}} 日",
"kpi_cache_hint": "ヒット率 {{pct}}% · 読み取り {{reads}}",
"kpi_tokens_label": "トークン · {{days}} 日",
"kpi_tokens_hint": "入力 {{input}} · 出力 {{output}}",
"when_title": "このランタイムでコストが発生した時期",
"when_tab_daily": "日別",
"when_tab_weekly": "週別",
"when_tab_heatmap": "ヒートマップ",
"daily_metric_cost": "コスト",
"daily_metric_tokens": "トークン",
"weekly_partial_label": "{{range}}(一部 · 7 日中 {{covered}} 日)",
"heatmap_caption": "直近 26 週 · 日別の $ 強度(ここでは期間セレクターは無視されます)",
"legend_input": "入力",
"legend_output": "出力",
"legend_cache_read": "キャッシュ読み取り",
"legend_cache_write": "キャッシュ書き込み",
"empty_no_usage": "この期間には使用量がありません。",
"empty_pricing_missing": "トークンは記録されましたが、次のモデルの価格情報がありません:",
"empty_pricing_hint": "コスト合計に含めるには、カスタム単価を設定してください。",
"empty_zero_cost": "トークンは記録されましたが、コスト計算の結果は $0 でした。",
"unmapped_notice_other": "管理された価格がないモデルが {{count}} 個あり、そのトークンはコスト合計から除外されています。",
"custom_pricing": {
"open_button": "カスタム価格を設定",
"title": "カスタムモデル価格",
"description": "管理された単価を提供していないモデルの価格を計算できるよう、100 万トークンあたりの単価を入力してください。このマシンにローカルで保存されます。",
"empty": "今のところ、カスタム価格が必要なモデルはありません。",
"field_input": "入力",
"field_output": "出力",
"field_cache_read": "キャッシュ読み取り",
"field_cache_write": "キャッシュ書き込み",
"unit_hint": "すべての単価は 100 万トークンあたりの USD です。上書きを削除するには、すべてのフィールドを空にしてください。",
"remove_aria": "カスタム価格を削除",
"cancel": "キャンセル",
"save": "保存"
},
"cost_by_title_agent": "エージェント別コスト",
"cost_by_title_model": "モデル別コスト",
"cost_by_tab_agent": "エージェント別",
"cost_by_tab_model": "モデル別",
"cost_by_caption_agent_other": "このランタイムのエージェント {{count}} 個",
"cost_by_caption_model_other": "使用されたモデル {{count}} 個",
"daily_breakdown_toggle": "日別内訳テーブル",
"table_date": "日付",
"table_model": "モデル",
"table_input": "入力",
"table_output": "出力",
"table_cache_r": "キャッシュ R",
"table_cache_w": "キャッシュ W",
"no_data": "まだ使用量データがありません"
}
}

View File

@@ -0,0 +1,44 @@
{
"title": "検索",
"description": "ページ、イシュー、プロジェクト、メンバーを検索します",
"placeholder": "コマンドを入力するか検索...",
"groups": {
"pages": "ページ",
"commands": "コマンド",
"members": "メンバー",
"projects": "プロジェクト",
"issues": "イシュー",
"recent": "最近の項目"
},
"pages": {
"inbox": "インボックス",
"my_issues": "マイイシュー",
"issues": "イシュー",
"projects": "プロジェクト",
"agents": "エージェント",
"runtimes": "ランタイム",
"skills": "スキル",
"settings": "設定"
},
"commands": {
"current_theme_aria": "現在のテーマ",
"new_issue": "新規イシュー",
"new_project": "新規プロジェクト",
"copy_issue_link": "イシューのリンクをコピー",
"copy_identifier": "識別子をコピー ({{identifier}})",
"switch_to_light": "ライトテーマに切り替え",
"switch_to_dark": "ダークテーマに切り替え",
"use_system_theme": "システムテーマを使用"
},
"toast": {
"link_copied": "リンクをコピーしました",
"copied_identifier": "{{identifier}}をコピーしました"
},
"empty": {
"no_results": "結果が見つかりませんでした。",
"type_to_search": "イシューやプロジェクトを検索するには入力してください"
},
"trigger": {
"label": "検索..."
}
}

View File

@@ -0,0 +1,303 @@
{
"preferences": {
"theme": {
"title": "テーマ",
"light": "ライト",
"dark": "ダーク",
"system": "システム"
},
"language": {
"title": "言語",
"english": "English",
"chinese": "中文",
"korean": "한국어",
"japanese": "日本語",
"sync_failed": "このデバイスに言語を保存しましたが、アカウントへの同期に失敗しました。他のデバイスでは以前の言語が表示される場合があります。"
},
"timezone": {
"title": "表示タイムゾーン",
"browser_suffix": " (ブラウザ)",
"hint": "ダッシュボード、チャート、表示される「今日」ラベルに使用されます。すべてのワークスペースに適用される個人設定です。",
"sync_failed": "タイムゾーン設定を保存できませんでした。"
}
},
"page": {
"title": "設定",
"my_account": "マイアカウント",
"workspace_fallback": "ワークスペース",
"tabs": {
"profile": "プロフィール",
"preferences": "環境設定",
"notifications": "通知",
"tokens": "API トークン",
"general": "一般",
"repositories": "リポジトリ",
"github": "GitHub",
"integrations": "連携",
"labs": "ラボ",
"members": "メンバー"
}
},
"account": {
"section_profile": "プロフィール",
"click_avatar_hint": "クリックしてアバターをアップロード",
"name_label": "名前",
"profile_description_label": "自己紹介",
"profile_description_hint": "あなたの代わりに作業するエージェントに共有されます。役割、技術スタック、好みなど、新しいコラボレーターに初日に伝えたいことを書いてください。",
"profile_description_placeholder": "例: Go と Postgres を使うバックエンドエンジニア。簡潔な PR と変更に合わせたテストを好みます。",
"profile_description_too_long": "プロフィールが長すぎます(最大 {{max}} 文字、現在 {{count}} 文字)。",
"save": "プロフィールを更新",
"saving": "更新中...",
"toast_avatar_updated": "アバターを更新しました",
"toast_avatar_failed": "アバターをアップロードできませんでした",
"toast_profile_updated": "プロフィールを更新しました",
"toast_profile_failed": "プロフィールを更新できませんでした"
},
"notifications": {
"title": "インボックス通知",
"description": "どのイベントがインボックス通知を生成するかを制御します。ミュートしたイベントタイプは静かにフィルタされますが、イシューを直接開けば引き続き確認できます。",
"toast_failed": "通知設定を更新できませんでした",
"groups": {
"assignments": {
"label": "担当の割り当て",
"description": "イシューの担当者に割り当てられたとき、または解除されたとき"
},
"status_changes": {
"label": "ステータス変更",
"description": "フォロー中のイシューのステータスが変わったとき(例: todo、in progress、done"
},
"comments": {
"label": "コメントとメンション",
"description": "フォロー中のイシューに新しいコメントが付いたとき、または誰かがあなたを @メンションしたとき"
},
"updates": {
"label": "優先度と期限",
"description": "フォロー中のイシューの優先度や期限が変わったとき"
},
"agent_activity": {
"label": "エージェントのアクティビティ",
"description": "エージェントのタスクが完了または失敗したとき"
}
},
"system": {
"title": "システム通知",
"description": "Multica がバックグラウンドにあるときに表示される OS のネイティブ通知バナーを制御します。",
"label": "システム通知を表示",
"hint": "アプリにフォーカスがないときに、新しいインボックス項目について OS のバナーを表示します。"
}
},
"tokens": {
"title": "API トークン",
"description": "個人アクセストークンを使うと、CLI や外部連携があなたのアカウントで認証できます。",
"name_placeholder": "トークン名(例: My CLI",
"expiry": {
"30": "30 日",
"90": "90 日",
"365": "1 年",
"never": "有効期限なし"
},
"create": "作成",
"creating": "作成中...",
"toast_load_failed": "トークンを読み込めませんでした",
"toast_create_failed": "トークンを作成できませんでした",
"toast_revoked": "トークンを失効しました",
"toast_revoke_failed": "トークンを失効できませんでした",
"metadata_prefix": "{{prefix}}... · 作成 {{created}} · {{lastUsed}}",
"last_used_with_date": "最終使用 {{date}}",
"last_used_never": "未使用",
"expires_with_date": " · 有効期限 {{date}}",
"revoke_aria": "{{name}} を失効",
"revoke_tooltip": "失効",
"revoke_dialog": {
"title": "トークンを失効",
"description": "このトークンは永久に失効し、以降は使用できなくなります。この操作は元に戻せません。",
"cancel": "キャンセル",
"confirm": "失効"
},
"created_dialog": {
"title": "トークンを作成しました",
"description": "今すぐ個人アクセストークンをコピーしてください。再表示はできません。",
"copy_tooltip": "トークンをコピー",
"done": "完了"
}
},
"workspace": {
"section_general": "一般",
"name_label": "名前",
"description_label": "説明",
"description_placeholder": "このワークスペースは何に注力していますか?",
"context_label": "コンテキスト",
"context_placeholder": "このワークスペースで作業する AI エージェント向けの背景情報とコンテキスト",
"slug_label": "スラッグ",
"issue_prefix_label": "イシュー接頭辞",
"issue_prefix_hint": "{{example}} のようなイシュー番号に使用されます。",
"prefix_confirm_title": "イシュー接頭辞を変更しますか?",
"prefix_confirm_description": "すべてのイシュー番号が {{oldPrefix}}-N から {{newPrefix}}-N に振り直されます。Pull request のタイトル、ブランチ名、ドキュメントやチャットのリンクなど、{{oldPrefix}}-N を使用している外部参照は解決されなくなります。",
"save": "保存",
"saving": "保存中...",
"manage_hint": "ワークスペース設定を更新できるのは admin と owner のみです。",
"toast_saved": "ワークスペース設定を保存しました",
"toast_save_failed": "ワークスペース設定を保存できませんでした",
"danger_zone": "危険な操作",
"leave_title": "ワークスペースを退出",
"leave_sole_owner": "あなたは唯一の owner です。先に別のメンバーを owner に昇格させるか、ワークスペースを削除してください。",
"leave_sole_member": "あなたは唯一のメンバーです。退出するにはワークスペースを削除してください。",
"leave_default": "このワークスペースからあなた自身を削除します。",
"leave_button": "ワークスペースを退出",
"leaving": "退出中...",
"leave_confirm_title": "ワークスペースを退出",
"leave_confirm_description": "{{name}} から退出しますか?再招待されるまでアクセスできなくなります。",
"toast_leave_failed": "ワークスペースから退出できませんでした",
"delete_title": "ワークスペースを削除",
"delete_description": "このワークスペースとそのデータを完全に削除します。",
"delete_button": "ワークスペースを削除",
"deleting": "削除中...",
"toast_delete_failed": "ワークスペースを削除できませんでした",
"confirm_cancel": "キャンセル",
"confirm_action": "確認",
"change_logo_aria": "ワークスペースのロゴを変更",
"click_logo_hint": "ロゴをクリックして新しい画像をアップロード",
"toast_logo_updated": "ワークスペースのロゴを更新しました",
"toast_logo_failed": "ワークスペースのロゴをアップロードできませんでした"
},
"delete_workspace_dialog": {
"title": "ワークスペースを削除",
"description": "この操作は元に戻せません。すべてのイシュー、エージェント、データが完全に削除されます。",
"type_to_confirm_prefix": "確認するには、下に",
"type_to_confirm_suffix": " と入力してください。",
"cancel": "キャンセル",
"confirm": "ワークスペースを削除",
"deleting": "削除中..."
},
"labs": {
"section_placeholder_title": "まだ実験機能はありません",
"section_placeholder_description": "実験的な設定はリリースされ次第ここに表示されます。現在このタブは意図的に空にしてあります。",
"toast_failed": "設定を更新できませんでした"
},
"integrations": {
"section_title": "連携",
"empty_title": "まだサードパーティ連携はありません",
"empty_description": "Slack、Linear などの連携が設定されると、ここに表示されます。GitHub は専用タブに移動しました。",
"manage_hint": "連携を管理できるのは admin と owner のみです。"
},
"github": {
"page_description": "GitHub App を接続し、Pull request が Multica 内でどう表示されるかを制御し、エージェントがコミット履歴に残す情報を設定します。",
"section_master": "GitHub 機能を有効にする",
"master_description_on": "オフにすると、すべての GitHub UI が非表示になり、新しい副作用が記録されなくなります。既存のデータはバックエンドに保持されます。開発チームではありませんか?ここでオフにできます。",
"master_description_off": "GitHub 機能はオフです。PR サイドバー、Co-authored-by トレーラー、自動リンクが一時停止されています。バックエンドのデータは削除されません。",
"section_connection": "接続",
"connection_title": "GitHub App",
"connection_description_prefix": "イシューを Pull request に自動でリンクします。ブランチ、タイトル、または本文に",
"connection_description_suffix": "を含む PR がマージされると、対応するイシューが次のステータスに移動します:",
"connection_description_done": "完了",
"connection_identifier_example": "MUL-123",
"connected_to": "{{login}} に接続済み",
"connect_github": "GitHub を接続",
"connect_opening": "開いています…",
"connect_disabled_tooltip": "このサーバーには GitHub App が設定されていません",
"disconnect": "接続解除",
"disconnecting": "接続解除中…",
"disconnect_confirm_title": "GitHub App の接続を解除",
"disconnect_confirm_description": "Multica はこのインストールの Webhook 受信を停止します。既存の PR ミラーとリンクは保持され、いつでも再接続して更新を再開できます。",
"disconnect_confirm_cancel": "キャンセル",
"disconnect_confirm_action": "接続解除",
"not_configured": "このデプロイには GitHub 連携が設定されていません。運営者が次の値を設定する必要があります:",
"not_configured_and": "および",
"read_only_hint": "読み取り専用ビューです。GitHub を接続または解除できるのはワークスペースの admin と owner のみです。",
"contact_admin_to_connect": "このワークスペースには GitHub が接続されていません。admin または owner に GitHub App のセットアップを依頼してください。",
"connected_by": "{{name}} が接続",
"toast_not_configured": "このデプロイには GitHub 連携が設定されていません",
"toast_open_failed": "GitHub のインストール画面を開けませんでした",
"toast_disconnect_failed": "GitHub App の接続を解除できませんでした",
"toast_disconnected": "GitHub App の接続を解除しました",
"section_features": "機能",
"feature_pr_sidebar_label": "Pull request サイドバー",
"feature_pr_sidebar_description": "リンクされた Pull request をイシュー詳細サイドバーに表示します。",
"feature_co_author_label": "Co-authored-by トレーラー",
"feature_co_author_description_prefix": "エージェントが作成したコミットに",
"feature_co_author_description_suffix": "を追加します。",
"feature_auto_link_label": "イシューと PR を自動リンク",
"feature_auto_link_description": "PR のタイトル、本文、ブランチ名をイシュー識別子と照合し、自動でリンクを作成します。",
"section_repositories": "リポジトリ",
"repositories_shortcut_label": "リポジトリ URL はリポジトリタブにあります",
"repositories_shortcut_link": "リポジトリを管理 →",
"toast_failed": "GitHub 設定を更新できませんでした"
},
"repositories": {
"section_title": "リポジトリ",
"description": "このワークスペースに関連付けられた Git リポジトリです。エージェントはこれらをクローンしてコードを作業します。",
"url_placeholder": "https://git.example.com/org/repo.git または git@git.example.com:org/repo.git",
"url_empty": "(空の URL",
"description_placeholder": "説明(例: Go バックエンド + Next.js フロントエンド)",
"add": "リポジトリを追加",
"save": "保存",
"saving": "保存中...",
"saved_hint": "すべての変更を保存しました",
"empty": "まだリポジトリがありません。",
"edit_aria": "リポジトリを編集",
"cancel_aria": "編集をキャンセル",
"delete_aria": "リポジトリを削除",
"manage_hint": "リポジトリを管理できるのは admin と owner のみです。",
"toast_saved": "リポジトリを保存しました",
"toast_save_failed": "リポジトリを保存できませんでした"
},
"desktop": {
"tabs": {
"updates": "アップデート"
},
"updates": {
"title": "アップデート",
"description": "デスクトップアプリは 1 時間に 1 回、および起動直後に新しいバージョンを自動で確認し、バックグラウンドでダウンロードします。アップデートの準備が整うと、再起動を促すメッセージが表示されます。",
"current_version": "現在のバージョン",
"check_section_title": "アップデートを確認",
"check_section_description": "次回の自動確認を待たずに、今すぐ確認します。利用可能なアップデートはバックグラウンドでダウンロードされ、準備が整うと再起動を促すメッセージが表示されます。",
"up_to_date": "最新バージョンを使用しています。",
"downloading": "v{{version}} をバックグラウンドでダウンロード中です。インストールの準備が整うとお知らせします。",
"check_now": "今すぐ確認",
"checking": "確認中…"
}
},
"members": {
"section_title": "メンバー({{count}}",
"invite_title": "メンバーを招待",
"invite_email_placeholder": "user@company.com",
"invite_button": "招待",
"inviting": "招待中...",
"toast_invitation_sent": "招待を送信しました",
"toast_invitation_failed": "招待を送信できませんでした",
"no_members": "メンバーが見つかりません。",
"pending_title": "保留中の招待({{count}}",
"pending_status": "保留中",
"revoke_invitation_tooltip": "招待を取り消し",
"revoke_invitation_title": "招待を取り消し",
"revoke_invitation_description": "{{email}} への招待を取り消しますか?このワークスペースに参加できなくなります。",
"toast_invitation_revoked": "招待を取り消しました",
"toast_invitation_revoke_failed": "招待を取り消せませんでした",
"toast_role_updated": "ロールを更新しました",
"toast_role_failed": "メンバーを更新できませんでした",
"toast_member_removed": "メンバーを削除しました",
"toast_member_remove_failed": "メンバーを削除できませんでした",
"remove_member_title": "{{name}} を削除",
"remove_member_description": "{{workspace}} から {{name}} を削除しますか?このワークスペースへのアクセスを失います。",
"confirm_cancel": "キャンセル",
"confirm_action": "確認",
"change_role": "ロールを変更",
"remove_action": "ワークスペースから削除",
"cannot_demote_last_owner_title": "先に別のメンバーを owner に昇格させてください。ワークスペースには少なくとも 1 人の owner が必要です。",
"cannot_demote_last_owner": "最後の owner は降格できません",
"roles": {
"owner": {
"label": "オーナー",
"description": "フルアクセス、すべての設定を管理"
},
"admin": {
"label": "管理者",
"description": "メンバーと設定を管理"
},
"member": {
"label": "メンバー",
"description": "イシューの作成と作業"
}
}
}
}

View File

@@ -0,0 +1,245 @@
{
"page": {
"title": "スキル",
"tagline": "このワークスペースのどのエージェントでも使用できる指示です。",
"learn_more": "詳しく見る →",
"new_skill": "新規スキル",
"search_placeholder": "スキルを検索…",
"scopes": {
"all": { "label": "すべて", "description": "このワークスペースのすべてのスキル" },
"used": { "label": "使用中", "description": "1 つ以上のエージェントに割り当てられたスキル" },
"unused": { "label": "未使用", "description": "どのエージェントにも割り当てられていないスキル" },
"mine": { "label": "自分が作成", "description": "あなたが作成したスキル" }
},
"empty": {
"title": "まだスキルがありません",
"description": "最初のスキルを作成するか、URL からインポートするか、接続済みのランタイムからコピーしてください。ワークスペースのすべてのエージェントが使用できます。"
},
"no_matches": {
"title": "一致なし",
"with_query": "「{{query}}」に一致するスキルがありません{{filterSuffix}}。",
"with_query_filter_suffix": "(このフィルター内)",
"filter_only": "このフィルターに一致するスキルがありません。",
"try_different": " 別の検索語を試してください。"
},
"intro_banner": {
"title": "ワークスペースと共有されます。",
"body": "誰でもスキルを作成したり、URL からインポートしたり、ローカルランタイムからコピーしたりでき、すべてのエージェントが使用できます。",
"highlight": "ローカルランタイムのスキルは、ここにコピーするまで非公開のままです。"
},
"list_error": {
"title": "スキルを読み込めませんでした",
"fallback": "スキル一覧の取得中に問題が発生しました。",
"retry": "再試行"
},
"supporting_data_warning": "一部のワークスペースデータを読み込めませんでした。作成者の表示、ランタイム名、編集権限が不完全に見える場合があります。"
},
"table": {
"name": "名前",
"used_by": "使用中",
"source": "ソース · 追加者",
"updated": "更新日",
"no_description": "説明なし",
"lock_tooltip": "読み取り専用 — 作成者または管理者のみが編集できます",
"unused": "— 未使用",
"by_creator": "{{name}}",
"source_manual": "手動で作成",
"source_runtime_named": "{{name}} から",
"source_runtime_provider": "{{provider}} ランタイムから",
"source_runtime_unknown": "ランタイムから",
"source_clawhub": "ClawHub から",
"source_skills_sh": "Skills.sh から",
"source_github": "GitHub から"
},
"detail": {
"all_skills": "すべてのスキル",
"read_only": "読み取り専用",
"delete_aria": "スキルを削除",
"delete_tooltip": "スキルを削除",
"supporting_data_warning": "一部のワークスペースデータを読み込めませんでした。次回の更新まで、作成者の表示、ランタイム名、編集権限が不完全に見える場合があります。",
"files_label": "ファイル · {{count}}",
"add_file_aria": "ファイルを追加",
"add_file_tooltip": "ファイルを追加",
"delete_file": "ファイルを削除",
"name_aria": "スキル名",
"name_placeholder": "skill-name",
"description_label": "説明",
"description_placeholder": "エージェントがこのスキルをいつ使うべきかを 1 文で説明してください…",
"subline": {
"origin_runtime_named": "ローカルランタイム · {{name}}",
"origin_runtime_provider": "ローカルランタイム · {{provider}}",
"origin_runtime_unknown": "ローカルランタイム",
"origin_clawhub": "インポート済み · ClawHub",
"origin_skills_sh": "インポート済み · Skills.sh",
"origin_github": "インポート済み · GitHub",
"origin_workspace": "ワークスペース",
"updated_label": "{{when}} に更新",
"by_creator": "{{name}}"
},
"conflict_banner": {
"title": "他のユーザーがこのスキルを更新しました",
"body": "あなたの編集内容は保持されています。破棄すると相手の変更を取り込み、保存すると上書きします。"
},
"save_bar": {
"unsaved": "未保存の変更 — 保存すると現在のスキルを上書きします",
"discard": "破棄",
"save": "変更を保存",
"saving": "保存中…"
},
"sidebar": {
"metadata": "メタデータ",
"created": "作成日",
"updated": "更新日",
"created_by": "作成者",
"files": "ファイル",
"id": "ID",
"origin": "ソース",
"used_by_other": "{{count}} 個のエージェントが使用中",
"permissions": "権限",
"permissions_owner": "このスキルを編集および削除できます。変更は次回のエージェント実行から有効になります。",
"permissions_locked_creator": "このスキルを編集できるのは作成者({{name}})またはワークスペース管理者のみです。",
"permissions_locked": "このスキルを編集できるのは作成者またはワークスペース管理者のみです。",
"used_by_empty": "まだどのエージェントにも割り当てられていません。エージェントのスキルタブを開いて割り当ててください。"
},
"origin_card": {
"imported_runtime": "ローカルランタイムからインポート",
"imported_clawhub": "ClawHub からインポート",
"imported_skills_sh": "Skills.sh からインポート",
"imported_github": "GitHub からインポート",
"provider": "プロバイダー · {{provider}}"
},
"not_found": {
"title": "スキルが見つかりません",
"fallback": "このスキルは削除されたか、アクセス権を失った可能性があります。",
"back": "スキルに戻る"
},
"toast_saved": "スキルを保存しました",
"toast_save_failed": "スキルを保存できませんでした",
"toast_deleted": "スキルを削除しました",
"toast_delete_failed": "スキルを削除できませんでした",
"delete_dialog": {
"title": "スキルを削除しますか?",
"description_with_agents_other": "「{{name}}」を完全に削除し、現在使用中の {{count}} 個のエージェントから削除します。",
"description_no_agents": "「{{name}}」を完全に削除し、すべてのエージェントから削除します。",
"warning": "この操作は元に戻せません。",
"cancel": "キャンセル",
"confirm": "完全に削除",
"deleting": "削除中…"
},
"add_file": {
"placeholder": "templates/review.md",
"add": "追加",
"cancel": "キャンセル",
"errors": {
"empty": "パスは空にできません。",
"absolute": "絶対パスは使用できません。",
"double_dot": "パスに「..」を含めることはできません。",
"reserved": "SKILL.md はメインファイル用に予約されています。",
"exists": "このパスにはすでにファイルが存在します。"
}
}
},
"create": {
"back": "戻る",
"back_aria": "方式の選択に戻る",
"close": "閉じる",
"close_aria": "閉じる",
"method": {
"chooser": {
"title": "新規スキル",
"desc": "このワークスペースにスキルを追加する方法を選択してください。"
},
"manual": {
"title": "手動で作成",
"desc": "新しい SKILL.md を一から作成します。"
},
"url": {
"title": "URL からインポート",
"desc": "公開済みのスキルを URL で取得します。ファイルはサーバー側で取得されます。"
},
"runtime": {
"title": "ランタイムからコピー",
"desc": "ローカルランタイムをスキャンし、ディスク上のスキルの 1 つをこのワークスペースに昇格します。"
}
},
"method_card": {
"manual_title": "手動で作成",
"manual_desc": "空の SKILL.md から始めて、独自の指示を記述します。",
"url_title": "URL からインポート",
"url_desc": "ClawHub または Skills.sh の公開スキルを取得します。",
"runtime_title": "ランタイムからコピー",
"runtime_desc": "ローカルランタイムにすでにインストールされているスキルを昇格します。"
},
"manual": {
"name_label": "名前",
"name_placeholder": "例: review-helper",
"name_hint": "ワークスペース内で一意である必要があります。",
"description_label": "説明",
"description_placeholder": "このスキルをエージェントにいつ割り当てるべきかを 1 文で書いてください。",
"name_conflict_hint": " 別の名前で再度送信してください。",
"fallback_error": "スキルを作成できませんでした",
"cancel": "キャンセル",
"submit": "スキルを作成",
"submitting": "作成中…",
"toast_created": "スキルを作成しました"
},
"url": {
"url_label": "スキル URL",
"supported_sources": "対応ソース",
"import": "インポート",
"importing": "インポート中…",
"importing_clawhub": "ClawHub からインポート中…",
"importing_skills_sh": "Skills.sh からインポート中…",
"importing_github": "GitHub からインポート中…",
"name_conflict_hint": " インポートしたスキル名はすでに存在します。再試行する前に既存のものを削除してください。",
"fallback_error": "インポートに失敗しました",
"cancel": "キャンセル",
"toast_imported": "スキルをインポートしました"
}
},
"runtime_import": {
"runtime_label": "ランタイム",
"runtime_placeholder": "ローカルランタイムを選択",
"no_local_runtimes_title": "利用可能なローカルランタイムがありません",
"no_local_runtimes_hint": "ローカルスキルを参照してインポートするには、ローカルランタイムを接続してください。",
"choose_runtime": "続行するにはランタイムを選択してください",
"must_be_online": "ローカルスキルを参照するには、ランタイムがオンラインである必要があります。",
"load_failed": "ランタイムのローカルスキルを読み込めませんでした",
"not_supported": "このランタイムプロバイダーは、まだローカルスキル一覧の取得に対応していません。",
"no_skills_title": "ローカルスキルが見つかりません",
"no_skills_hint": "このランタイムには、まだ検出可能なローカルスキルがありません。",
"ignored_files_hint": "シンボリックリンク、読み取れないファイル、サイズが大きすぎるファイル、非常に大きなバンドルはインポート時に無視されます。",
"ready": "インポートの準備完了",
"into_workspace": "をこのワークスペースに。",
"select_skill": "続行するにはスキルを選択してください。",
"import_button": "ワークスペースにインポート",
"importing": "インポート中…",
"skill_files_other": "{{count}} 個のファイル",
"skill_name_label": "ワークスペースのスキル名",
"skill_description_label": "説明",
"skill_description_placeholder": "任意 — エージェントがこのスキルをいつ使うべきかを説明してください。",
"toast_imported": "スキルをインポートしました",
"toast_import_failed": "スキルをインポートできませんでした",
"select_all": "すべて選択({{count}}",
"bulk_ready": "{{count}} 個のスキルを選択中",
"bulk_import_button": "{{count}} 個のスキルをインポート",
"bulk_progress": "インポート中 {{completed}} / {{total}}…",
"bulk_cancel_button": "キャンセル",
"bulk_complete_hint": "インポートが完了しました。",
"bulk_cancelled_hint": "インポートをキャンセルしました。",
"bulk_done_button": "完了",
"bulk_summary_imported": "インポート済み",
"bulk_summary_skipped": "スキップ",
"bulk_summary_failed": "失敗"
},
"file_tree": {
"no_files": "ファイルなし"
},
"file_viewer": {
"edit_tooltip": "編集",
"preview_tooltip": "プレビュー",
"no_content": "*まだ内容がありません*",
"markdown_placeholder": "Markdown の内容を記述...",
"raw_placeholder": "ファイルの内容..."
}
}

View File

@@ -0,0 +1,73 @@
{
"page": {
"title": "スクワッド",
"new_button": "新規スクワッド",
"empty_no_squads": "スクワッドはまだありません。作成して始めましょう。",
"empty_no_match": "フィルターに一致するスクワッドはありません。"
},
"inspector": {
"details_section": "詳細",
"archive_button": "アーカイブ"
},
"archive_dialog": {
"title": "このスクワッドをアーカイブしますか?",
"description": "\"{{name}}\" がアーカイブされます。現在このスクワッドに割り当てられているイシューはリーダーに引き継がれます。この操作は取り消せません。ルーティングを元に戻すには、新しいスクワッドを作成してください。",
"cancel": "キャンセル",
"confirm": "アーカイブ",
"archiving": "アーカイブ中…"
},
"name_editor": {
"cancel": "キャンセル"
},
"add_member_dialog": {
"title": "メンバーを追加",
"description": "ワークスペースのメンバーまたはエージェントをこのスクワッドに追加します。",
"label_member": "メンバー",
"label_role": "役割",
"label_optional": "(任意)",
"placeholder_role_inline": "役割を追加…",
"cancel": "キャンセル"
},
"description_dialog": {
"title": "説明を編集",
"placeholder_empty": "説明を追加",
"cancel": "キャンセル"
},
"discard_changes_dialog": {
"title": "保存していない変更を破棄しますか?",
"description": "このタブに保存していない変更があります。タブを切り替えると変更は破棄されます。",
"keep_editing": "編集を続ける",
"discard_button": "破棄"
},
"members_tab": {
"section_title": "メンバー",
"section_count_other": "このスクワッドのメンバー {{count}}名",
"add_member_button": "メンバーを追加",
"create_agent_button": "エージェントを作成",
"leader_chip": "リーダー",
"view_agent_tooltip": "エージェントの詳細を開く",
"make_leader_tooltip": "スクワッドリーダーに指定",
"remove_member_tooltip": "スクワッドから削除",
"status_working": "作業中",
"status_idle": "アイドル",
"status_offline": "オフライン",
"status_unstable": "不安定",
"issue_status_blocked": "ブロック中",
"active_issue_more": "他 {{count}}件",
"last_active_label": "最終アクティブ {{time}}",
"status_archived": "アーカイブ済み"
},
"profile_card": {
"unavailable": "スクワッドを利用できません",
"detail_link": "詳細 →",
"archived": "アーカイブ済み",
"member_count_other": "メンバー {{count}}名",
"members_section": "メンバー",
"more_members_other": "他 {{count}}名"
},
"instructions_tab": {
"description": "スクワッドの指示は、リーダーエージェントがこのスクワッドに割り当てられたイシューに取り組むたびに、そのプロンプトに挿入されます。スクワッド全体の方針、作業上の取り決め、リーダーがすべてのタスクで従うべきコンテキストを伝えるために使用します。",
"unsaved_changes": "保存していない変更",
"save_button": "保存"
}
}

View File

@@ -0,0 +1,8 @@
{
"attach_file": "ファイルを添付",
"toggle_sidebar": "サイドバーの開閉",
"pagination_previous": "前のページへ移動",
"pagination_next": "次のページへ移動",
"copy_code": "コードをコピー",
"plain_text": "プレーンテキスト"
}

View File

@@ -0,0 +1,58 @@
{
"title": "使用量",
"subtitle": "このワークスペース全体のトークン消費とエージェントの活動です。",
"filter": {
"project_label": "プロジェクト",
"all_projects": "すべてのプロジェクト",
"period_label": "期間"
},
"kpi": {
"cost_label": "コスト · {{days}}日",
"tokens_label": "トークン · {{days}}日",
"tokens_hint": "入力 {{input}} · 出力 {{output}}",
"run_time_label": "実行時間 · {{days}}日",
"run_time_hint": "{{tasks}} 件のタスク全体",
"tasks_label": "タスク · {{days}}日",
"tasks_hint": "{{failed}} 件失敗"
},
"dim": {
"label": "単位",
"daily": "日別",
"weekly": "週別"
},
"daily": {
"title_cost": "日別コスト",
"title_tokens": "日別トークン",
"title_time": "日別実行時間",
"title_tasks": "日別タスク",
"metric_cost": "コスト",
"metric_tokens": "トークン",
"metric_time": "時間",
"metric_tasks": "タスク",
"no_data": "この期間に使用量はありません。"
},
"weekly": {
"title_cost": "週別コスト",
"title_tokens": "週別トークン",
"title_time": "週別実行時間",
"title_tasks": "週別タスク",
"partial_label": "{{range}} (一部 · 7日中 {{covered}}日)"
},
"leaderboard": {
"title": "リーダーボード",
"caption": "{{count}} 件のエージェント",
"header_agent": "エージェント",
"header_tokens": "トークン",
"header_cost": "コスト",
"header_time": "時間",
"header_tasks": "タスク",
"no_data": "この期間にエージェントの活動はありません。"
},
"empty": {
"title": "まだ使用量はありません",
"body": "ここでエージェントがタスクを実行し始めると、トークンの消費と実行時間がこの画面に表示されます。"
},
"duration": {
"less_than_minute": "1分未満"
}
}

View File

@@ -0,0 +1,34 @@
{
"create_form": {
"name_label": "ワークスペース名",
"name_placeholder": "マイワークスペース",
"url_label": "ワークスペースURL",
"url_placeholder": "my-workspace",
"submit": "ワークスペースを作成",
"submitting": "作成中...",
"errors": {
"slug_format": "小文字、数字、ハイフンのみ使用できます",
"slug_taken": "このワークスペースURLはすでに使用されています。",
"slug_reserved": "このワークスペースURLは予約されているため使用できません。",
"slug_conflict_toast": "別のワークスペースURLを選択してください",
"create_failed": "ワークスペースを作成できませんでした"
}
},
"new_page": {
"back": "戻る",
"log_out": "ログアウト",
"title": "Multicaへようこそ",
"description": "あなたとAIの仲間が同じコンテキストを共有しながら、イシューを引き受け、コメントを残し、隣り合って作業する1つのワークスペースです。",
"invite_hint": "ワークスペースの準備ができたら、仲間を招待できます。"
},
"creation_disabled": {
"title": "ワークスペースの作成が無効になっています",
"description": "このMultica instanceでは新しいワークスペースを作成できません。既存のワークスペースへの招待を管理者に依頼してください。"
},
"no_access": {
"title": "ワークスペースを利用できません",
"description": "このワークスペースは存在しないか、アクセス権がありません。",
"go_to_workspaces": "マイワークスペースへ移動",
"sign_in_different": "別のユーザーでログイン"
}
}

View File

@@ -11,6 +11,7 @@
"english": "English",
"chinese": "中文",
"korean": "한국어",
"japanese": "日本語",
"sync_failed": "이 기기에는 언어가 저장되었지만 계정 동기화에 실패했습니다. 다른 기기에서는 이전 언어가 표시될 수 있습니다."
},
"timezone": {

View File

@@ -11,6 +11,7 @@
"english": "English",
"chinese": "中文",
"korean": "한국어",
"japanese": "日本語",
"sync_failed": "语言已在本设备保存,但同步到账号失败。其他设备可能仍显示旧语言。"
},
"timezone": {

View File

@@ -23,10 +23,11 @@ export const CREATE_AGENT_GUIDE_ISSUE_TITLE = {
en: "Step 2 — Create your first Multica Agent",
zh: "第 2 步 —— 创建你的第一个 Multica Agent",
ko: "2단계 — 첫 Multica Agent 만들기",
ja: "ステップ2 — 最初の Multica Agent を作成する",
} as const;
interface BodyOpts {
lang: "en" | "zh" | "ko";
lang: "en" | "zh" | "ko" | "ja";
installRuntimeIdentifier: string;
installRuntimeId: string;
}
@@ -39,6 +40,9 @@ export function getCreateAgentGuideBody(opts: BodyOpts): string {
if (opts.lang === "ko") {
return koBody(mention);
}
if (opts.lang === "ja") {
return jaBody(mention);
}
return enBody(mention);
}
@@ -167,3 +171,45 @@ ${HELPER_INSTRUCTIONS.ko}
- **Autopilots** — 예약 또는 webhook으로 실행되는 작업입니다.
- **Docs** — https://multica.ai/docs.`;
}
function jaBody(installRuntimeMention: string): string {
return `runtime が online になったら(${installRuntimeMention} を参照)、最初の agent である Multica Helper を作りましょう。下の prompt はあらかじめ書いてあるので、そのままコピーするだけです。
## 1. 新しい agent の画面を開く
サイドバーの **Agents** を開き、**New Agent** をクリックします。
## 2. さっきインストールした runtime を選ぶ
"Runtime" でその runtime を選びます。何も表示されない場合は runtime がまだ online ではありません。${installRuntimeMention} のインストール手順を先に終わらせてください。
## 3. 各ブロックを対応するフィールドにコピーする
**Name**
\`\`\`md
${HELPER_AGENT_NAME}
\`\`\`
**Description**
\`\`\`md
${HELPER_DESCRIPTION.ja}
\`\`\`
**Instructions**
\`\`\`md
${HELPER_INSTRUCTIONS.ja}
\`\`\`
## 4. 保存 → issue を割り当てる
**Create** を押します。新しい agent がワークスペースの agent 一覧に表示されます。
次に issue を作る(または既存の issue を割り当て直す)→ assignee を Multica Helper にする → status を **todo** にします。runtime が数秒以内にタスクを受け取って作業を始めます。進捗は issue の task panel で確認できます。
## 次に見る場所
- **Skills** — どの agent にも付けられる、再利用可能な instruction パックです。
- **Squads** — 一緒に割り当てられる agent のグループです。
- **Autopilots** — スケジュールや webhook で実行される処理です。
- **Docs** — https://multica.ai/docs。`;
}

View File

@@ -115,7 +115,36 @@ Multica는 오픈소스 AI-native 팀 워크스페이스입니다(소스: https:
\`multica --help\`, 공식 문서, GitHub 저장소가 이 instruction과 충돌하거나 중요한 내용을 추가한다고 판단되면(명령 이름 변경, 새 핵심 개념, 삭제된 플래그 등), 먼저 사용자에게 알리고 업데이트된 instruction 초안을 제안한 뒤 계속하세요. 스스로 instruction을 조용히 바꾸지 마세요. 사용자의 확인을 받은 뒤 CLI로 적용하세요.`;
export const HELPER_INSTRUCTIONS = { en, zh, ko } as const;
const ja = `あなたは Multica Helper、この Multica ワークスペースに組み込まれた AI アシスタントです。役割は、すべてのメンバーが Multica をより上手に使えるよう支援することです。質問に答え、アドバイスを伝え、ユーザーに代わってワークスペースの操作を実行してください。
## Multica とは
Multica はオープンソースで AI ネイティブなチームワークスペースです(ソース: https://github.com/multica-ai/multica)。中心となる考え方は、AI agent を本物のチームメイトとして扱うことです。エージェントはかんばんボードで issue を割り当てられ、スレッドにコメントし、ステータスを変え、コードを実行します。人間のメンバーとまったく同じです。agent と直接チャット(chat)したり、複数の agent を squad にまとめたり、スケジュールやイベントで起動する自動化(autopilot)を動かすこともできます。
概念の詳細(workspace / issue / project / agent / runtime / skill / squad / autopilot / inbox / chat session)は WebFetch で https://multica.ai/docs を取得して確認してください。これが信頼できる情報源です。「なぜそうなっているか」や実装の詳細は上記の GitHub リポジトリを参照してください。記憶に頼って概念を言い換えないでください。
ユーザーが製品の利用中に遭遇したあらゆる問題(バグ、分かりにくい挙動、足りない機能、改善案)については、https://github.com/multica-ai/multica/issues で issue を作成するよう案内してください。これが公式のフィードバック窓口です。
## できること
あなたのツールボックスは \`multica\` CLI です。すでに PATH 上にあり、ワークスペースの owner として認証済みです。
あなたが使える機能の全体像は \`multica --help\` に表示される内容です。まず \`multica --help\` を実行し、必要なサブコマンドは \`multica <command> --help\` で確認してください。構造化データが必要なときは \`--output json\` を使います。CLI が機能の一覧です。コマンドやフラグを勝手に作り出さないでください。
実際にできることの例(すべてではありません。\`--help\` が基準です):
- issue の作成、コメントの投稿
- agent の作成や改善
- project、squad、autopilot、skill、runtime などの管理
## 話し方
同僚のように、簡潔で率直に答えてください。ユーザーの言語で応答してください(日本語で聞かれたら日本語で回答)。UI の場所を案内するときは正確なパスを示し(例: "Settings → Agents → New")、ドキュメントを案内するときはトップページではなく具体的なページにリンクしてください。URL、フラグ、ファイルパスを絶対に捏造しないでください。
## 最新の状態を保つ
\`multica --help\`、公式ドキュメント、GitHub リポジトリがこの instruction と矛盾している、または重要な追加があると気づいたら(コマンド名の変更、新しい中心概念、削除されたフラグなど)、まずユーザーに知らせ、更新後の instruction の案を提案してから続けてください。自分の instruction を黙って書き換えないでください。ユーザーの確認を得てから CLI で変更を適用してください。`;
export const HELPER_INSTRUCTIONS = { en, zh, ko, ja } as const;
export type HelperInstructionsLang = keyof typeof HELPER_INSTRUCTIONS;
/**
@@ -132,4 +161,5 @@ export const HELPER_DESCRIPTION = {
en: "Multica usage assistant. Ask how to use it, help create/view tasks, configure agents, and more.",
zh: "Multica 使用助手。可以询问用法、帮助创建/查看任务、配置 agent 等。",
ko: "Multica 사용 어시스턴트입니다. 사용법 질문, 작업 생성/조회, agent 설정 등을 도와줍니다.",
ja: "Multica の使い方アシスタントです。使い方の質問、タスクの作成・確認、agent の設定などを手伝います。",
} as const;

View File

@@ -17,8 +17,8 @@ export const STARTER_CARD_IDS = ["intro", "tour", "welcome_page"] as const;
export type StarterCardId = (typeof STARTER_CARD_IDS)[number];
interface StarterPrompt {
title: { en: string; zh: string; ko: string };
prompt: { en: string; zh: string; ko: string };
title: { en: string; zh: string; ko: string; ja: string };
prompt: { en: string; zh: string; ko: string; ja: string };
}
export const HELPER_STARTER_PROMPTS: Record<StarterCardId, StarterPrompt> = {
@@ -27,11 +27,13 @@ export const HELPER_STARTER_PROMPTS: Record<StarterCardId, StarterPrompt> = {
en: "Introduce Multica to me",
zh: "简单介绍一下 Multica",
ko: "Multica를 간단히 소개해 주세요",
ja: "Multica を簡単に紹介してください",
},
prompt: {
en: "Introduce Multica to me in 12 paragraphs. Cover what it is, the core concepts (workspace / issue / agent / runtime), and how it differs from tools like Linear or Jira.",
zh: "用 1-2 段话简单介绍 Multica 给我。讲清楚它是什么、核心概念有哪些(workspace / issue / agent / runtime)、和 Linear / Jira 之类的工具核心区别在哪。",
ko: "Multica를 1-2문단으로 간단히 소개해 주세요. 무엇인지, 핵심 개념(workspace / issue / agent / runtime)이 무엇인지, Linear나 Jira 같은 도구와 핵심적으로 어떻게 다른지 설명해 주세요.",
ja: "Multica を1〜2段落で簡単に紹介してください。何であるか、中心となる概念(workspace / issue / agent / runtime)、そして Linear や Jira のようなツールと根本的にどう違うのかを説明してください。",
},
},
tour: {
@@ -39,11 +41,13 @@ export const HELPER_STARTER_PROMPTS: Record<StarterCardId, StarterPrompt> = {
en: "Walk me through the core features",
zh: "带我熟悉每个功能",
ko: "핵심 기능을 안내해 주세요",
ja: "主要な機能を案内してください",
},
prompt: {
en: "Walk me through Multica's core features — issue, agent, squad, autopilot, chat. Pick one realistic scenario I might run into and explain how all these pieces fit together.",
zh: "陪我熟悉 Multica 的每个核心功能 —— issue、agent、squad、autopilot、chat。挑一个我可能用得上的真实场景,讲讲这几个东西是怎么配合的。",
ko: "Multica의 핵심 기능인 issue, agent, squad, autopilot, chat을 안내해 주세요. 제가 실제로 겪을 만한 상황 하나를 골라 이 요소들이 어떻게 함께 작동하는지 설명해 주세요.",
ja: "Multica の主要な機能 — issue、agent、squad、autopilot、chat を案内してください。私が実際に遭遇しそうな現実的なシナリオを1つ選び、これらの要素がどう連携するのかを説明してください。",
},
},
welcome_page: {
@@ -51,6 +55,7 @@ export const HELPER_STARTER_PROMPTS: Record<StarterCardId, StarterPrompt> = {
en: "Show me what Multica can do for me — as slides",
zh: "用 slides 介绍 Multica 能为我做什么",
ko: "Multica가 저에게 무엇을 해줄 수 있는지 슬라이드로 보여 주세요",
ja: "Multica が私に何をしてくれるのかをスライドで見せてください",
},
prompt: {
en: `Build me a single-file HTML slide deck that shows what Multica can do for me. Tailor it to my role and use case (see "About me" below). Paste the FULL HTML in a fenced \`\`\`html block in a comment on this issue so I can copy it straight out, save as \`multica-intro.html\`, and double-click to open it in a browser.
@@ -131,6 +136,32 @@ When done, also reply with a one-sentence summary of which scenarios you picked
- ArrowLeft / ArrowRight와 Space로 이동. 모서리에 작은 page indicator를 두세요.
완료 후, 어떤 시나리오를 골랐고 왜 골랐는지 한 문장으로 요약해 주세요.`,
ja: `Multica が私に何をしてくれるのかを示す、単一ファイルの HTML スライドデッキを作ってください。私の役割とユースケースに合わせてください(下の「私について」を参照)。完全な HTML を、この issue のコメントに fenced \`\`\`html コードブロックで貼り付けてください。そのままコピーして \`multica-intro.html\` として保存し、ブラウザでダブルクリックして開けるようにしてください。
**出力フォーマット**
- 1つの self-contained な .html。CSS / JS はすべて inline。依存関係なし、ビルドツールなし、外部画像なし(視覚要素は CSS で生成 — グラデーション、幾何学的な図形、inline SVG を使用)。
- 全体で5〜8枚のスライド:
1. タイトル — 「[私の役割] に Multica ができること」
2. 4つの中心概念 — workspace / issue / agent / runtime を1枚で
3〜6. 私のユースケースに合わせた具体的なシナリオを3〜4個。それぞれ「X をしたいとき → Multica はこう処理します」の形で
7. 締め — 具体的な次の一歩のアクション
**ビューポートのルール(必ず守ること)**
- すべての \`.slide\`: \`height: 100vh; height: 100dvh; overflow: hidden;\`
- すべての font-size と spacing は \`clamp(min, preferred, max)\` を使用。固定の px / rem は使わない。
- 1枚あたりの密度: 見出し1つ + bullet 4つ以下、または見出し1つ + 短い段落2つ。あふれたら次のスライドに分ける。
- \`prefers-reduced-motion: reduce\` を尊重する(アニメーションを無効化)。
**美しさ(ありがちな AI っぽい見た目を避ける)**
- Fontshare か Google Fonts から個性のある typeface を選ぶ。Inter、Roboto、Arial、システムフォントは使わない。
- CSS variable で一貫した palette を決める: 主となる色1つ + 鋭いアクセント1つ。ありがちな「紫のグラデーション + 白背景」は避ける。
- 背景: 雰囲気を出すために重ねたグラデーションや幾何学パターンを使い、のっぺりした白は使わない。
- アニメーション: スライドごとに、よく練られた load-in を1回だけ(\`animation-delay\` でずらす)。CSS のみ。散らばった micro-interaction は禁止。
**ナビゲーション**
- ArrowLeft / ArrowRight と Space で進む。隅に小さな page indicator を置く。
完成したら、私のためにどのシナリオを選び、なぜ選んだのかを一文で要約してください。`,
},
},
};

View File

@@ -6,6 +6,7 @@ describe("pickContentLang", () => {
expect(pickContentLang("en-US")).toBe("en");
expect(pickContentLang("zh-Hant")).toBe("zh");
expect(pickContentLang("ko-KR")).toBe("ko");
expect(pickContentLang("ja-JP")).toBe("ja");
});
it("falls back to English for unsupported or missing languages", () => {

View File

@@ -28,12 +28,13 @@ export {
type QuestionnaireRaw,
} from "./user-context";
type ContentLang = "en" | "zh" | "ko";
type ContentLang = "en" | "zh" | "ko" | "ja";
const CONTENT_LANG_BY_LOCALE: Record<SupportedLocale, ContentLang> = {
en: "en",
"zh-Hans": "zh",
ko: "ko",
ja: "ja",
};
/**

View File

@@ -24,6 +24,7 @@ export const INSTALL_RUNTIME_ISSUE_TITLE = {
en: "Step 1 — Connect a runtime to start using agents",
zh: "第 1 步 —— 连接运行时,开始使用 agent",
ko: "1단계 — agent를 사용하려면 runtime 연결하기",
ja: "ステップ1 — agent を使うために runtime を接続する",
} as const;
const en = `Welcome to Multica.
@@ -144,7 +145,46 @@ Codex 참고 문서: https://developers.openai.com/codex/cli
runtime이 연결되면 Multica Helper를 만들어 안내를 받으며 첫 실행을 시작할 수 있습니다.`;
export const INSTALL_RUNTIME_ISSUE_BODY = { en, zh, ko } as const;
const ja = `Multica へようこそ。
agent が作業を実行するには、まず runtime が必要です。runtime をインストールしている間も、Multica を軽量なプロジェクト管理ワークスペースとして先に使うことができます。
## まず Multica を使ってみる
runtime が準備できる前に、次のことを試せます:
1. いまの仕事のための project を作る。
2. issue をいくつか作り、backlog、todo、in_progress、done の間で動かしてみる。
3. priority、label、comment、subscription を追加する。
4. Inbox で自分への割り当てや mention を確認する。
これでまずプロジェクト管理のレイヤーに慣れることができます。runtime を接続すると、agent が同じ issue から作業を始められます。
## 最初の agent runtime をインストールする
詳しいガイド: https://multica.ai/docs/install-agent-runtime
日本語ユーザーには、Codex で始めるのが最も速い経路です:
1. Node.js がインストールされていることを確認します。
2. Codex をインストールします:
npm i -g @openai/codex
3. サインインします:
codex
4. ターミナルから見つけられるか確認します:
which codex
codex --version
5. Multica daemon を再起動します:
multica daemon restart
デスクトップアプリを使っている場合は、アプリを再起動するだけで十分です。
6. Runtimes に戻って再読み込みします。Codex runtime が online と表示されるはずです。
7. その runtime から最初の agent を作り、issue を agent に割り当てて status を todo にします。
Codex のリファレンス: https://developers.openai.com/codex/cli
runtime が接続されたら、Multica Helper を作成して、案内付きの最初の実行を始められます。`;
export const INSTALL_RUNTIME_ISSUE_BODY = { en, zh, ko, ja } as const;
/**
* Prefix sentence for the follow-up comment posted on this issue (the one
@@ -159,4 +199,5 @@ export const FOLLOWUP_COMMENT_PREFIX = {
en: "Your next step:",
zh: "完成后的下一步:",
ko: "다음 단계:",
ja: "次のステップ:",
} as const;

View File

@@ -118,6 +118,18 @@ describe("PreferencesTab — Language switcher", () => {
expect(mockToastWarning).not.toHaveBeenCalled();
});
it("when not logged in: selecting Japanese persists ja + reloads, no PATCH", async () => {
const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
render(<PreferencesTab />, { wrapper: I18nWrapper });
await user.click(screen.getByRole("radio", { name: "日本語" }));
expect(mockPersist).toHaveBeenCalledWith("ja");
expect(mockUpdateMe).not.toHaveBeenCalled();
expect(mockReload).toHaveBeenCalledTimes(1);
expect(mockToastWarning).not.toHaveBeenCalled();
});
it("when logged in + PATCH success: persists + PATCH + reload immediately", async () => {
userRef.current = { id: "user-1" };
mockUpdateMe.mockResolvedValueOnce({});

View File

@@ -122,6 +122,7 @@ export function PreferencesTab() {
{ value: "en", label: t(($) => $.preferences.language.english) },
{ value: "zh-Hans", label: t(($) => $.preferences.language.chinese) },
{ value: "ko", label: t(($) => $.preferences.language.korean) },
{ value: "ja", label: t(($) => $.preferences.language.japanese) },
];
// Persist locally → sync to user.language → reload. Reload (vs in-place

Some files were not shown because too many files have changed in this diff Show More