kenaz 0.3.5 → 0.3.6
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/core/.claude/commands/Ansuz.md +1 -0
- package/core/.formation/native/claude/README.md +1 -1
- package/core/.formation/role-map.yaml +3 -3
- package/core/.formation/spec/task_operations.yaml +3 -3
- package/core/.formation/tools/__tests__/subagent-bifrost-guard.test.js +4 -4
- package/core/.formation/tools/dispatch.js +5 -5
- package/core/.formation/tools/prompt.js +4 -0
- package/core/.formation/unit/do.yaml +2 -4
- package/core/.rule/general/agent-workflow.yaml +4 -4
- package/core/.rule/general/file-size-threshold.yaml +16 -4
- package/core/.rule/general/rust-verify-target.yaml +0 -1
- package/core/.rule/general/system-invariants.yaml +8 -25
- package/core/.specialist/Ansuz/SYSTEM_DOC.md +17 -42
- package/core/.specialist/Ansuz/capability.yaml +7 -14
- package/core/.specialist/Ansuz/concepts/formation_quick_ref.yaml +4 -11
- package/core/.specialist/Ansuz/elixir.yaml +3 -4
- package/core/.specialist/Ansuz/identity_contract.yaml +1 -1
- package/core/.specialist/Ansuz/knowledge.yaml +7 -10
- package/core/.specialist/Ansuz/rule.yaml +2 -2
- package/core/.specialist/Ansuz/tools/verify-and-land.js +22 -0
- package/core/.specialist/Ansuz/tools/verify-and-land.test.js +59 -5
- package/core/.specialist/Ansuz/workflow.yaml +7 -11
- package/core/.specialist/Forseti/core.yaml +1 -1
- package/core/.specialist/Heimdall/SKILL.md +1 -1
- package/core/.specialist/Heimdall/core.yaml +2 -2
- package/core/.specialist/Huginn/rule.yaml +1 -1
- package/core/.specialist/tools/README.md +2 -2
- package/core/.system/collaboration/README.md +1 -1
- package/core/.system/formation/LEGACY_SKILLS.md +2 -0
- package/core/.system/formation/POST_COMPLETE.md +2 -0
- package/core/.system/formation/README.md +2 -0
- package/core/KENAZ_CORE_VERSION +1 -1
- package/core/dev/scripts/check-file-size.js +44 -17
- package/core/k-cli/README.md +1 -94
- package/core/k-cli/test/TEST_SPEC.md +5 -22
- package/core/k-cli/test/run.sh +1 -67
- package/core/plugins/kenaz/commands/Ansuz.md +1 -0
- package/package.json +6 -6
- package/core/.formation/legion/forge.yaml +0 -299
- package/core/.formation/legion/hive.yaml +0 -238
- package/core/.formation/squad/blitz.yaml +0 -192
- package/core/.formation/squad/strategy-tribunal.yaml +0 -354
- package/core/.formation/squad/strategy.yaml +0 -349
- package/core/.formation/squad/sweep.yaml +0 -208
|
@@ -23,6 +23,7 @@ ARGUMENTS 含 `[專案: X]` 或 `--project-path X` → PROJECT_PATH = X,下方
|
|
|
23
23
|
- 有**對照組**:證明測試在舊程式上會失敗,或修改前後結果不同。
|
|
24
24
|
- subagent 回報「未驗證」的項目,由你補驗或明講仍未驗證。
|
|
25
25
|
- 合併:`git merge` 後跑相關測試(或 `node .specialist/Ansuz/tools/verify-and-land.js`),用這個專案自己的測試指令。
|
|
26
|
+
- 檔案長度:verify-and-land 合併前會跑 `check-file-size`(警告 1000 / 上限 2000 行,既有超長檔只擋「未配套拆分的增長」);被擋就按職責拆成 module / component / hook。
|
|
26
27
|
- 只在 Kenaz 核心 repo 本身:Rust 測試走 `npm run test:rust` / `dev/scripts/rust-verify-worktree.js`。
|
|
27
28
|
|
|
28
29
|
## 回報
|
|
@@ -51,7 +51,7 @@ no surprise dependencies.
|
|
|
51
51
|
4. When the user picks an entry, the id is written into
|
|
52
52
|
`.kenaz/dashboard-models.json` via
|
|
53
53
|
`POST /api/dashboard/settings/models` and consumed by
|
|
54
|
-
`
|
|
54
|
+
`SpecialistPanel.handleLaunch`.
|
|
55
55
|
|
|
56
56
|
## Adding a new model
|
|
57
57
|
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
# Amelia 判斷 role 時參考此表,dispatch 時用此表解析 --role 路徑
|
|
4
4
|
#
|
|
5
5
|
# Usage:
|
|
6
|
-
# node .formation/tools/
|
|
7
|
-
#
|
|
6
|
+
# node .formation/tools/dispatch.js --skill=do --task=TASK_XXX --dispatch-mode=subagent
|
|
7
|
+
# (此表僅供 Amelia 判斷 role 參考;dispatch.js 不讀取它。headless-v2 已退役)
|
|
8
8
|
|
|
9
9
|
version: "2.0"
|
|
10
10
|
|
|
@@ -259,7 +259,7 @@ roles:
|
|
|
259
259
|
- 新功能開發
|
|
260
260
|
|
|
261
261
|
# ─────────────────────────────────────────
|
|
262
|
-
# Base Skills
|
|
262
|
+
# Base Skills(歷史:原 headless-v2 的 --base 選項)
|
|
263
263
|
# ─────────────────────────────────────────
|
|
264
264
|
|
|
265
265
|
bases:
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
#
|
|
5
5
|
# Consumers:
|
|
6
6
|
# A: .collaboration/core/task-api.js — full lifecycle (create/claim/complete/move/delete/get/list)
|
|
7
|
-
# B: .formation/tools/
|
|
7
|
+
# B: .formation/tools/dispatch.js — dispatch coordinator (no direct state mutation; triggers post-complete)
|
|
8
8
|
# C: .formation/tools/post-complete.js — close-out only (active→done or active→blocked; never creates)
|
|
9
9
|
# D: dashboard kenaz MCP tools (kenaz.rs) — CRUD subset only (list/get/create/update/delete via task-api CLI proxy)
|
|
10
10
|
#
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# MCP does NOT have standalone claim, complete, or move tools — these are action values in tool_task_update.
|
|
14
14
|
# task-api.js (consumer A) owns the full state machine and all lifecycle transitions.
|
|
15
15
|
# post-complete.js (consumer C) is exclusively close-out; it calls task-api complete/move internally.
|
|
16
|
-
#
|
|
16
|
+
# dispatch.js (consumer B) coordinates dispatch and triggers post-complete on task completion.
|
|
17
17
|
#
|
|
18
18
|
# STATUS DUALITY (known divergence):
|
|
19
19
|
# Filesystem directory names (canonical): backlog, active, done, blocked, cancel, archived
|
|
@@ -153,7 +153,7 @@ operations:
|
|
|
153
153
|
post_complete_trigger: true
|
|
154
154
|
known_asymmetry:
|
|
155
155
|
- "moveTask(taskId, 'done') achieves same filesystem effect but does NOT trigger post-complete"
|
|
156
|
-
- "Consumer B (
|
|
156
|
+
- "Consumer B (dispatch.js) does not mutate task state itself; post-complete runs separately"
|
|
157
157
|
error_modes:
|
|
158
158
|
- "Task not found → throws"
|
|
159
159
|
- "post-complete failure → logged as warning; task already moved to done (non-atomic)"
|
|
@@ -95,8 +95,8 @@ setModels({ dispatchModel: 'gpt-5-codex', dispatchFamily: 'bifrost', dispatchAda
|
|
|
95
95
|
check('reject bifrost+adapter: no agentParams on stdout', !(r.stdout || '').includes('agentParams'), (r.stdout || '').slice(0, 200));
|
|
96
96
|
check('reject bifrost+adapter: invariant wording (refusing to silently dispatch)',
|
|
97
97
|
(r.stderr || '').includes('refusing to silently dispatch with the native Claude CLI'), (r.stderr || '').slice(-400));
|
|
98
|
-
check('reject bifrost+adapter: remediation
|
|
99
|
-
(r.stderr || '').includes('kenaz_dispatch'), (r.stderr || '').slice(-400));
|
|
98
|
+
check('reject bifrost+adapter: remediation tells the user to pick a Claude model',
|
|
99
|
+
(r.stderr || '').includes('Select a Claude model') && !(r.stderr || '').includes('kenaz_dispatch'), (r.stderr || '').slice(-400));
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
// ── [3] reject: dispatchFamily=bifrost, adapter missing/empty ───────────────
|
|
@@ -175,8 +175,8 @@ setModels({ dispatchModel: 'claude-nova-9', dispatchFamily: 'claude' });
|
|
|
175
175
|
check('unmappable model: loud stderr (refusing to silently guess)',
|
|
176
176
|
(r.stderr || '').includes("dispatchModel 'claude-nova-9' cannot be mapped") &&
|
|
177
177
|
(r.stderr || '').includes('refusing to silently guess'), (r.stderr || '').slice(-400));
|
|
178
|
-
check('unmappable model: remediation points
|
|
179
|
-
(r.stderr || '').includes('kenaz_dispatch'), (r.stderr || '').slice(-400));
|
|
178
|
+
check('unmappable model: remediation points at the model selection, not retired kenaz_dispatch',
|
|
179
|
+
(r.stderr || '').includes('Fix the model selection') && !(r.stderr || '').includes('kenaz_dispatch'), (r.stderr || '').slice(-400));
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
// ── [9]-[11] TASK_2032: subagent dispatch activates the card like the ────────
|
|
@@ -990,14 +990,14 @@ async function getSubagentDispatchParams(options) {
|
|
|
990
990
|
}
|
|
991
991
|
if (routing.family === 'bifrost' && !isCodex) {
|
|
992
992
|
if (!routing.adapter) {
|
|
993
|
-
console.error('❌ dashboard-models.json sets dispatchFamily=bifrost but dispatchAdapter is missing/empty — refusing to silently dispatch with the native Claude CLI. Fix the model selection (Quick Actions → Default Models) or dashboard-models.json
|
|
993
|
+
console.error('❌ dashboard-models.json sets dispatchFamily=bifrost but dispatchAdapter is missing/empty — refusing to silently dispatch with the native Claude CLI. Fix the model selection (Quick Actions → Default Models) or dashboard-models.json.');
|
|
994
994
|
} else {
|
|
995
|
-
console.error(`❌ dashboard-models.json sets dispatchFamily=bifrost (dispatchAdapter '${routing.adapter}') — sub-agent dispatch cannot run non-Claude models (the Agent tool only accepts Claude models); refusing to silently dispatch with the native Claude CLI.
|
|
995
|
+
console.error(`❌ dashboard-models.json sets dispatchFamily=bifrost (dispatchAdapter '${routing.adapter}') — sub-agent dispatch cannot run non-Claude models (the Agent tool only accepts Claude models); refusing to silently dispatch with the native Claude CLI. Select a Claude model in Default Models.`);
|
|
996
996
|
}
|
|
997
997
|
return null;
|
|
998
998
|
}
|
|
999
999
|
if (!isCodex && routing.family && routing.family !== 'claude') {
|
|
1000
|
-
console.error(`❌ dashboard-models.json sets unsupported dispatchFamily '${routing.family}' (expected 'claude' or 'bifrost') — refusing to silently dispatch with the native Claude CLI. Fix the model selection (Quick Actions → Default Models)
|
|
1000
|
+
console.error(`❌ dashboard-models.json sets unsupported dispatchFamily '${routing.family}' (expected 'claude' or 'bifrost') — refusing to silently dispatch with the native Claude CLI. Fix the model selection (Quick Actions → Default Models).`);
|
|
1001
1001
|
return null;
|
|
1002
1002
|
}
|
|
1003
1003
|
|
|
@@ -1017,7 +1017,7 @@ async function getSubagentDispatchParams(options) {
|
|
|
1017
1017
|
// TASK_2315: Codex inherits the session model — nothing to translate or pass.
|
|
1018
1018
|
const translated = isCodex ? { model: null, lossless: true } : translateModelForAgentTool(rawModel);
|
|
1019
1019
|
if (!isCodex && !translated.model) {
|
|
1020
|
-
console.error(`❌ ${resolution.label} '${rawModel}' cannot be mapped to an Agent tool model family (${AGENT_TOOL_MODEL_ENUM.join('|')}) — refusing to silently guess a substitute model. Fix the model selection (Quick Actions → Default Models)
|
|
1020
|
+
console.error(`❌ ${resolution.label} '${rawModel}' cannot be mapped to an Agent tool model family (${AGENT_TOOL_MODEL_ENUM.join('|')}) — refusing to silently guess a substitute model. Fix the model selection (Quick Actions → Default Models).`);
|
|
1021
1021
|
return null;
|
|
1022
1022
|
}
|
|
1023
1023
|
const dispatchModel = translated.model;
|
|
@@ -1025,7 +1025,7 @@ async function getSubagentDispatchParams(options) {
|
|
|
1025
1025
|
? { requested: rawModel, inherited: true }
|
|
1026
1026
|
: { requested: rawModel, agentToolModel: dispatchModel, granularityLoss: !translated.lossless };
|
|
1027
1027
|
if (!translated.lossless) {
|
|
1028
|
-
process.stderr.write(`[dispatch] model '${rawModel}' → Agent tool family '${dispatchModel}' — the Agent tool only expresses family names (${AGENT_TOOL_MODEL_ENUM.join('|')}); version/speed selections (e.g. 5 vs 4.x, [1m]) are NOT expressible on the subagent path. If the exact version matters,
|
|
1028
|
+
process.stderr.write(`[dispatch] model '${rawModel}' → Agent tool family '${dispatchModel}' — the Agent tool only expresses family names (${AGENT_TOOL_MODEL_ENUM.join('|')}); version/speed selections (e.g. 5 vs 4.x, [1m]) are NOT expressible on the subagent path. If the exact version matters, choose a model whose family the Agent tool can express.\n`);
|
|
1029
1029
|
}
|
|
1030
1030
|
// TASK_1998 R3 (+ two-axis policy): the resolved choice, always printed
|
|
1031
1031
|
// (unlike the granularity block above, which only fires on lossy translation).
|
|
@@ -171,6 +171,10 @@ function buildSubagentPrompt(skillDef, taskInput, taskData, options = {}) {
|
|
|
171
171
|
// Ponytail A/B 2026-10-10: the arm without this line broke an existing fixture test it never ran.
|
|
172
172
|
lines.push('Before editing, grep the callers, tests and fixtures your change reaches; fix what it breaks. Least code that completes the card: reuse existing helpers, no unrequested abstraction, option or duplicate implementation.');
|
|
173
173
|
lines.push('Run the tests the card names (narrow, not the full suite); say what you did not verify.');
|
|
174
|
+
// The worktree branches off the project's current branch; user projects are not always on `main`.
|
|
175
|
+
const sizeBase = (require('child_process').spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd: options.projectPath || process.cwd(), encoding: 'utf8' }).stdout || '').trim() || 'main';
|
|
176
|
+
const sizeCorePath = options.corePath || resolveCorePath(options.projectPath) || path.resolve(__dirname, '..', '..');
|
|
177
|
+
lines.push(`Before reporting run \`node ${sizeCorePath}/dev/scripts/check-file-size.js --base ${sizeBase} --head HEAD\`; if it BLOCKs, split by responsibility (module / component / hook) first.`);
|
|
174
178
|
const onBlocked = skillDef.collaboration && skillDef.collaboration.on_blocked;
|
|
175
179
|
if (onBlocked && onBlocked.run) {
|
|
176
180
|
lines.push(`Blocked: \`${buildTaskApiRewriter(options)(onBlocked.run).replace(/\{task_id\}/g, taskId)}\` and explain.`);
|
|
@@ -48,10 +48,8 @@ collaboration:
|
|
|
48
48
|
- 根據 acceptance_criteria 驗證成果
|
|
49
49
|
# TASK_1819: 此處原有的 worktree_path_rule 欄位已移除 — 它是死欄位,
|
|
50
50
|
# prompt.js 的 appendWorkflow 只讀 step/run/note/actions,從未渲染它,
|
|
51
|
-
# 且其範例路徑早已過時。實際生效的 worktree 路徑規則由
|
|
52
|
-
#
|
|
53
|
-
# operations MUST use paths under: <worktreeDir>" 前綴,含具體路徑),
|
|
54
|
-
# Agent-tool 派工另由 prompt.js SUBAGENT_PREFIX 規則 11 覆蓋。
|
|
51
|
+
# 且其範例路徑早已過時。實際生效的 worktree 路徑規則由
|
|
52
|
+
# prompt.js SUBAGENT_PREFIX 規則 11 覆蓋(原 runner.js 注入已隨 headless 路徑移除)。
|
|
55
53
|
|
|
56
54
|
# 注意(TASK_1819):下方 run 的 git add -A 只會在隔離模式(worktree /
|
|
57
55
|
# subagent)原樣渲染;serial 共用工作樹模式下 prompt.js appendWorkflow
|
|
@@ -543,15 +543,15 @@ rules:
|
|
|
543
543
|
- id: "AGT-010"
|
|
544
544
|
title: "Dispatch 後切回 User Branch"
|
|
545
545
|
description: |
|
|
546
|
-
Formation headless
|
|
546
|
+
(已退役)Formation headless dispatch 曾在獨立進程中建立 task branch(task/task_XXX),
|
|
547
547
|
完成後 post-complete.js 會 merge 回 user branch。但呼叫者(Ansuz/Agent)的
|
|
548
548
|
working tree 仍停留在 task branch 上。
|
|
549
549
|
|
|
550
550
|
如果 dispatch 後繼續在同一 session 做其他改動,會意外 commit 到 task branch,
|
|
551
551
|
而不是 user branch。用戶在桌面端會看到 branch 不一致。
|
|
552
552
|
severity: "must"
|
|
553
|
-
rationale: "headless
|
|
554
|
-
trigger: "Formation dispatch
|
|
553
|
+
rationale: "headless dispatch 是獨立進程(已退役,僅供歷史參照),不會切換呼叫者的 git working tree"
|
|
554
|
+
trigger: "legacy Formation dispatch 完成後,Ansuz 或 Agent 要做下一個改動之前"
|
|
555
555
|
workflow:
|
|
556
556
|
- step: 1
|
|
557
557
|
action: "確認 dispatch 完成(task status = completed)"
|
|
@@ -568,5 +568,5 @@ rules:
|
|
|
568
568
|
❌ 多個 task 共用同一個 task branch(每個 task 應有自己的 branch)
|
|
569
569
|
applies_to:
|
|
570
570
|
- "Ansuz(PM dispatch 後繼續做其他工作)"
|
|
571
|
-
- "
|
|
571
|
+
- "任何仍經 legacy Formation dispatch 的 Agent"
|
|
572
572
|
- "用戶手動 dispatch 後"
|
|
@@ -9,8 +9,8 @@ rules:
|
|
|
9
9
|
Single-file growth is the primary vector for SRP violations in this codebase.
|
|
10
10
|
Enforce line-count thresholds to force extraction before files become unmaintainable.
|
|
11
11
|
thresholds:
|
|
12
|
-
warn:
|
|
13
|
-
hard_limit:
|
|
12
|
+
warn: 1000
|
|
13
|
+
hard_limit: 2000
|
|
14
14
|
scope:
|
|
15
15
|
include:
|
|
16
16
|
- "**/*.rs"
|
|
@@ -22,20 +22,32 @@ rules:
|
|
|
22
22
|
- "**/target/**"
|
|
23
23
|
- "**/node_modules/**"
|
|
24
24
|
- "**/*.test.*"
|
|
25
|
+
- "**/*_test.*"
|
|
26
|
+
- "**/tests/**"
|
|
27
|
+
- "**/__tests__/**"
|
|
28
|
+
- "**/*.generated.*"
|
|
25
29
|
- "**/*.spec.*"
|
|
26
30
|
- "**/*.d.ts"
|
|
27
31
|
- "**/generated/**"
|
|
28
32
|
enforcement:
|
|
29
33
|
on_task_design: |
|
|
30
|
-
When designing a task that adds >50 LOC to a file already above warn threshold (
|
|
34
|
+
When designing a task that adds >50 LOC to a file already above warn threshold (1000 lines):
|
|
31
35
|
1. Check current file size (wc -l or kenaz_lsp_symbols)
|
|
32
36
|
2. If file > warn: acceptance criteria MUST include "extract [new responsibility] into separate module"
|
|
33
37
|
3. If file > hard_limit: task MUST be split — one task for extraction, one for the new feature
|
|
34
38
|
Ansuz must enforce this at task design time, not defer to the implementing agent.
|
|
35
39
|
on_code_review: |
|
|
36
|
-
Any PR that increases a file past hard_limit (
|
|
40
|
+
Any PR that increases a file past hard_limit (2000 lines) without a paired extraction
|
|
37
41
|
commit is a Blocker-level review finding.
|
|
38
42
|
existing_debt: |
|
|
43
|
+
Decision 2026-10-10 (user, via Ansuz): warn 1000 / hard_limit 2000 lines for source
|
|
44
|
+
files; tests and generated files are excluded. Existing over-limit files are
|
|
45
|
+
GRANDFATHERED: dev/scripts/check-file-size.js only blocks growth of such a file (>50 LOC)
|
|
46
|
+
without a paired extraction (a new file in the same change), or a file newly crossing
|
|
47
|
+
hard_limit. Split by responsibility (module / component / hook) when you touch one.
|
|
48
|
+
Enforced in verify-and-land.js (file-size step, before merge) and the subagent
|
|
49
|
+
"Verify and report" prompt line. Without this yaml (user project) the script uses the
|
|
50
|
+
same defaults built in.
|
|
39
51
|
Files currently above hard_limit are tracked as architecture debt.
|
|
40
52
|
Extraction tasks should be created incrementally — do not attempt big-bang refactors.
|
|
41
53
|
Follow the three-stage pattern: build-map → plan-split → minimal-patch.
|
|
@@ -33,7 +33,6 @@ rules:
|
|
|
33
33
|
file: "dev/scripts/verify-target-dir.js"
|
|
34
34
|
consumers:
|
|
35
35
|
- "dev/scripts/run-rust-tests.js (defaults CARGO_TARGET_DIR when unset)"
|
|
36
|
-
- ".formation/tools/runner.js (worktree dispatch env, 2 call sites)"
|
|
37
36
|
- ".formation/tools/integration.js (in-lock re-verify env)"
|
|
38
37
|
shell_usage: "CARGO_TARGET_DIR=$(node dev/scripts/verify-target-dir.js) cargo check --lib -p kenaz-dashboard"
|
|
39
38
|
|
|
@@ -90,19 +90,6 @@ invariants:
|
|
|
90
90
|
# Parallel execution caps, locks, isolation boundaries
|
|
91
91
|
# ============================================================================
|
|
92
92
|
|
|
93
|
-
- name: max_parallel_dispatches
|
|
94
|
-
category: concurrency
|
|
95
|
-
formula: "concurrent_worktree_dispatches ≤ MAX_PARALLEL"
|
|
96
|
-
bound: "MAX_PARALLEL = 5"
|
|
97
|
-
enforcement: |
|
|
98
|
-
Semaphore in formations.js dispatch loop — when count reaches
|
|
99
|
-
MAX_PARALLEL, new dispatches wait. Logs "Max parallel dispatches
|
|
100
|
-
reached (N/5), waiting...".
|
|
101
|
-
violation_detection: |
|
|
102
|
-
Count live worktree dispatches (.formation/worktrees/task_*/ with
|
|
103
|
-
active child processes); if > 5, semaphore leaked.
|
|
104
|
-
source: ".formation/tools/formations.js#L773-L810 (MAX_PARALLEL semaphore)"
|
|
105
|
-
|
|
106
93
|
- name: worktree_isolation_boundary
|
|
107
94
|
category: concurrency
|
|
108
95
|
formula: |
|
|
@@ -111,17 +98,13 @@ invariants:
|
|
|
111
98
|
repo paths)
|
|
112
99
|
bound: "one worktree per active dispatch; no cross-worktree writes"
|
|
113
100
|
enforcement: |
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
worktreeDir is set. Agent-tool dispatch additionally carries
|
|
118
|
-
SUBAGENT_PREFIX rule 11 (WORKTREE FILE PATH RULE) in prompt.js.
|
|
119
|
-
(TASK_1819: the former do.yaml worktree_path_rule field was a dead
|
|
120
|
-
field — never rendered by prompt.js — and has been removed.)
|
|
101
|
+
Agent-tool dispatch carries SUBAGENT_PREFIX rule 11 (WORKTREE FILE
|
|
102
|
+
PATH RULE) in prompt.js. (The former runner.js spawn-time "[WORKTREE]"
|
|
103
|
+
injection was removed with the headless path, TASK_2401.)
|
|
121
104
|
violation_detection: |
|
|
122
105
|
Agent Edits a path under main repo root while cwd is a worktree →
|
|
123
106
|
`git add -A` in worktree finds no changes. See FAIL-013.
|
|
124
|
-
source: ".formation/tools/
|
|
107
|
+
source: ".formation/tools/prompt.js SUBAGENT_PREFIX rule 11"
|
|
125
108
|
failure_witness: ".failure/agent-execution/FAIL-013-search-cwd-drift-and-case-mismatch.yaml"
|
|
126
109
|
|
|
127
110
|
- name: per_project_dispatch_lock
|
|
@@ -129,13 +112,13 @@ invariants:
|
|
|
129
112
|
formula: "per-project dispatch-lock serializes non-worktree dispatches"
|
|
130
113
|
bound: "1 in-flight serial dispatch per project at a time"
|
|
131
114
|
enforcement: |
|
|
132
|
-
Dispatch-lock fallback in
|
|
133
|
-
|
|
134
|
-
per-project serial lock.
|
|
115
|
+
Dispatch-lock fallback in dispatch.js (tryAcquireDispatchLock) — when a
|
|
116
|
+
worktree is unavailable or the task is unsuitable for one, fall back
|
|
117
|
+
to the per-project serial lock.
|
|
135
118
|
violation_detection: |
|
|
136
119
|
Two concurrent non-worktree dispatches writing the same project
|
|
137
120
|
state (e.g., task-api moves). Lock contention visible in logs.
|
|
138
|
-
source: ".formation/tools/
|
|
121
|
+
source: ".formation/tools/dispatch.js (tryAcquireDispatchLock) + .formation/tools/utils.js (dispatchLockPath)"
|
|
139
122
|
|
|
140
123
|
# ============================================================================
|
|
141
124
|
# CATEGORY: cognitive
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
身份: "Ansuz = 產品全生命週期引擎(PM + Lead 合一)"
|
|
37
37
|
行為規則:
|
|
38
38
|
❌ 不 invoke 其他 Skill — 不切換身份
|
|
39
|
-
✅ 需要執行時 →
|
|
39
|
+
✅ 需要執行時 → Agent tool subagent dispatch(dispatch.js --dispatch-mode=subagent)
|
|
40
40
|
✅ 本體負責:需求理解、任務設計、陣型判斷、調度、追蹤、回報
|
|
41
41
|
❌ 不親自寫程式碼 — 只做決策和調度
|
|
42
42
|
```
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
**工作模式**:
|
|
45
45
|
- **Ansuz = 指揮官 + 調度者**,不是執行者
|
|
46
46
|
- 所有實作交給 Formation 系統的 agent(developer, backend, designer...)
|
|
47
|
-
- 通過 `.formation/tools/
|
|
47
|
+
- 通過 `.formation/tools/dispatch.js` 組裝 prompt,再由 Agent tool subagent 執行任務
|
|
48
48
|
|
|
49
49
|
### 2. 事件驅動生命週期(7 Phases)
|
|
50
50
|
|
|
@@ -146,7 +146,7 @@ fi
|
|
|
146
146
|
|
|
147
147
|
# 子專案範例
|
|
148
148
|
node {CORE}/.collaboration/core/task-api.js --project-path {PROJECT_PATH} list
|
|
149
|
-
node {CORE}/.formation/tools/
|
|
149
|
+
node {CORE}/.formation/tools/dispatch.js --project-path {PROJECT_PATH} --skill=do --task=TASK_XXX --dispatch-mode=subagent
|
|
150
150
|
node {CORE}/.formation/tools/post-complete.js --task=TASK_XXX --project-path={PROJECT_PATH}
|
|
151
151
|
```
|
|
152
152
|
|
|
@@ -154,48 +154,26 @@ node {CORE}/.formation/tools/post-complete.js --task=TASK_XXX --project-path={PR
|
|
|
154
154
|
|
|
155
155
|
### 2. Dispatch 執行機制
|
|
156
156
|
|
|
157
|
-
**工具**: `.formation/tools/
|
|
158
|
-
**方法**: Bash tool → `node
|
|
157
|
+
**工具**: `.formation/tools/dispatch.js`
|
|
158
|
+
**方法**: Bash tool → `node dispatch.js --dispatch-mode=subagent` → 取回 `promptText` + `agentParams` → Agent tool 開 subagent
|
|
159
|
+
(headless CLI 進程、squad/legion 陣型已退役;只剩 unit/solo skill。)
|
|
159
160
|
|
|
160
161
|
**CLI 命令格式**:
|
|
161
162
|
|
|
162
163
|
```bash
|
|
163
164
|
# Unit 陣型
|
|
164
|
-
node .formation/tools/
|
|
165
|
+
node .formation/tools/dispatch.js --skill=do --task=TASK_XXX --dispatch-mode=subagent
|
|
165
166
|
|
|
166
167
|
# Solo 陣型
|
|
167
|
-
node .formation/tools/
|
|
168
|
-
|
|
169
|
-
# Squad 陣型
|
|
170
|
-
node .formation/tools/headless.js --formation=squad --skill=blitz --task=TASK_XXX
|
|
171
|
-
|
|
172
|
-
# Legion 陣型
|
|
173
|
-
node .formation/tools/headless.js --formation=legion --skill=forge --task=TASK_XXX
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
**並行模式**:
|
|
177
|
-
|
|
178
|
-
```javascript
|
|
179
|
-
// 單任務(單一 Bash)
|
|
180
|
-
Bash(run_in_background: true): node headless.js --task=TASK_148
|
|
181
|
-
|
|
182
|
-
// 並行多任務(多個 Bash 同時啟動)
|
|
183
|
-
Bash(run_in_background: true): node headless.js --task=TASK_148
|
|
184
|
-
Bash(run_in_background: true): node headless.js --task=TASK_149
|
|
185
|
-
Bash(run_in_background: true): node headless.js --task=TASK_150
|
|
186
|
-
|
|
187
|
-
// 有依賴(順序執行)
|
|
188
|
-
Bash: node headless.js --task=TASK_147
|
|
189
|
-
// 等待完成後
|
|
190
|
-
Bash: node headless.js --task=TASK_148
|
|
168
|
+
node .formation/tools/dispatch.js --formation=solo --skill=strategy --task=TASK_XXX --dispatch-mode=subagent
|
|
191
169
|
```
|
|
192
170
|
|
|
193
171
|
**關鍵規則**:
|
|
194
172
|
- ✅ 所有調度必須經過 `.collaboration` 任務系統
|
|
195
|
-
- ✅ 流程:create →
|
|
196
|
-
- ✅
|
|
173
|
+
- ✅ 流程:create → dispatch.js(subagent) → Agent tool → complete
|
|
174
|
+
- ✅ 有依賴 → 前一個完成再 dispatch 下一個;同一 project 序列化
|
|
197
175
|
- ❌ 不跳過任務系統直接 dispatch
|
|
198
|
-
- ❌
|
|
176
|
+
- ❌ 不手寫 subagent prompt — 用 dispatch.js 組裝(prompt 組裝、principles 注入)
|
|
199
177
|
|
|
200
178
|
### 3. Scope 安全保證
|
|
201
179
|
|
|
@@ -254,7 +232,7 @@ rigor: "medium" # low | medium | high
|
|
|
254
232
|
dependencies: ["TASK_147"] # 真依賴(B 的輸入 = A 的輸出)
|
|
255
233
|
scope_paths: # 修改的檔案/目錄(用於衝突檢測)
|
|
256
234
|
- "CLAUDE.md"
|
|
257
|
-
- ".formation/tools/
|
|
235
|
+
- ".formation/tools/dispatch.js"
|
|
258
236
|
requirements:
|
|
259
237
|
- "新增 Lead Agent 開發流程章節"
|
|
260
238
|
- "引用 .rule/pipeline/task-execution.yaml"
|
|
@@ -402,9 +380,8 @@ Step 2: 展示 Banner
|
|
|
402
380
|
└── Ansuz.md # 斜線指令觸發點
|
|
403
381
|
|
|
404
382
|
.formation/tools/
|
|
405
|
-
├──
|
|
383
|
+
├── dispatch.js # Formation 調度核心(subagent)
|
|
406
384
|
├── prompt.js # Prompt 組裝 + principles 注入
|
|
407
|
-
├── runner.js # 執行引擎
|
|
408
385
|
├── post-complete.js # 任務完成後自動化
|
|
409
386
|
└── logger.js # 日誌系統
|
|
410
387
|
|
|
@@ -439,11 +416,9 @@ Phase 3: 建立任務
|
|
|
439
416
|
- node task-api.js create ... (x3 任務)
|
|
440
417
|
|
|
441
418
|
Phase 4: 陣型判斷 + Dispatch
|
|
442
|
-
- 判斷:3
|
|
419
|
+
- 判斷:3 個任務 → 各自 unit/do,序列化 dispatch
|
|
443
420
|
- Dispatch:
|
|
444
|
-
|
|
445
|
-
Bash(bg): node headless.js --formation=squad --skill=blitz --task=TASK_152
|
|
446
|
-
Bash(bg): node headless.js --formation=squad --skill=blitz --task=TASK_153
|
|
421
|
+
node dispatch.js --skill=do --task=TASK_151 --dispatch-mode=subagent(完成後再下一個)
|
|
447
422
|
|
|
448
423
|
Phase 5: 結果處理
|
|
449
424
|
- 驗證:檔案變更 + Git commit + 驗收標準
|
|
@@ -531,7 +506,7 @@ Phase 7: 回報
|
|
|
531
506
|
```yaml
|
|
532
507
|
無衝突(可並行):
|
|
533
508
|
TASK_A: scope_paths: ["CLAUDE.md"]
|
|
534
|
-
TASK_B: scope_paths: [".formation/tools/
|
|
509
|
+
TASK_B: scope_paths: [".formation/tools/dispatch.js"]
|
|
535
510
|
|
|
536
511
|
有衝突(必須順序執行):
|
|
537
512
|
TASK_A: scope_paths: [".rule/pipeline/"]
|
|
@@ -601,7 +576,7 @@ Phase 7: 回報
|
|
|
601
576
|
| 能力定義 | `.specialist/Ansuz/capability.yaml` | 需求分析、任務設計、陣型判斷等能力 |
|
|
602
577
|
| 執行模式 | `.specialist/Ansuz/workflow.yaml` | 事件驅動 7 phases 工作流程 |
|
|
603
578
|
| 共享詞彙 | `.specialist/Ansuz/knowledge.yaml` | Formation、任務系統、Agent 類型 |
|
|
604
|
-
| Formation 系統 | `.formation/tools/` |
|
|
579
|
+
| Formation 系統 | `.formation/tools/` | dispatch.js, prompt.js, post-complete.js... |
|
|
605
580
|
| 任務系統 | `.collaboration/core/task-api.js` | 任務 API |
|
|
606
581
|
| CLAUDE.md | `CLAUDE.md` | 專案級指令與工作流程 |
|
|
607
582
|
|
|
@@ -91,24 +91,17 @@ capabilities:
|
|
|
91
91
|
# ─── 調度執行 ───
|
|
92
92
|
# §dispatch
|
|
93
93
|
dispatch:
|
|
94
|
-
description: "使用 Formation
|
|
95
|
-
tool: ".formation/tools/
|
|
96
|
-
method: "Bash tool → node
|
|
94
|
+
description: "使用 Formation prompt 組裝 + Agent tool subagent 執行任務(headless CLI 進程已退役)"
|
|
95
|
+
tool: ".formation/tools/dispatch.js"
|
|
96
|
+
method: "Bash tool → node dispatch.js --dispatch-mode=subagent → 取回 assembled prompt → Agent tool 開 subagent"
|
|
97
97
|
rules:
|
|
98
98
|
- "✅ 所有調度必須經過 .collaboration 任務系統"
|
|
99
|
-
- "✅ create →
|
|
100
|
-
- "
|
|
101
|
-
- "⚠️
|
|
102
|
-
- "⚠️ 原因:多個 agent 共用同一 git working directory,並行會 git 衝突 + agent stall"
|
|
103
|
-
- "⚠️ 有依賴鏈時:按依賴順序逐一 dispatch,等 TaskOutput/poll 確認前一個完成"
|
|
99
|
+
- "✅ create → dispatch.js(subagent) → Agent tool → complete"
|
|
100
|
+
- "⚠️ 同一 project 的 dispatch 必須序列化 — 多個 agent 共用同一 git working directory,並行會衝突"
|
|
101
|
+
- "⚠️ 有依賴鏈時:按依賴順序逐一 dispatch,確認前一個完成"
|
|
104
102
|
- "❌ 不跳過任務系統直接 dispatch"
|
|
105
|
-
- "❌ 不用 Task tool 開 subagent 繞過 Formation — Formation 有 prompt 組裝、log、principles 注入"
|
|
106
|
-
- "❌ 禁止同時 dispatch 多個 task 到同一 project(即使它們沒有依賴關係)"
|
|
107
103
|
commands:
|
|
108
|
-
unit: "node .formation/tools/
|
|
109
|
-
solo: "node .formation/tools/headless.js --formation=solo --skill=strategy --task=TASK_XXX"
|
|
110
|
-
squad: "node .formation/tools/headless.js --formation=squad --skill=blitz --task=TASK_XXX"
|
|
111
|
-
legion: "node .formation/tools/headless.js --formation=legion --skill=forge --task=TASK_XXX"
|
|
104
|
+
unit: "node .formation/tools/dispatch.js --skill=do --task=TASK_XXX --dispatch-mode=subagent"
|
|
112
105
|
|
|
113
106
|
# ─── 結果追蹤 ───
|
|
114
107
|
# §result_tracking
|
|
@@ -9,20 +9,13 @@ size_kb: 0.98
|
|
|
9
9
|
evolution_status: reference
|
|
10
10
|
---
|
|
11
11
|
formation_quick_ref:
|
|
12
|
-
principle: "
|
|
12
|
+
principle: "Only unit/solo skills are dispatchable (squad/legion retired); dispatch = Agent-tool subagent"
|
|
13
13
|
unit:
|
|
14
14
|
when: "Clear goal, single scope, direct execution"
|
|
15
|
-
command: "node .formation/tools/
|
|
15
|
+
command: "node .formation/tools/dispatch.js --skill=do --task=TASK_XXX --dispatch-mode=subagent"
|
|
16
16
|
solo:
|
|
17
17
|
when: "Multi-perspective analysis needed"
|
|
18
|
-
command: "node .formation/tools/
|
|
19
|
-
squad:
|
|
20
|
-
when: "Independent parallel subtasks possible"
|
|
21
|
-
command: "node .formation/tools/headless.js --formation=squad --skill=blitz --task=TASK_XXX"
|
|
22
|
-
legion:
|
|
23
|
-
when: "Sequential dependencies or real-time coordination required"
|
|
24
|
-
command: "node .formation/tools/headless.js --formation=legion --skill=forge --task=TASK_XXX"
|
|
18
|
+
command: "node .formation/tools/dispatch.js --formation=solo --skill=strategy --task=TASK_XXX --dispatch-mode=subagent"
|
|
25
19
|
dispatch_rules:
|
|
26
|
-
- "✅ Always background=true for parallel dispatch (Bash run_in_background=true)"
|
|
27
20
|
- "⚠️ Same project: serialize dispatches — wait for each to complete (git conflicts)"
|
|
28
|
-
- "✅ create →
|
|
21
|
+
- "✅ create → dispatch.js(subagent) → Agent tool → complete lifecycle"
|
|
@@ -54,13 +54,12 @@ mandates:
|
|
|
54
54
|
- "Project pinning: when boot banner shows a `[pin:...]` line or session was started with --project-path, EVERY MCP call to synapse_*/hippocampus_*/cortex_* that accepts a projectPath param MUST pass projectPath=<pin>; every specialist tool CLI call (task-api, phase-gate, dispatch) MUST pass --project-path <pin>. Missing projectPath leaks memory into the wrong project graph."
|
|
55
55
|
- "Verification policy (PARTIAL/UNVERIFIED/FIX-keeps-original/verified_uncommitted vs committed_unmerged vs merged): .specialist/Ansuz/VERIFY.md, loaded on demand at Phase 9."
|
|
56
56
|
- "Landing mechanics for a verified card (branch check -> Rust/node suites -> optional negative control -> merge -> task-api complete -> mark-landed -> optional backend-restart wait): run .specialist/Ansuz/tools/verify-and-land.js instead of doing the same 10-20 tool calls by hand; it only executes, judgement (what to verify, scope) stays with you."
|
|
57
|
-
- "WISHING WELL (every incarnation, TASK_1997/TASK_2040): file a wish with kenaz_wish_create — BEFORE working around the problem — whenever the Kenaz app itself blocks or degrades the work: a Kenaz tool/route fails or returns wrong data, a capability you needed is missing, a UX confusion cost you a turn, or a task ends failed/blocked because of the app. wish_type=bug|feature|question, one-line repro + what you expected, task_id when there is one. SCOPE (required on every wish): scope 'kenaz' — the Kenaz app/tools/dispatch itself blocked or degraded the work; scope 'project' — an idea or problem specific to the project being worked on (still sent; the mother may adopt it globally when it benefits Kenaz overall). FEATURE PROPOSALS: when the work reveals a capability Kenaz itself lacks that would help beyond this one task (not only blockers), you may file kenaz_wish_create with wish_type=feature, scope=kenaz. Content, in this order, within ~3000 chars: need (what you were trying to do), why current Kenaz falls short (evidence), proposed shape, who else benefits. Propose only - do not build Kenaz-core changes from a branch instance; the mother decides whether and how. MOTHER-SIDE TRIAGE: on the mother machine, field-report cards tagged needs-triage (blockers, project-scope wishes, and feature proposals alike) are judged at boot — adopt (rewrite as a global card stating the Kenaz-wide benefit, cancel the original with a pointer) or decline (cancel with a one-line reason); a feature proposal may be reshaped rather than built as proposed; never implement a project-specific ask verbatim in core. EXAMPLES — blocker: scope=kenaz, wish_type=bug, '
|
|
57
|
+
- "WISHING WELL (every incarnation, TASK_1997/TASK_2040): file a wish with kenaz_wish_create — BEFORE working around the problem — whenever the Kenaz app itself blocks or degrades the work: a Kenaz tool/route fails or returns wrong data, a capability you needed is missing, a UX confusion cost you a turn, or a task ends failed/blocked because of the app. wish_type=bug|feature|question, one-line repro + what you expected, task_id when there is one. SCOPE (required on every wish): scope 'kenaz' — the Kenaz app/tools/dispatch itself blocked or degraded the work; scope 'project' — an idea or problem specific to the project being worked on (still sent; the mother may adopt it globally when it benefits Kenaz overall). FEATURE PROPOSALS: when the work reveals a capability Kenaz itself lacks that would help beyond this one task (not only blockers), you may file kenaz_wish_create with wish_type=feature, scope=kenaz. Content, in this order, within ~3000 chars: need (what you were trying to do), why current Kenaz falls short (evidence), proposed shape, who else benefits. Propose only - do not build Kenaz-core changes from a branch instance; the mother decides whether and how. MOTHER-SIDE TRIAGE: on the mother machine, field-report cards tagged needs-triage (blockers, project-scope wishes, and feature proposals alike) are judged at boot — adopt (rewrite as a global card stating the Kenaz-wide benefit, cancel the original with a pointer) or decline (cancel with a one-line reason); a feature proposal may be reshaped rather than built as proposed; never implement a project-specific ask verbatim in core. EXAMPLES — blocker: scope=kenaz, wish_type=bug, 'dispatch.js timed out on a cross-project worktree with no partial log, TASK_2011'. feature proposal: scope=kenaz, wish_type=feature, 'need: retry one failed sub-task without rerunning the whole formation; current Kenaz only retries the full formation; shape: dispatch.js --retry-task <id>; benefits every multi-task formation'. project-specific: scope=project, wish_type=feature, 'this project needs a CSV importer for onboarding — project-specific, flagging in case it generalizes'. At session close, anything unfinished BECAUSE of the app also becomes a wish. This is the channel that feeds the mother from every branch (TASK_1994); a session that hit an app problem and filed no wish has skipped a mandate, not saved time. Boot banner shows the open-wish count (and needs-triage count when >0) so you can see the channel is live."
|
|
58
58
|
dispatch_routing:
|
|
59
59
|
paths:
|
|
60
60
|
subagent: "Agent tool within interactive session — stays on subscription billing, results return directly, no log polling. Use: short/medium tasks (rigor:low/medium, same-project or trivial scope)."
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
mandate: "ALWAYS evaluate both paths before dispatching. Check .kenaz/dashboard-models.json dispatchMode for the user override (set from the Dashboard Model Selection panel > Dispatch Routing, persisted by dashboard_settings.rs since TASK_1814): 'formation' or 'subagent' = hard override, route ALL dispatches through that path; 'auto' = no forced route, apply the heuristic (subagent when within interactive session unless task requires cross-project cwd or is rigor:high, else formation); key missing = dispatch.js falls back to 'formation' (TASK_1813 contract) — treat missing the same as no override and apply the heuristic at the Ansuz level."
|
|
61
|
+
how: "Run `node .formation/tools/dispatch.js --skill=do --task=TASK_XXX --dispatch-mode=subagent` (include the project pin when present). Read the assembled prompt from top-level promptText and pass it as the Agent tool prompt alongside agentParams. Top-level isolation is orchestration metadata, NOT an Agent tool argument: cross-project worktreePath specifies the target cwd; serialLock specifies required serialization and release. agentParams.isolation is present only for the native same-project worktree route. agentParams.model is ALREADY translated to the Agent tool enum (sonnet|opus|haiku|fable, TASK_1815) — pass it verbatim to a compatible Agent tool, do NOT re-translate or improvise. LIMIT: the Agent tool expresses family names ONLY, so dashboard version/speed picks (claude-opus-5[1m] vs claude-opus-4-8[1m], [1m] modifiers) all degrade to the family name; the payload's modelTranslation {requested, agentToolModel, granularityLoss} shows exactly what was lost. Unmappable dispatchModel values make dispatch.js exit 1 loudly; never substitute a model silently."
|
|
62
|
+
mandate: "Subagent is the only dispatch path (Formation headless/kenaz_dispatch retired, TASK_2359/2401/2402). dispatchMode in .kenaz/dashboard-models.json no longer selects a route."
|
|
64
63
|
exo_cortex:
|
|
65
64
|
opening_move: synapse_recall + kenaz_lsp_callers
|
|
66
65
|
anti_pattern: "Bash grep/rg/find for source archaeology — prefer Grep/Glob (and kenaz_lsp_symbols for symbols); the hook nudge is downstream of you knowing the tool exists"
|
|
@@ -339,7 +339,7 @@ cross_model:
|
|
|
339
339
|
- "ME-001 governance (immutable rules cannot be deleted) must hold"
|
|
340
340
|
- "AskUserQuestion tool must be available and used for all user-response questions"
|
|
341
341
|
- "Phase sequence 0-11 must be respected; phase-gate.js must be callable"
|
|
342
|
-
- "
|
|
342
|
+
- "Subagent dispatch must work (.formation/tools/dispatch.js --dispatch-mode=subagent must be callable)"
|
|
343
343
|
- "Task-api.js must be callable for task lifecycle management"
|
|
344
344
|
|
|
345
345
|
acceptable_substrate_drift:
|
|
@@ -34,9 +34,8 @@ formation:
|
|
|
34
34
|
- "Squad ≠ 開會。Squad = 多個獨立 subagent 並行,零溝通"
|
|
35
35
|
- "Legion ≠ 大號 Squad。Legion = 持久化團隊,成員間即時通訊"
|
|
36
36
|
key_files:
|
|
37
|
-
|
|
37
|
+
dispatch: ".formation/tools/dispatch.js"
|
|
38
38
|
prompt: ".formation/tools/prompt.js"
|
|
39
|
-
runner: ".formation/tools/runner.js"
|
|
40
39
|
logs: ".formation/logs/{formation}/"
|
|
41
40
|
post_complete: ".formation/tools/post-complete.js"
|
|
42
41
|
research_notes:
|
|
@@ -49,12 +48,10 @@ formation:
|
|
|
49
48
|
- "Better mapping: represent agent-role reliability and coordination cost as factorised hidden states, then evaluate a whole formation against task context."
|
|
50
49
|
- "Keep a collective dispatch objective separate from per-agent or per-symbol EFE because ensemble-level EFE is not guaranteed to be aggregate-optimal."
|
|
51
50
|
dispatch_mechanism:
|
|
52
|
-
how: "Bash tool → node
|
|
53
|
-
why: "
|
|
54
|
-
anti_pattern: "❌
|
|
55
|
-
|
|
56
|
-
max_parallel: 5 # 同時最多 5 個 headless 進程,超過排隊等空位
|
|
57
|
-
monitoring: "讀 .formation/logs/{formation}/ 下的 log 確認結果"
|
|
51
|
+
how: "Bash tool → node dispatch.js --dispatch-mode=subagent → Agent tool subagent"
|
|
52
|
+
why: "dispatch.js 統一處理 prompt 組裝(prompt.js)、principles 注入"
|
|
53
|
+
anti_pattern: "❌ 不手寫 subagent prompt — 用 dispatch.js 組裝"
|
|
54
|
+
monitoring: "Agent tool 結果直接返回"
|
|
58
55
|
|
|
59
56
|
# ═══════════════════════════════════════
|
|
60
57
|
# 任務系統
|
|
@@ -89,10 +86,10 @@ task_system:
|
|
|
89
86
|
project_yaml: ".kenaz/project.yaml"
|
|
90
87
|
rule: |
|
|
91
88
|
子專案的任務存在 .kenaz/tasks/,不是 .collaboration/tasks/。
|
|
92
|
-
所有 task-api.js、
|
|
89
|
+
所有 task-api.js、dispatch.js、post-complete.js 呼叫都必須加 --project-path。
|
|
93
90
|
cli_pattern:
|
|
94
91
|
task_api: "node {CORE}/.collaboration/core/task-api.js --project-path {PROJECT_PATH} <command>"
|
|
95
|
-
|
|
92
|
+
dispatch: "node {CORE}/.formation/tools/dispatch.js --project-path {PROJECT_PATH} --skill=do --task=TASK_XXX --dispatch-mode=subagent"
|
|
96
93
|
post_complete: "node {CORE}/.formation/tools/post-complete.js --task=TASK_XXX --project-path={PROJECT_PATH}"
|
|
97
94
|
|
|
98
95
|
# ═══════════════════════════════════════
|
|
@@ -35,7 +35,7 @@ allow:
|
|
|
35
35
|
- "讀取專案內所有原始碼"
|
|
36
36
|
- "讀寫 specialist/Ansuz/ 下所有檔案"
|
|
37
37
|
- "使用 .collaboration/core/task-api.js 管理任務"
|
|
38
|
-
- "使用 .formation/tools/
|
|
38
|
+
- "使用 .formation/tools/dispatch.js --dispatch-mode=subagent 調度執行"
|
|
39
39
|
- "使用 .formation/tools/post-complete.js 完成後自動化"
|
|
40
40
|
- "執行 git 操作(建立分支、commit、merge 到用戶分支)"
|
|
41
41
|
|
|
@@ -51,7 +51,7 @@ identity:
|
|
|
51
51
|
symbol: "ᚨ — 神諭符文:理解意圖,傳遞給執行層"
|
|
52
52
|
rules:
|
|
53
53
|
- "❌ 不 invoke 其他 Skill — 不切換身份"
|
|
54
|
-
- "✅ 需要執行時 → 用
|
|
54
|
+
- "✅ 需要執行時 → 用 Agent tool subagent dispatch(dispatch.js --dispatch-mode=subagent)"
|
|
55
55
|
- "✅ Ansuz 本體負責:需求理解、任務設計、陣型判斷、調度、追蹤、回報"
|
|
56
56
|
- "❌ 不親自寫程式碼 — 只做決策和調度"
|
|
57
57
|
- "✅ Task-First — 預設先建立任務卡再 dispatch,除非是極簡單的單檔修改(< 20 行)"
|