@geekbeer/minion 3.60.5 → 4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,53 @@
1
+ Copyright (c) 2026 GeekBeer Co., Ltd.
2
+
3
+ Source code in this repository is covered by the Elastic License 2.0.
4
+ The full license text is available at:
5
+ https://www.elastic.co/licensing/elastic-license
6
+
7
+ ----
8
+
9
+ Elastic License
10
+
11
+ Acceptance
12
+ By using the software, you agree to all of the terms and conditions below.
13
+
14
+ Copyright License
15
+ The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations and conditions below.
16
+
17
+ Limitations
18
+ You may not provide the software to third parties as a hosted or managed service, where the service provides users with access to any substantial set of the features or functionality of the software.
19
+
20
+ You may not move, change, disable, or circumvent the license key functionality in the software, and you may not remove or obscure any functionality in the software that is protected by the license key.
21
+
22
+ You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor’s trademarks is subject to applicable law.
23
+
24
+ Patents
25
+ The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
26
+
27
+ Notices
28
+ You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms.
29
+
30
+ If you modify the software, you must include in any modified copies of the software prominent notices stating that you have modified the software.
31
+
32
+ No Other Rights
33
+ These terms do not imply any licenses other than those expressly granted in these terms.
34
+
35
+ Termination
36
+ If you use the software in violation of these terms, such use is not licensed, and your licenses will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your licenses will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your licenses to terminate automatically and permanently.
37
+
38
+ No Liability
39
+ As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.
40
+
41
+ Definitions
42
+ The licensor is the entity offering these terms, and the software is the software the licensor makes available under these terms, including any portion of it.
43
+
44
+ you refers to the individual or entity agreeing to these terms.
45
+
46
+ your company is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
47
+
48
+ your licenses are all the licenses granted to you for the software under these terms.
49
+
50
+ use means anything you do with the software requiring one of your licenses.
51
+
52
+ trademark means trademarks, service marks, and similar rights.
53
+
package/README.md CHANGED
@@ -1,64 +1,59 @@
1
- # @geekbeer/minion
1
+ > [!IMPORTANT]
2
+ > This package is the agent runtime for [Minion](https://minion-agent.com), GeekBeer's AI agent platform. It is intended to run on a Minion-managed host (provisioned via the HQ dashboard) and is not designed for standalone use.
2
3
 
3
- AI Agent runtime for Minion - manages heartbeat, status, and skill deployment on VPS.
4
+ # @geekbeer/minion
4
5
 
5
- ## Install
6
+ AI agent runtime that runs on a Minion host (Lightsail VPS, Docker container, or self-hosted machine). It exposes a local HTTP API on port `8080`, syncs heartbeats and skills with the HQ server, and runs Claude Code–based workflows and routines via tmux (Linux/macOS) or node-pty (Windows).
6
7
 
7
- ```bash
8
- npm install -g @geekbeer/minion
9
- ```
8
+ Supported platforms: Linux (systemd / supervisord), Windows (NSSM service + WSL), macOS (launchd).
10
9
 
11
- ## Usage
10
+ ## Documentation
12
11
 
13
- ### Setup (VPS)
12
+ Full documentation lives at **https://docs.minion-agent.com**. Start here:
14
13
 
15
- ```bash
16
- minion-cli setup \
17
- --hq-url https://minion-agent.com \
18
- --minion-id <MINION_ID> \
19
- --api-token <API_TOKEN> \
20
- --setup-tunnel \
21
- --non-interactive
22
- ```
14
+ - [Quickstart](https://docs.minion-agent.com/getting-started/quickstart/) — provision a minion from the HQ dashboard
15
+ - [Concepts](https://docs.minion-agent.com/getting-started/concepts/) workspaces, projects, skills, workflows, routines
16
+ - [Self-hosting / Provisioning](https://docs.minion-agent.com/getting-started/provisioning/) — bring your own host
17
+ - [Skill authoring](https://docs.minion-agent.com/skills-workflows/skill-authoring/) and [workflow design](https://docs.minion-agent.com/skills-workflows/workflow-design/)
18
+ - [DAG workflow nodes](https://docs.minion-agent.com/skills-workflows/dag-nodes/)
23
19
 
24
- ### Service Management
20
+ Japanese documentation is available at https://docs.minion-agent.com/ja/.
25
21
 
26
- ```bash
27
- minion-cli start # Start the minion agent
28
- minion-cli stop # Stop the minion agent
29
- minion-cli restart # Restart the minion agent
30
- minion-cli status # Show service status
31
- minion-cli health # Run health check
32
- ```
22
+ ## Install
33
23
 
34
- ### Logging
24
+ Most users do **not** install this package manually — the HQ dashboard provisions hosts automatically. For self-hosted setups:
35
25
 
36
26
  ```bash
37
- minion-cli log -m "Task completed" -l info -s skill-name
27
+ npm install -g @geekbeer/minion
38
28
  ```
39
29
 
40
- ### Issue Reporting
30
+ Then follow the [self-hosting guide](https://docs.minion-agent.com/getting-started/provisioning/) to register the host with your HQ workspace.
41
31
 
42
- ```javascript
43
- const { reportIssue } = require('@geekbeer/minion/api')
32
+ ## CLI
44
33
 
45
- await reportIssue({
46
- title: 'HQ APIで502エラーが発生する',
47
- body: '## 状況\n...\n\n## 再現手順\n...',
48
- labels: ['bug', 'critical']
49
- })
50
- // { success: true, issue_url: '...', issue_number: 42 }
34
+ ```bash
35
+ minion-cli setup --user <USERNAME> # Install dependencies and register services (Linux/macOS, run as root)
36
+ minion-cli configure --hq-url ... --minion-id ... --api-token ...
37
+ minion-cli start | stop | restart | status
38
+ minion-cli health | diagnose | daemons
39
+ minion-cli set-status <status> [task]
40
+ hq <subcommand> # HQ API helper (notes, threads, tasks, memories, etc.)
51
41
  ```
52
42
 
43
+ On Windows the equivalents are exposed as `minion-cli-win` and `hq-win`; on macOS as `minion-cli-mac` and `hq-mac`. See the [provisioning guide](https://docs.minion-agent.com/getting-started/provisioning/) for end-to-end setup.
44
+
53
45
  ## Environment Variables
54
46
 
55
- | Variable | Description | Default |
56
- |----------|-------------|---------|
57
- | `HQ_URL` | Minion HQ server URL | - |
58
- | `API_TOKEN` | Authentication token | - |
59
- | `MINION_ID` | Minion UUID | - |
60
- | `AGENT_PORT` | Agent API listen port | `8080` |
47
+ | Variable | Description |
48
+ |----------|-------------|
49
+ | `HQ_URL` | HQ server URL (leave empty for standalone mode) |
50
+ | `API_TOKEN` | Bearer token for HQ and local API authentication |
51
+ | `MINION_ID` | UUID assigned by HQ on provisioning |
52
+ | `AGENT_PORT` | Local agent API port (default `8080`) |
53
+ | `MINION_USER` | System user that owns the agent process |
61
54
 
62
55
  ## License
63
56
 
64
- MIT
57
+ This software is licensed under the [Elastic License 2.0](./LICENSE.md) (SPDX: `Elastic-2.0`).
58
+
59
+ Copyright (c) 2026 GeekBeer Co., Ltd.
@@ -161,12 +161,19 @@ async function executeSkillNode(node) {
161
161
  )
162
162
 
163
163
  try {
164
- // 1. Claim the node
164
+ // 1. Claim the node. Response includes `template_vars` containing the
165
+ // workspace/project-scope variables resolved on HQ — we merge these
166
+ // with minion-local variables for the skill fetch below so HQ-side
167
+ // variable updates (e.g. project_variables) take effect on the next
168
+ // node execution. Minion-local values win over HQ-scope values,
169
+ // matching the cross-scope rule (workspace < project < minion).
170
+ let hqVars = {}
165
171
  try {
166
- await dagRequest('/claim-node', {
172
+ const claimResp = await dagRequest('/claim-node', {
167
173
  method: 'POST',
168
174
  body: JSON.stringify({ node_execution_id }),
169
175
  })
176
+ hqVars = (claimResp && claimResp.template_vars) || {}
170
177
  } catch (claimErr) {
171
178
  if (claimErr.statusCode === 409) {
172
179
  console.log(`[DagPoller] Node ${node_id} already claimed, skipping`)
@@ -187,7 +194,7 @@ async function executeSkillNode(node) {
187
194
  if (skillName) {
188
195
  try {
189
196
  const minionVars = variableStore.getAll('variables')
190
- const mergedVars = { ...minionVars }
197
+ const mergedVars = { ...hqVars, ...minionVars }
191
198
  const varsParam = Object.keys(mergedVars).length > 0
192
199
  ? `?vars=${Buffer.from(JSON.stringify(mergedVars)).toString('base64')}`
193
200
  : ''
@@ -5,7 +5,7 @@
5
5
  * either the Primary (user-facing) session or as a Child (specialist) session
6
6
  * dispatched from the Primary via the dispatch MCP server.
7
7
  *
8
- * See: packages/docs-internal/src/content/docs/design/llm-plugin-system.md
8
+ * See: packages/docs-internal/src/content/docs/design/llm/llm-plugin-system.md
9
9
  */
10
10
 
11
11
  /**
@@ -19,7 +19,7 @@
19
19
  * Secrets never leave the minion and are never persisted in HQ DB. Variables
20
20
  * are non-sensitive and may also be defined at HQ scopes (workspace /
21
21
  * project / workflow); see packages/docs-internal/src/content/docs/design/
22
- * variables-and-secrets.md for the full resolution model.
22
+ * workflow-execution/variables-and-secrets.md for the full resolution model.
23
23
  */
24
24
 
25
25
  const fs = require('fs')
@@ -1236,6 +1236,9 @@ POST `/api/minion/dag-workflows/:id/publish` (body なし):
1236
1236
  | POST | `/api/minion/dag-workflows/:id/contracts` | 個別contractを追加/更新 |
1237
1237
  | DELETE | `/api/minion/dag-workflows/:id/contracts` | 個別contractを削除 |
1238
1238
  | POST | `/api/minion/dag-workflows/:id/validate` | ドラフトをフル検証(公開せず) |
1239
+ | GET | `/api/minion/dag-workflows/:id/variables` | DAGワークフロー変数の一覧取得 |
1240
+ | PUT | `/api/minion/dag-workflows/:id/variables` | DAGワークフロー変数を一括 upsert(既存を全削除→再投入) |
1241
+ | POST | `/api/minion/dag-workflows/:id/trigger` | 公開済みワークフローを手動実行(pull-model) |
1239
1242
 
1240
1243
  #### POST `/api/minion/dag-workflows/:id/nodes` — ノード追加
1241
1244
 
@@ -1482,6 +1485,80 @@ body なし。現在のドラフトを `validateDagGraph` でフル検証し結
1482
1485
  }
1483
1486
  ```
1484
1487
 
1488
+ #### GET / PUT `/api/minion/dag-workflows/:id/variables` — DAGワークフロー変数
1489
+
1490
+ DAGワークフロー単位のキー/値ペア。スキル本文の `{{VAR_NAME}}` プレースホルダーに展開される。展開タイミングは `claim-node` のレスポンス `template_vars` に乗って降ってくる経路で、変更は **次のノード claim から即時反映** される。
1491
+
1492
+ **スコープ優先順位** (narrower wins): `workspace_variables` < `project_variables` < `dag_workflow_variables` < minion-local。
1493
+
1494
+ **バリデーション**:
1495
+ - `key`: `^[A-Za-z_][A-Za-z0-9_]{0,99}$`(先頭英字またはアンダースコア、最大100文字)
1496
+ - `value`: 文字列、最大2000文字
1497
+ - 同一 `key` の重複は不可
1498
+
1499
+ `GET /api/minion/dag-workflows/:id/variables` レスポンス:
1500
+ ```json
1501
+ {
1502
+ "variables": [
1503
+ { "id": "<uuid>", "key": "TARGET_CATEGORY", "value": "electronics", "created_at": "...", "updated_at": "..." }
1504
+ ]
1505
+ }
1506
+ ```
1507
+
1508
+ `PUT /api/minion/dag-workflows/:id/variables` body:
1509
+ ```json
1510
+ {
1511
+ "variables": [
1512
+ { "key": "TARGET_CATEGORY", "value": "electronics" },
1513
+ { "key": "API_BASE_URL", "value": "https://api.example.com" }
1514
+ ]
1515
+ }
1516
+ ```
1517
+
1518
+ - バッチ upsert 形式: **既存を全削除 → 渡された配列を全 insert** する(部分更新不可)。
1519
+ - 単一変数だけを変更したい場合も、先に GET で現在の集合を取得 → 編集 → PUT で全件送信する。
1520
+ - `variables: []` を送ると全削除になる。
1521
+
1522
+ レスポンス:
1523
+ ```json
1524
+ { "success": true, "count": 2 }
1525
+ ```
1526
+
1527
+ エラー時 (400): `{ "error": "Invalid key: 1FOO" }` / `{ "error": "Duplicate key: FOO" }` 等。
1528
+
1529
+ #### POST `/api/minion/dag-workflows/:id/trigger` — ワークフロー手動実行
1530
+
1531
+ 公開済み (`is_active=true` かつ `current_version_id` 設定済み) の DAG ワークフローを手動でトリガーする。HQダッシュボード経由の `POST /api/dag/projects/:projectId/workflows/:dagWfId/trigger` と同じ pull-model で動き、`trigger_source` は `'manual'` として記録される(cron / webhook と区別される)。
1532
+
1533
+ Body (任意):
1534
+ ```json
1535
+ {
1536
+ "payload": { "...": "..." }
1537
+ }
1538
+ ```
1539
+
1540
+ - `payload` は start ノードの `output_data` に注入され、cascade 経由で下流に伝播する。
1541
+ - start ノードに `input_contract` が定義されている場合、`payload` が contract に準拠していないと 400 (`violations` フィールドに違反詳細) が返る。
1542
+ - payload を省略すると start ノードは空の出力で完了する。
1543
+
1544
+ レスポンス (201):
1545
+ ```json
1546
+ {
1547
+ "execution_id": "<uuid>",
1548
+ "dag_workflow_name": "Order Pipeline",
1549
+ "root_nodes": 3,
1550
+ "total_nodes": 12,
1551
+ "mode": "pull"
1552
+ }
1553
+ ```
1554
+
1555
+ エラー応答:
1556
+ - 400: ワークフロー非アクティブ / 未公開 / graph 空 / payload 形式不正 / contract 違反
1557
+ - 403: ミニオンがプロジェクトの PM でない
1558
+ - 404: ワークフロー / プロジェクト未発見
1559
+
1560
+ トリガー後はミニオンの `dag-step-poller` が pending ノードを順次拾って実行する。手動実行も含め、すべての DAG 実行は `dag_executions` テーブル + ダッシュボードの実行履歴で追跡できる。
1561
+
1485
1562
  #### 全操作共通のレスポンス形式
1486
1563
 
1487
1564
  ノード/エッジ操作のレスポンスにはワークフロー全体 + `validation` フィールドが含まれる:
@@ -1682,9 +1759,15 @@ Body:
1682
1759
 
1683
1760
  Response (成功 / 201):
1684
1761
  ```json
1685
- { "success": true, "node_execution_id": "uuid" }
1762
+ {
1763
+ "success": true,
1764
+ "node_execution_id": "uuid",
1765
+ "template_vars": { "PROJECT_VAR_NAME": "value", "WORKSPACE_VAR": "value" }
1766
+ }
1686
1767
  ```
1687
1768
 
1769
+ `template_vars` には claim したノードのコンテキストで解決された **workspace_variables / project_variables / dag_workflow_variables** が narrower-scope-wins (workspace < project < dag_workflow) でマージされて入る。スキルノードの場合は後続の `POST /api/skills/fetch/:name?vars=...` でこの値を base64 JSON として渡し、HQ 側で SKILL.md の `{{VAR}}` を置換する。ミニオンローカル変数はミニオン側で更にレイヤされ、`template_vars` の値を上書きする(cross-scope rule: workspace < project < dag_workflow < minion)。
1770
+
1688
1771
  Response (競合 / 409): 他ミニオンが既に claim 済み、または状態が pending でない場合。
1689
1772
  ```json
1690
1773
  { "error": "Node already claimed or not pending" }
@@ -1949,6 +2032,55 @@ Response:
1949
2032
 
1950
2033
  スキルはバージョン管理される。push ごとに新バージョンが作成され、ファイルは Supabase Storage に保存される。
1951
2034
 
2035
+ **`GET /api/minion/skills/:name` レスポンス**:
2036
+ ```json
2037
+ {
2038
+ "id": "<skill-uuid>",
2039
+ "current_version_id": "<skill-version-uuid>",
2040
+ "name": "variable-injection-test",
2041
+ "display_name": "Variable Injection Test",
2042
+ "type": "workflow",
2043
+ "description": "...",
2044
+ "content": "...",
2045
+ "files": [{ "path": "files/extra.md", "content": "..." }]
2046
+ }
2047
+ ```
2048
+
2049
+ **`POST /api/minion/skills` レスポンス**:
2050
+ ```json
2051
+ {
2052
+ "success": true,
2053
+ "skill": {
2054
+ "id": "<skill-uuid>",
2055
+ "name": "variable-injection-test",
2056
+ "workspace_id": "<workspace-uuid>",
2057
+ "current_version_id": "<skill-version-uuid>",
2058
+ "version": 3
2059
+ }
2060
+ }
2061
+ ```
2062
+
2063
+ スキルを push してそのまま DAG ノードに組み込む典型フロー:
2064
+
2065
+ ```bash
2066
+ # 1. push してスキルIDを得る
2067
+ SKILL_ID=$(curl -s -X POST -H "Authorization: Bearer $API_TOKEN" -H "Content-Type: application/json" \
2068
+ $HQ_URL/api/minion/skills -d '{"name":"my-skill","content":"..."}' | jq -r '.skill.id')
2069
+
2070
+ # 2. DAG ノードを追加 (skill_version_id は省略 = 常に最新を追従)
2071
+ curl -X POST -H "Authorization: Bearer $API_TOKEN" -H "Content-Type: application/json" \
2072
+ $HQ_URL/api/minion/dag-workflows/$DAG_ID/nodes \
2073
+ -d "{\"type\":\"skill\",\"skill_id\":\"$SKILL_ID\",\"assigned_role\":\"engineer\",\"after\":\"start\",\"before\":\"end\"}"
2074
+ ```
2075
+
2076
+ **スキルバージョンの pin / latest 追従** (DAGスキルノード):
2077
+
2078
+ DAGスキルノードの `skill_version_id` は **オプション** です。
2079
+ - `skill_version_id` を **省略 / null** にすると、実行時に常に skill の `current_version_id` (最新版) を fetch する(**latest auto-track**)。スキルを push して新バージョンを公開すると、次のノード実行から自動で反映される。
2080
+ - `skill_version_id` を **明示的に指定** すると、その特定バージョンに pin される(将来の pinned 実行向け。現状ランタイムは latest 解決を使うが、カラムは保持される)。
2081
+
2082
+ 旧来の挙動(publish 時に skill_version_id 必須)は廃止済み。`skill_id` のみ指定すれば DAG publish できる。
2083
+
1952
2084
  ### Threads (HQ)
1953
2085
 
1954
2086
  | Method | Endpoint | Description |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekbeer/minion",
3
- "version": "3.60.5",
3
+ "version": "4.1.1",
4
4
  "description": "AI Agent runtime for Minion - manages status and skill deployment on VPS",
5
5
  "main": "linux/server.js",
6
6
  "bin": {
@@ -57,5 +57,5 @@
57
57
  "claude",
58
58
  "automation"
59
59
  ],
60
- "license": "MIT"
60
+ "license": "Elastic-2.0"
61
61
  }
@@ -0,0 +1,42 @@
1
+ # Accountant Role Guidelines
2
+
3
+ このセッションではあなたは **Accountant** ロールとして行動します。
4
+
5
+ ## 責務
6
+
7
+ - **記帳**: 取引(仕訳)をHQの会計帳簿に正確に記録する
8
+ - **立替経費の処理**: 役員・従業員が立て替えた経費を記帳・精算する
9
+ - **取引先マスタの整備**: 仕入先・顧客・役員・従業員などの取引先を整備する
10
+ - **補助元帳の照会**: 取引先別の残高・明細を確認し、PMやユーザーへ報告する
11
+
12
+ ## 利用するスキル
13
+
14
+ 会計操作の具体手順とAPI仕様は専用スキルにまとまっています。コアルールにはあえて含めていません(トークン圧迫を避けるため)。
15
+
16
+ - `/accounting-bookkeeping` — 取引記帳・立替経費・精算・補助元帳の標準フロー
17
+ - 詳細仕様は `~/.claude/skills/accounting-bookkeeping/references/` 配下を必要時に参照
18
+
19
+ スキルが未配布の場合は `minion-cli skill fetch accounting-bookkeeping` で取得してください。
20
+
21
+ ## 重要な原則
22
+
23
+ - **仕訳の確定済み(closed)期は修正しない。** 締め後の仕訳訂正はPMの承認が必要です。
24
+ - **立替経費は取引先(counterparty)を必ず紐付ける。** 「誰の立替か」を後から照会できるようにするため。
25
+ - **default_payable_account_id 未設定の取引先には立替記帳できない。** API が 422 を返します。先に取引先ページで貸方科目を設定してください。
26
+ - **判断に迷ったら勝手に進めない。** 不明な取引・推測の余地がある仕訳は、threadで PM にエスカレーションすること。
27
+
28
+ ## ブロッカー対処
29
+
30
+ 会計記帳中に自力で解決できない問題に遭遇した場合:
31
+
32
+ 1. **まずプロジェクトメモリーを検索** — 過去に同じ取引パターンの記帳例があるか確認
33
+ 2. **API のエラーレスポンスを読む** — 会計APIは `next_action` フィールドで次に取るべき操作を返す。これに従う
34
+ 3. **自己解決不可なら即ヘルプスレッドを起票** — `attempted_resolution` に試したことを記載
35
+ 4. **人間にしか判断できない問題は即エスカレーション** — 法的判断、過去取引の意図確認など
36
+
37
+ **仕訳を失敗終了させる前に、必ずヘルプスレッドでエスカレーションすること。**
38
+ 詳細は `~/.minion/rules/core.md` の「Blocker Handling」セクションを参照。
39
+
40
+ ## 実行コンテキスト
41
+
42
+ ミニオン変数・シークレット(HQ UIまたはAPI経由で設定)はサーバー起動時に `process.env` にロードされ、会計操作中も利用可能。
package/rules/core.md CHANGED
@@ -32,6 +32,7 @@ Minion
32
32
  - **transform ノードの I/O 型は edge の contract から自動導出**。incoming edge と outgoing edge にそれぞれ contract を必ず貼ること。`transform_instruction` は contract だけで意図が伝わらない場合の補足ヒント(任意)
33
33
  - **script ノード (v3.54.0〜)** は LLM を使わない決定的処理用。`script_runtime` (`'python'` or `'node'`) と `script_source` を指定。input_data を stdin で JSON 受け取り → output_data を stdout に JSON 出力する規約。outgoing edge に contract を貼れば transform と同じ runtime validation が走る。LLMトークンを節約したい・出力ブレを許容できない定型処理に使う。詳細は `~/.minion/docs/task-guides.md` の「Script ノード」を参照
34
34
  - **fan_out の incoming edge に contract を貼る場合**、`fan_out_source` が指すフィールドが contract 内に `type='array'` として宣言されている必要がある(静的検証で弾かれる)
35
+ - **スキルノードの skill_version_id は省略可** (v3.60.8〜)。省略するとランタイムが常に skill の最新バージョンを fetch する(latest auto-track)。特定バージョンに pin したい場合のみ明示指定する。`POST /api/minion/skills` のレスポンスで `skill.id` (skill_id) と `skill.current_version_id` の両方が返るので、auto-track 運用なら前者だけ使えばよい
35
36
  - **Routine**: ミニオンスコープ。ミニオンローカルの定期タスク。
36
37
  - **Project Tasks / Milestones / Sprints**: プロジェクトスコープ。**人間+ミニオンが共有するタスクボード**(5段階Kanban: `backlog`→`todo`→`doing`→`review`→`done`)、ロードマップ(マイルストーン)、アジャイル運用単位(スプリント)。ミニオンは `/api/minion/projects/:projectId/{tasks,milestones,sprints,health}` で操作可能。
37
38
  - PMロールは朝のチェックで `/health` を叩いて遅延・停滞タスクを把握、ユーザー要望をエピック+子タスクに分解、スプリントに割り当てて active 化
@@ -225,6 +226,8 @@ Routine 実行中は以下もtmuxセッション環境で利用可能:
225
226
 
226
227
  **変数**(ワークスペース変数・プロジェクト変数・ワークフロー変数・ミニオン変数)はスキル本文の `{{VAR_NAME}}` テンプレートとして実行時に展開される。スキル作成時にパラメータ化したい値は `{{変数名}}` で記述すること。展開優先順位: ワークスペース < プロジェクト < ワークフロー < ミニオン(後者が優先)。ミニオンが最終オーバーライドとなる設計で、ミニオン運用者がHQ側のデフォルトを差し替えられる経路を保証する。ミニオン変数はさらにミニオン全体スコープとワークスペース別スコープに分かれ、当該ワークスペースのコンテキストで動く実行時はWS別がミニオン全体を上書きする。`/api/variables/*` は `?workspace_id=<uuid>` でスコープ指定(省略時はミニオン全体)。
227
228
 
229
+ DAGワークフローでは、HQ側スコープ(workspace/project/dag_workflow)の変数は **`POST /api/dag/minion/claim-node` のレスポンス `template_vars`** に乗って降ってきて、ミニオン側で minion-local 変数とマージしたうえで `POST /api/skills/fetch/:name?vars=...` の base64 JSON に詰めて HQ に渡し、HQ 側で SKILL.md の `{{VAR}}` を置換して返す。つまり HQ-scope 変数の更新は **次のノード claim から反映される**(既存のミニオン上 SKILL.md は次回 fetch で上書きされる)。DAGワークフロー単位の変数は `dag_workflow_variables` テーブルに格納され、DAGエディタの "Variables" ボタンから編集可能。
230
+
228
231
  **シークレット**はワークスペース別にスコープされ、ミニオンローカルのSQLite (`secrets(workspace_id, key, value)`) に保存される。ワークスペース未指定(`workspace_id=''`)はミニオン全体のスコープで、サーバー起動時に `process.env` にロードされ全子プロセスで `$SECRET_NAME` として利用可能。ワークスペース別シークレット(`workspace_id=<uuid>`)は `process.env` にはロードされず、当該ワークスペースのコンテキストで動くランナー(ワークフロー/WSバインドされたルーティン/チャットセッション)にのみ実行時注入される。同名キーが両スコープに存在する場合はワークスペース別が優先。スキル側は常に `$KEY` で参照すればよく、どちらのスコープから来た値かを意識する必要はない。シークレット値はHQ DBに保存されることはなく、HQはpass-throughとして中継するのみ。
229
232
 
230
233
  デイリーログやメモリーから変数・シークレットの値を推測して使用してはならない。変数は `{{VAR_NAME}}` テンプレートとして定義し、シークレットは環境変数として参照すること。
@@ -0,0 +1,97 @@
1
+ ---
2
+ name: accounting-bookkeeping
3
+ description: 会計帳簿の記帳・立替経費の処理・補助元帳の照会を行うワークフロー。使用タイミング:(1) 取引を仕訳として記録する時、(2) 役員・従業員の立替経費を記帳・精算する時、(3) 取引先別の残高を確認する時。accountantロールのミニオンが主に使用する。
4
+ ---
5
+
6
+ # Accounting Bookkeeping
7
+
8
+ 会計帳簿(HQ Accounting API)を操作するためのスキル。複式簿記の整合性を保ちながら、AI(ミニオン)が安全に記帳できるよう設計されている。
9
+
10
+ ## 前提
11
+
12
+ - ワークスペースで experimental_accounting feature flag が有効になっていること
13
+ - HQ API は `$HQ_URL/api/accounting/*` で利用可能(authentication は `Authorization: Bearer $API_TOKEN`)
14
+ - 1ワークスペース1帳簿の前提。`GET /books` で帳簿を取得し、勘定科目テンプレートはデフォルトで投入済み
15
+
16
+ ## 語彙
17
+
18
+ | 用語 | 説明 |
19
+ |------|------|
20
+ | **book(帳簿)** | ワークスペースに1冊。仕訳・科目・取引先のスコープ単位 |
21
+ | **account(勘定科目)** | 資産/負債/純資産/収益/費用の5型に分類。`is_wallet=true` のものが支払元(現金/預金)になる |
22
+ | **counterparty(取引先)** | 仕入先・顧客・役員・従業員などのマスタ。`kind` で種別を区別 |
23
+ | **journal entry(仕訳)** | 取引1件のヘッダ。複式簿記なので必ず複数の line を持つ |
24
+ | **journal line(仕訳明細)** | 借方/貸方の各行。`counterparty_id` を付与すると補助元帳が引ける |
25
+ | **expense reimbursement(立替経費)** | 役員/従業員が立て替えた経費。記帳仕訳と精算仕訳の対応を保持する別レイヤ |
26
+
27
+ ## 典型フロー
28
+
29
+ ### A) 通常取引の記帳
30
+
31
+ ```
32
+ 1. GET /api/accounting/accounts で勘定科目一覧取得
33
+ 2. 入金/出金口座(is_wallet=true)と相手勘定(費用 or 収益)を特定
34
+ 3. POST /api/accounting/entries でシンプル仕訳を作成
35
+ body: { entry_type: 'expense'|'income', entry_date, amount, wallet_account_id, category_account_id, description }
36
+ ```
37
+
38
+ 詳細: `references/api-journal-entries.md`
39
+
40
+ ### B) 立替経費の記帳
41
+
42
+ ```
43
+ 1. 立替者(役員/従業員)の counterparty を確認
44
+ - GET /api/accounting/counterparties?q=<name>&kind=director,employee
45
+ - 見つからなければ POST /api/accounting/counterparties で作成
46
+ - default_payable_account_id が未設定なら PATCH で先に設定する
47
+ 2. POST /api/accounting/expense-reimbursements で記帳
48
+ body: { paid_by_counterparty_id, occurred_on, amount, expense_account_id, description }
49
+ → 内部で「(借)費用 / (貸)立替者の負債科目」の仕訳が自動生成される
50
+ 3. レシートがあれば事前に POST /api/accounting/receipts でアップロードし、receipt_ids を渡す
51
+ ```
52
+
53
+ 詳細: `references/api-expense-reimbursement.md`
54
+
55
+ ### C) 立替経費の精算
56
+
57
+ ```
58
+ 1. GET /api/accounting/expense-reimbursements?settled=false で未精算リスト取得
59
+ 2. POST /api/accounting/expense-reimbursements/<id>/settle で精算
60
+ body: { settled_on, wallet_account_id }
61
+ → 内部で「(借)立替者の負債科目 / (貸)現金or預金」の仕訳が自動生成される
62
+ ```
63
+
64
+ 部分精算は非対応。全額精算のみ。
65
+
66
+ ### D) 補助元帳の照会
67
+
68
+ ```
69
+ GET /api/accounting/counterparties/<id>/balance
70
+ → 取引先別の残高(勘定科目ごと)・明細リスト・未精算立替件数を返す
71
+ ```
72
+
73
+ 詳細: `references/api-counterparties.md`
74
+
75
+ ## エラーレスポンスの読み方
76
+
77
+ 会計APIは AI 向けに以下の構造でエラーを返す:
78
+
79
+ ```json
80
+ {
81
+ "error": "missing_default_payable_account",
82
+ "message": "取引先「山田太郎」に立替用の貸方科目が未設定です",
83
+ "next_action": "PATCH /api/accounting/counterparties/<id> で default_payable_account_id を設定してください...",
84
+ "context": { "counterparty_id": "..." }
85
+ }
86
+ ```
87
+
88
+ **必ず `next_action` を読み、その指示に従うこと。** 推測で適当な処理を試みない。
89
+
90
+ 主要エラーパターンと対処は `references/troubleshooting.md` を参照。
91
+
92
+ ## 重要な制約
93
+
94
+ - **確定済み期間(closed)の日付では記帳できない。** 422/409 で拒否される。日付を変えるか PM に再オープン依頼
95
+ - **立替の貸方科目は負債(liability) or 純資産(equity)のみ許容。** 資産勘定の「立替金」(他人のために会社が立て替える勘定)は逆向きなので NG
96
+ - **counterparty マスタは book スコープ。** 別帳簿のIDは使えない
97
+ - **複式簿記の借方=貸方は trigger で強制される。** 自前で計算してから POST すること
@@ -0,0 +1,109 @@
1
+ # API: 取引先(Counterparties)
2
+
3
+ 取引先マスタは `book_id` スコープ。役員・従業員・仕入先・顧客などを統一管理する。
4
+
5
+ ## kind の選び方
6
+
7
+ | kind | 用途 |
8
+ |------|------|
9
+ | `vendor` | 仕入先・外注先・サブスク提供事業者など |
10
+ | `customer` | 顧客 |
11
+ | `director` | 役員(取締役・代表など)。立替経費の立替者になりうる |
12
+ | `employee` | 従業員。立替経費の立替者になりうる |
13
+ | `other` | その他 |
14
+
15
+ `member_id` で workspace_members に紐付け可能(役員/従業員のみ意味あり)。
16
+
17
+ ## default_payable_account_id
18
+
19
+ 立替記帳時の貸方デフォルト科目。`director`/`employee` の取引先には必ず設定すること。
20
+
21
+ - 推奨: **liability** 型の「役員借入金」「従業員未払金」など
22
+ - 許容: **equity** 型(運用実態として一部の帳簿で利用されるため)
23
+ - NG: **asset/revenue/expense** 型 → API が `invalid_default_payable_account` で 400 を返す
24
+
25
+ 該当科目が無い場合は先に `POST /api/accounting/accounts` で作成すること。
26
+
27
+ ## エンドポイント
28
+
29
+ ### GET /api/accounting/counterparties
30
+
31
+ ```
32
+ Query:
33
+ ?q=<部分一致検索>
34
+ ?kind=director,employee (カンマ区切り)
35
+ ?include_archived=true (デフォルトはアクティブのみ)
36
+ ?limit=200 (max 500)
37
+
38
+ Response:
39
+ { "counterparties": [{ id, book_id, name, kind, member_id, default_payable_account_id, is_archived, ... }] }
40
+ ```
41
+
42
+ ### POST /api/accounting/counterparties
43
+
44
+ ```
45
+ Body:
46
+ {
47
+ "name": "山田太郎",
48
+ "kind": "director",
49
+ "member_id": null,
50
+ "default_payable_account_id": "<account uuid>"
51
+ }
52
+
53
+ Response 201: { "counterparty": {...} }
54
+
55
+ エラー:
56
+ 400 invalid_kind — kind 不正
57
+ 400 invalid_default_payable_account — 指定した科目が立替貸方として不適切
58
+ 409 counterparty_name_conflict — 同名のアクティブな取引先が存在 (context.existing_id 参照)
59
+ ```
60
+
61
+ ### GET /api/accounting/counterparties/[id]
62
+
63
+ ```
64
+ Response: { "counterparty": {...} }
65
+ 404 counterparty_not_found
66
+ ```
67
+
68
+ ### PATCH /api/accounting/counterparties/[id]
69
+
70
+ ```
71
+ Body (全て任意):
72
+ { "name", "kind", "member_id", "default_payable_account_id", "is_archived" }
73
+
74
+ Response: { "counterparty": {...} }
75
+ ```
76
+
77
+ ### DELETE /api/accounting/counterparties/[id]
78
+
79
+ ソフト削除(`is_archived=true`)。物理削除はしない(過去仕訳の参照を保持するため)。
80
+
81
+ ```
82
+ エラー:
83
+ 409 has_unsettled_reimbursements — 未精算の立替が残っているとアーカイブ不可
84
+ ```
85
+
86
+ ### GET /api/accounting/counterparties/[id]/balance
87
+
88
+ 補助元帳。取引先別の残高(勘定科目別)と明細リスト。
89
+
90
+ ```
91
+ Query:
92
+ ?as_of=YYYY-MM-DD (任意。これより前の仕訳のみ集計)
93
+ ?limit=500 (明細最大件数)
94
+
95
+ Response:
96
+ {
97
+ "counterparty": {...},
98
+ "balance_by_account": [
99
+ { "account_id", "code", "name", "type", "debit", "credit", "balance" }
100
+ ],
101
+ "lines": [
102
+ { "id", "account_id", "debit", "credit", "memo", "entry": {...}, "account": {...} }
103
+ ],
104
+ "unsettled_reimbursements_count": 2,
105
+ "as_of": null
106
+ }
107
+ ```
108
+
109
+ 残高の符号: 資産/費用は `debit - credit`、負債/純資産/収益は `credit - debit`。
@@ -0,0 +1,120 @@
1
+ # API: 立替経費(Expense Reimbursements)
2
+
3
+ 立替経費は「立替記帳の仕訳」と「精算の仕訳」の対応関係を保持する別レイヤ。両仕訳の line に同じ `counterparty_id` が付与される。
4
+
5
+ ## 仕訳パターン
6
+
7
+ **立替記帳時:**
8
+ ```
9
+ (借) 費用科目 amount [counterparty_id=<立替者>]
10
+ (貸) counterparty.default_payable_account_id amount [counterparty_id=<立替者>]
11
+ ```
12
+
13
+ **精算時:**
14
+ ```
15
+ (借) counterparty.default_payable_account_id amount [counterparty_id=<立替者>]
16
+ (貸) wallet_account (現金 or 普通預金) amount [counterparty_id=<立替者>]
17
+ ```
18
+
19
+ ## エンドポイント
20
+
21
+ ### POST /api/accounting/expense-reimbursements
22
+
23
+ 立替経費を記帳する。
24
+
25
+ ```
26
+ Body:
27
+ {
28
+ "paid_by_counterparty_id": "<立替者のcounterparty uuid>",
29
+ "occurred_on": "YYYY-MM-DD",
30
+ "amount": 1000,
31
+ "expense_account_id": "<費用科目 uuid>",
32
+ "description": "新幹線代 東京→大阪", // 任意
33
+ "receipt_ids": ["<receipt uuid>"], // 任意。既存の未添付レシートを紐付ける
34
+ "category_dimensions": { // 任意。一般社団法人プロファイル等で expense 行に
35
+ "net_asset_restriction": "general" // ディメンションが必要な場合に指定。expense 行(借方)のみに付与される
36
+ }
37
+ }
38
+
39
+ Response 201: { "reimbursement": { "id", "expense_journal_entry_id" } }
40
+
41
+ 主要エラー:
42
+ 400 invalid_amount — amount が正の数値でない
43
+ 400 expense_account_not_found — 費用科目が見つからない / 別帳簿
44
+ 400 invalid_expense_account_type — expense_account_id が expense 型でない
45
+ 404 counterparty_not_found — 立替者が見つからない (next_action: POST で先に作成)
46
+ 409 counterparty_archived — 立替者がアーカイブ済み
47
+ 409 period_closed — occurred_on が締め済期間内
48
+ 422 missing_default_payable_account — 立替者の default_payable_account_id が未設定
49
+ ```
50
+
51
+ ### POST /api/accounting/expense-reimbursements/[id]/settle
52
+
53
+ 立替を全額精算する。**部分精算は非対応**。
54
+
55
+ ```
56
+ Body:
57
+ {
58
+ "settled_on": "YYYY-MM-DD",
59
+ "wallet_account_id": "<is_wallet=true の account uuid>"
60
+ }
61
+
62
+ Response: { "reimbursement": { "id", "expense_journal_entry_id" } }
63
+ ※ expense_journal_entry_id は精算仕訳のIDが返る
64
+
65
+ 主要エラー:
66
+ 404 reimbursement_not_found
67
+ 409 already_settled — 既に精算済み (context.settled_at 参照)
68
+ 409 period_closed — settled_on が締め済期間内
69
+ 400 wallet_account_not_found — 支払口座が見つからない
70
+ 400 not_a_wallet_account — is_wallet=false の科目を指定した
71
+ 422 missing_default_payable_account — 立替者の貸方科目が後から消去された場合
72
+ ```
73
+
74
+ ### GET /api/accounting/expense-reimbursements
75
+
76
+ ```
77
+ Query:
78
+ ?counterparty_id=<uuid>
79
+ ?settled=true|false (未指定なら両方)
80
+ ?from=YYYY-MM-DD&to=YYYY-MM-DD (occurred_on で絞り込み)
81
+ ?limit=200
82
+
83
+ Response:
84
+ {
85
+ "reimbursements": [{
86
+ id, paid_by_counterparty_id, occurred_on, amount, description,
87
+ expense_journal_entry_id, settled_at, settlement_journal_entry_id,
88
+ counterparty: { id, name, kind }
89
+ }]
90
+ }
91
+ ```
92
+
93
+ ### GET /api/accounting/expense-reimbursements/[id]
94
+
95
+ ```
96
+ Response:
97
+ {
98
+ "reimbursement": {
99
+ ...,
100
+ counterparty: {...},
101
+ expense_entry: {...},
102
+ settlement_entry: null|{...}
103
+ }
104
+ }
105
+ ```
106
+
107
+ ### DELETE /api/accounting/expense-reimbursements/[id]
108
+
109
+ 立替記帳の取消(精算前のみ)。関連する立替仕訳も同時に削除される。
110
+
111
+ ```
112
+ エラー:
113
+ 409 already_settled — 精算済みは取消不可
114
+ ```
115
+
116
+ ## ベストプラクティス
117
+
118
+ - 立替者を識別できない場合は推測しない。`GET /counterparties?q=<name>` で検索し、複数候補がある場合は **PMに確認** すること
119
+ - 「立替金」(asset 勘定として存在することがある)は会社が他者のために立て替えた場合の科目。**役員/従業員が立て替えた場合の貸方には使わない** こと
120
+ - 描かれた `next_action` を必ず読む。recover 可能なエラーは指示通りに対処
@@ -0,0 +1,100 @@
1
+ # API: 仕訳(Journal Entries)
2
+
3
+ 複式簿記の仕訳エンドポイント。立替経費以外の通常取引(収入/支出/振替/手動仕訳/期首残高)を扱う。
4
+
5
+ ## entry_type の区別
6
+
7
+ | entry_type | 用途 | buildLines の挙動 |
8
+ |-----------|------|------------------|
9
+ | `income` | 収入 | (借)wallet / (貸)category(収益) |
10
+ | `expense` | 支出 | (借)category(費用) / (貸)wallet |
11
+ | `transfer` | 振替 | (借)to_account / (貸)from_account |
12
+ | `manual` | 手動仕訳(複合仕訳) | lines を直接指定 |
13
+ | `opening_balance` | 期首残高 | 専用APIあり(本ドキュメント対象外) |
14
+
15
+ ## エンドポイント
16
+
17
+ ### POST /api/accounting/entries
18
+
19
+ **シンプル仕訳 (income/expense):**
20
+ ```
21
+ {
22
+ "entry_type": "expense",
23
+ "entry_date": "2026-05-25",
24
+ "amount": 1000,
25
+ "wallet_account_id": "<is_wallet=true の account>",
26
+ "category_account_id": "<expense 型の account>",
27
+ "description": "サーバー利用料",
28
+ "category_dimensions": { "net_asset_restriction": "general" } // 一般社団法人プロファイル時のみ必要
29
+ }
30
+ ```
31
+
32
+ **振替 (transfer):**
33
+ ```
34
+ {
35
+ "entry_type": "transfer",
36
+ "entry_date": "2026-05-25",
37
+ "amount": 50000,
38
+ "from_account_id": "<wallet account>",
39
+ "to_account_id": "<wallet account>",
40
+ "description": "現金→普通預金"
41
+ }
42
+ ```
43
+
44
+ **手動仕訳 (manual) - 複合仕訳が必要なときのみ:**
45
+ ```
46
+ {
47
+ "entry_type": "manual",
48
+ "entry_date": "2026-05-25",
49
+ "description": "...",
50
+ "lines": [
51
+ { "account_id": "...", "debit": 1000, "credit": 0, "memo": "...", "counterparty_id": "..." },
52
+ { "account_id": "...", "debit": 0, "credit": 1000, "counterparty_id": "..." }
53
+ ]
54
+ }
55
+ ```
56
+
57
+ **注意点:**
58
+ - `lines` は **必ず2行以上** で **借方合計=貸方合計** であること(DB triggerで強制される)
59
+ - `counterparty_id` は任意。付与すると補助元帳でその取引先の明細として集計される
60
+ - 一般社団法人プロファイルでは収益/費用行に `dimensions.net_asset_restriction` が必須
61
+
62
+ ```
63
+ Response: { "entry": {...} }
64
+ エラー:
65
+ 400 entry_date and entry_type are required
66
+ 400 at least 2 lines required
67
+ 400 debit/credit must balance
68
+ 409 period_closed
69
+ ```
70
+
71
+ ### PATCH /api/accounting/entries/[id]
72
+
73
+ 仕訳の編集。明細は全置換(既存lineを削除して body.lines を挿入)。
74
+
75
+ ```
76
+ 締めチェック:
77
+ - 元の entry_date が締め後 → 409 period_closed (編集不可)
78
+ - 新しい entry_date が締め後 → 409 (日付変更不可)
79
+ - opening_balance は編集不可(専用画面から再入力)
80
+ ```
81
+
82
+ ### DELETE /api/accounting/entries/[id]
83
+
84
+ 仕訳削除。lines は CASCADE で同時削除。
85
+
86
+ ### GET /api/accounting/entries
87
+
88
+ ```
89
+ Query:
90
+ ?from=YYYY-MM-DD&to=YYYY-MM-DD
91
+ ?limit=200
92
+
93
+ Response: { "entries": [{ ..., lines: [...] }] }
94
+ ```
95
+
96
+ ## ベストプラクティス
97
+
98
+ - **通常の経費は manual で複合仕訳を組まず、`expense` ですませる。** シンプルな分、間違いが少ない
99
+ - **立替経費は仕訳APIで組み立てず、必ず /expense-reimbursements を使う。** 自前で組むと「立替者」軸の集計ができない
100
+ - **dimensions の `net_asset_restriction`** は一般社団法人プロファイル時のみ意味あり。株式会社(corporation-jp)では空でOK
@@ -0,0 +1,117 @@
1
+ # Troubleshooting: 会計API
2
+
3
+ 会計APIで遭遇しやすいエラーパターンと対処。
4
+
5
+ ## エラーレスポンスの構造
6
+
7
+ ```json
8
+ {
9
+ "error": "missing_default_payable_account",
10
+ "message": "取引先「山田太郎」に立替用の貸方科目が未設定です",
11
+ "next_action": "PATCH /api/accounting/counterparties/<id> で...",
12
+ "context": { "counterparty_id": "..." }
13
+ }
14
+ ```
15
+
16
+ **必ず `next_action` を読み、その指示に従うこと。** 指示が曖昧な場合のみ自己判断する。
17
+
18
+ ## 立替経費まわり
19
+
20
+ ### `missing_default_payable_account` (422)
21
+
22
+ **原因:** 立替者の `default_payable_account_id` が未設定。
23
+
24
+ **対処:**
25
+ 1. liability 型の科目「役員借入金」「従業員未払金」などがあるか確認
26
+ - `GET /api/accounting/accounts` で `type=liability` をフィルタ
27
+ 2. 無ければ作成: `POST /api/accounting/accounts` で `{ name: "役員借入金", type: "liability" }`
28
+ 3. counterparty に紐付け: `PATCH /api/accounting/counterparties/<id>` で `{ default_payable_account_id: "..." }`
29
+ 4. 立替記帳をリトライ
30
+
31
+ ### `counterparty_not_found` (404)
32
+
33
+ **原因:** 立替者の counterparty が未登録。
34
+
35
+ **対処:**
36
+ 1. `GET /api/accounting/counterparties?q=<name>` で typo の可能性を確認
37
+ 2. 該当者がいなければ `POST /api/accounting/counterparties` で作成
38
+ - 役員なら `kind: "director"`、従業員なら `kind: "employee"`
39
+ - 可能なら `default_payable_account_id` も同時に設定
40
+
41
+ ### `counterparty_name_conflict` (409)
42
+
43
+ **原因:** 同名のアクティブな取引先が既に存在(本人と判断できない場合がある)。
44
+
45
+ **対処:**
46
+ - `context.existing_id` が返るので、それが同一人物か確認
47
+ - 同一人物なら既存IDを使う
48
+ - 別人なら名前を変える(例: "山田太郎(役員)" vs "山田太郎(従業員)")
49
+
50
+ ### `already_settled` (409)
51
+
52
+ **原因:** 精算しようとした立替が既に精算済み。
53
+
54
+ **対処:** `context.settled_at` と `context.settlement_journal_entry_id` を確認し、二重精算を回避
55
+
56
+ ## 期間まわり
57
+
58
+ ### `period_closed` (409)
59
+
60
+ **原因:** 指定日付が締め済期間内。
61
+
62
+ **対処:**
63
+ - 締めはPMの権限。勝手に再オープンしない
64
+ - 締め後の取引なら日付を調整(後日付に変更)、または PM にエスカレーション
65
+ - threadで `mentions: ["role:pm"]` を付けて「<DATE> の取引が締め後だが記帳が必要」と相談
66
+
67
+ ## 科目まわり
68
+
69
+ ### `invalid_expense_account_type` (400)
70
+
71
+ **原因:** 立替経費の費用科目に expense 型でない科目を指定した。
72
+
73
+ **対処:** `GET /api/accounting/accounts` で type=expense の科目を取得して使用
74
+
75
+ ### `not_a_wallet_account` (400)
76
+
77
+ **原因:** 精算時の支払口座に `is_wallet=false` の科目を指定した。
78
+
79
+ **対処:** `is_wallet=true` の科目(現金/普通預金)を選択
80
+
81
+ ### `invalid_default_payable_account` (400)
82
+
83
+ **原因:** default_payable_account_id に asset/revenue/expense 型を指定した。
84
+
85
+ **対処:** liability 型(または equity 型)の科目を指定する。「立替金」(asset)は逆向きなので使わない
86
+
87
+ ## 仕訳整合性
88
+
89
+ ### `at least 2 lines required` / `debit/credit must balance`
90
+
91
+ **原因:** 手動仕訳の `lines` が壊れている。
92
+
93
+ **対処:**
94
+ - lines は2行以上必要
95
+ - 借方合計 = 貸方合計 を自前で計算してから POST
96
+ - DB trigger は不整合を必ず検出するので、ローカル検算が大事
97
+
98
+ ## 取引先のアーカイブ
99
+
100
+ ### `has_unsettled_reimbursements` (409)
101
+
102
+ **原因:** 未精算の立替が残っている取引先をアーカイブしようとした。
103
+
104
+ **対処:**
105
+ 1. `GET /api/accounting/expense-reimbursements?counterparty_id=<id>&settled=false` で未精算リスト取得
106
+ 2. 各立替を精算 (`POST /<id>/settle`)
107
+ 3. アーカイブを再実行
108
+
109
+ ## 自己解決できない場合
110
+
111
+ エラーの `next_action` が無い、または指示通り対処しても繰り返し失敗する場合:
112
+
113
+ 1. プロジェクトメモリーで過去事例を検索
114
+ 2. なければ `POST /api/threads` でヘルプスレッド起票
115
+ - `thread_type: "help"`, `mentions: ["role:pm"]`
116
+ - `attempted_resolution` に試したことを必ず書く
117
+ 3. **仕訳を中途半端な状態で残さない。** 失敗した立替記帳は `DELETE /api/accounting/expense-reimbursements/<id>` で取り消してからエスカレーション