tycono 0.1.94-beta.0 → 0.1.94-beta.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/package.json +1 -1
- package/src/api/src/engine/agent-loop.ts +149 -142
- package/src/api/src/engine/context-assembler.ts +141 -66
- package/src/api/src/engine/org-tree.ts +1 -1
- package/src/api/src/engine/role-lifecycle.ts +1 -1
- package/src/api/src/engine/tools/definitions.ts +7 -4
- package/src/api/src/engine/tools/executor.ts +37 -3
- package/src/api/src/routes/execute.ts +139 -4
- package/src/api/src/routes/operations.ts +1 -1
- package/src/api/src/services/company-config.ts +3 -0
- package/src/api/src/services/digest-engine.ts +2 -2
- package/src/api/src/services/execution-manager.ts +82 -4
- package/src/api/src/services/scaffold.ts +24 -6
- package/src/api/src/services/supervisor-heartbeat.ts +378 -0
- package/src/api/src/services/wave-multiplexer.ts +11 -3
- package/src/shared/types.ts +3 -2
- package/src/web/dist/assets/{index-Cs1ZyjC9.js → index-C69_ijxi.js} +9 -9
- package/src/web/dist/assets/{index-BMTSnwP3.js → index-Dui2gg0N.js} +1 -1
- package/src/web/dist/assets/{preview-app-DgScvta-.js → preview-app-ClsM1ZiD.js} +1 -1
- package/src/web/dist/index.html +1 -1
- package/templates/teams/agency.json +31 -7
- package/templates/teams/research.json +32 -8
- package/templates/teams/startup.json +31 -7
package/package.json
CHANGED
|
@@ -172,7 +172,12 @@ export async function runAgentLoop(config: AgentConfig): Promise<AgentResult> {
|
|
|
172
172
|
const hasBash = !readOnly && !!config.codeRoot;
|
|
173
173
|
const node = orgTree.nodes.get(roleId);
|
|
174
174
|
const heartbeatEnabled = node?.heartbeat?.enabled === true && subordinates.length > 0;
|
|
175
|
-
|
|
175
|
+
// Peers = other roles with the same reportsTo (same parent in org tree)
|
|
176
|
+
const parentId = node?.reportsTo;
|
|
177
|
+
const hasPeers = parentId
|
|
178
|
+
? (getSubordinates(orgTree, parentId).filter(id => id !== roleId).length > 0)
|
|
179
|
+
: false;
|
|
180
|
+
const tools = getToolsForRole(subordinates.length > 0, readOnly, hasBash, heartbeatEnabled, hasPeers);
|
|
176
181
|
|
|
177
182
|
// 3. Set up tool executor
|
|
178
183
|
const toolExecOptions: ToolExecutorOptions = {
|
|
@@ -550,163 +555,63 @@ export async function runAgentLoop(config: AgentConfig): Promise<AgentResult> {
|
|
|
550
555
|
}
|
|
551
556
|
}
|
|
552
557
|
|
|
553
|
-
//
|
|
554
|
-
const
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
['write', 'edit', 'bash'].includes(tc.name.toLowerCase()),
|
|
558
|
-
);
|
|
558
|
+
// Detect file changes once — used by Phase B and Post-K
|
|
559
|
+
const hasFileChanges = allToolCalls.some((tc) =>
|
|
560
|
+
['write', 'edit', 'bash'].includes(tc.name.toLowerCase()),
|
|
561
|
+
);
|
|
559
562
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
if (turns < maxTurns) {
|
|
572
|
-
turns++;
|
|
573
|
-
const verifyResponse = await llm.chat(context.systemPrompt, messages, tools, abortSignal);
|
|
574
|
-
totalInput += verifyResponse.usage.inputTokens;
|
|
575
|
-
totalOutput += verifyResponse.usage.outputTokens;
|
|
576
|
-
config.tokenLedger?.record({
|
|
577
|
-
ts: new Date().toISOString(),
|
|
578
|
-
sessionId: config.sessionId,
|
|
579
|
-
roleId,
|
|
580
|
-
model: config.model ?? 'unknown',
|
|
581
|
-
inputTokens: verifyResponse.usage.inputTokens,
|
|
582
|
-
outputTokens: verifyResponse.usage.outputTokens,
|
|
583
|
-
});
|
|
563
|
+
// Phase B: Member Self-Verification — type checking + visual verification
|
|
564
|
+
// Any non-C-Level role that made file changes gets verification (no hardcoded role IDs)
|
|
565
|
+
if (!isCLevel && hasFileChanges) {
|
|
566
|
+
const verifyPrompt = [
|
|
567
|
+
'[AUTO-VERIFICATION] 작업이 완료되었습니다. 아래 검증을 수행하세요:',
|
|
568
|
+
'1. `cd src/api && npx tsc --noEmit` — 타입 에러 확인',
|
|
569
|
+
'2. `cd src/web && npx tsc --noEmit` — 프론트엔드 타입 에러 확인',
|
|
570
|
+
'3. UI/CSS 변경이 있었다면 Playwright MCP로 스크린샷을 촬영하여 시각 검증',
|
|
571
|
+
'검증 결과를 간단히 보고하세요.',
|
|
572
|
+
].join('\n');
|
|
584
573
|
|
|
585
|
-
|
|
586
|
-
for (const block of verifyResponse.content) {
|
|
587
|
-
if (block.type === 'text' && block.text) {
|
|
588
|
-
outputParts.push(block.text);
|
|
589
|
-
onText?.(block.text);
|
|
590
|
-
}
|
|
591
|
-
}
|
|
574
|
+
messages.push({ role: 'user', content: verifyPrompt });
|
|
592
575
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
}
|
|
607
|
-
messages.push({
|
|
608
|
-
role: 'user',
|
|
609
|
-
content: verifyResults.map((r) => ({
|
|
610
|
-
type: 'tool_result' as const,
|
|
611
|
-
tool_use_id: r.tool_use_id,
|
|
612
|
-
content: r.content,
|
|
613
|
-
is_error: r.is_error,
|
|
614
|
-
})) as unknown as MessageContent[],
|
|
615
|
-
});
|
|
576
|
+
if (turns < maxTurns) {
|
|
577
|
+
turns++;
|
|
578
|
+
const verifyResponse = await llm.chat(context.systemPrompt, messages, tools, abortSignal);
|
|
579
|
+
totalInput += verifyResponse.usage.inputTokens;
|
|
580
|
+
totalOutput += verifyResponse.usage.outputTokens;
|
|
581
|
+
config.tokenLedger?.record({
|
|
582
|
+
ts: new Date().toISOString(),
|
|
583
|
+
sessionId: config.sessionId,
|
|
584
|
+
roleId,
|
|
585
|
+
model: config.model ?? 'unknown',
|
|
586
|
+
inputTokens: verifyResponse.usage.inputTokens,
|
|
587
|
+
outputTokens: verifyResponse.usage.outputTokens,
|
|
588
|
+
});
|
|
616
589
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
config.tokenLedger?.record({
|
|
623
|
-
ts: new Date().toISOString(),
|
|
624
|
-
sessionId: config.sessionId,
|
|
625
|
-
roleId,
|
|
626
|
-
model: config.model ?? 'unknown',
|
|
627
|
-
inputTokens: summaryResponse.usage.inputTokens,
|
|
628
|
-
outputTokens: summaryResponse.usage.outputTokens,
|
|
629
|
-
});
|
|
630
|
-
for (const block of summaryResponse.content) {
|
|
631
|
-
if (block.type === 'text' && block.text) {
|
|
632
|
-
outputParts.push(block.text);
|
|
633
|
-
onText?.(block.text);
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
}
|
|
590
|
+
messages.push({ role: 'assistant', content: verifyResponse.content });
|
|
591
|
+
for (const block of verifyResponse.content) {
|
|
592
|
+
if (block.type === 'text' && block.text) {
|
|
593
|
+
outputParts.push(block.text);
|
|
594
|
+
onText?.(block.text);
|
|
637
595
|
}
|
|
638
|
-
|
|
639
|
-
onTurnComplete?.(turns);
|
|
640
596
|
}
|
|
641
597
|
|
|
642
|
-
//
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
'[POST-KNOWLEDGING] 구현이 완료되었습니다. The Loop 마무리를 수행하세요:',
|
|
646
|
-
'',
|
|
647
|
-
'## ④ Knowledge 업데이트 (The Loop Step 4)',
|
|
648
|
-
'다음 중 해당하는 항목을 수행하세요:',
|
|
649
|
-
'- 본인 journal 업데이트 (`roles/' + roleId + '/journal/YYYY-MM-DD.md` — 오늘 날짜 파일)',
|
|
650
|
-
'- 구현 중 새로 발견한 패턴/아키텍처 결정이 있다면 관련 문서 업데이트',
|
|
651
|
-
' (예: architecture/web-app-ia.md, architecture/session-worktree-isolation.md 등)',
|
|
652
|
-
'- 중요한 기술 결정은 operations/decisions/ 또는 architecture/ 반영',
|
|
653
|
-
'',
|
|
654
|
-
'## ⑤ Task 상태 갱신 (The Loop Step 5)',
|
|
655
|
-
'- `projects/tycono-platform/tasks.md` (또는 관련 tasks 파일)에서 완료한 태스크 상태를 DONE으로 변경',
|
|
656
|
-
'- 다음 작업이 있다면 식별하여 메모',
|
|
657
|
-
'',
|
|
658
|
-
'⛔ **필수**: ④와 ⑤를 모두 수행해야 The Loop이 완료됩니다.',
|
|
659
|
-
'이제 ④⑤를 수행하세요 (Read, Edit 도구 사용).',
|
|
660
|
-
].join('\n');
|
|
661
|
-
|
|
662
|
-
messages.push({ role: 'user', content: postKPrompt });
|
|
663
|
-
|
|
664
|
-
// Run Post-K loop (최대 2턴 — C-Level의 3턴보다 짧게)
|
|
665
|
-
const maxPostKRounds = 2;
|
|
666
|
-
for (let round = 0; round < maxPostKRounds && turns < maxTurns; round++) {
|
|
667
|
-
if (abortSignal?.aborted) break;
|
|
668
|
-
turns++;
|
|
669
|
-
|
|
670
|
-
const postKResponse = await llm.chat(context.systemPrompt, messages, tools, abortSignal);
|
|
671
|
-
totalInput += postKResponse.usage.inputTokens;
|
|
672
|
-
totalOutput += postKResponse.usage.outputTokens;
|
|
673
|
-
config.tokenLedger?.record({
|
|
674
|
-
ts: new Date().toISOString(),
|
|
675
|
-
sessionId: config.sessionId,
|
|
676
|
-
roleId,
|
|
677
|
-
model: config.model ?? 'unknown',
|
|
678
|
-
inputTokens: postKResponse.usage.inputTokens,
|
|
679
|
-
outputTokens: postKResponse.usage.outputTokens,
|
|
680
|
-
});
|
|
681
|
-
|
|
682
|
-
messages.push({ role: 'assistant', content: postKResponse.content });
|
|
683
|
-
for (const block of postKResponse.content) {
|
|
684
|
-
if (block.type === 'text' && block.text) {
|
|
685
|
-
outputParts.push(block.text);
|
|
686
|
-
onText?.(block.text);
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
// If no tool calls, Post-K is done
|
|
691
|
-
if (postKResponse.stopReason !== 'tool_use') break;
|
|
692
|
-
|
|
693
|
-
// Execute Post-K tool calls
|
|
694
|
-
const postKToolCalls = postKResponse.content.filter(
|
|
598
|
+
// Execute verification tool calls if needed
|
|
599
|
+
if (verifyResponse.stopReason === 'tool_use') {
|
|
600
|
+
const verifyToolCalls = verifyResponse.content.filter(
|
|
695
601
|
(b): b is MessageContent & { type: 'tool_use' } => b.type === 'tool_use',
|
|
696
602
|
);
|
|
697
|
-
const
|
|
698
|
-
for (const tc of
|
|
603
|
+
const verifyResults: ToolResult[] = [];
|
|
604
|
+
for (const tc of verifyToolCalls) {
|
|
699
605
|
allToolCalls.push({ name: tc.name, input: tc.input });
|
|
700
606
|
const result = await executeTool(
|
|
701
607
|
{ id: tc.id, name: tc.name, input: tc.input },
|
|
702
608
|
toolExecOptions,
|
|
703
609
|
);
|
|
704
|
-
|
|
610
|
+
verifyResults.push(result);
|
|
705
611
|
}
|
|
706
|
-
|
|
707
612
|
messages.push({
|
|
708
613
|
role: 'user',
|
|
709
|
-
content:
|
|
614
|
+
content: verifyResults.map((r) => ({
|
|
710
615
|
type: 'tool_result' as const,
|
|
711
616
|
tool_use_id: r.tool_use_id,
|
|
712
617
|
content: r.content,
|
|
@@ -714,8 +619,110 @@ export async function runAgentLoop(config: AgentConfig): Promise<AgentResult> {
|
|
|
714
619
|
})) as unknown as MessageContent[],
|
|
715
620
|
});
|
|
716
621
|
|
|
717
|
-
|
|
622
|
+
if (turns < maxTurns) {
|
|
623
|
+
turns++;
|
|
624
|
+
const summaryResponse = await llm.chat(context.systemPrompt, messages, tools, abortSignal);
|
|
625
|
+
totalInput += summaryResponse.usage.inputTokens;
|
|
626
|
+
totalOutput += summaryResponse.usage.outputTokens;
|
|
627
|
+
config.tokenLedger?.record({
|
|
628
|
+
ts: new Date().toISOString(),
|
|
629
|
+
sessionId: config.sessionId,
|
|
630
|
+
roleId,
|
|
631
|
+
model: config.model ?? 'unknown',
|
|
632
|
+
inputTokens: summaryResponse.usage.inputTokens,
|
|
633
|
+
outputTokens: summaryResponse.usage.outputTokens,
|
|
634
|
+
});
|
|
635
|
+
for (const block of summaryResponse.content) {
|
|
636
|
+
if (block.type === 'text' && block.text) {
|
|
637
|
+
outputParts.push(block.text);
|
|
638
|
+
onText?.(block.text);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
onTurnComplete?.(turns);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// ── Post-K: ④⑤ Knowledge/Task update (KP-008) ──
|
|
649
|
+
// ALL roles (C-Level and members) update journal/tasks after significant work.
|
|
650
|
+
// Runs for: members who made file changes, C-Level who dispatched work.
|
|
651
|
+
if (hasFileChanges || dispatches.length > 0) {
|
|
652
|
+
const postKPrompt = [
|
|
653
|
+
'[POST-KNOWLEDGING] 작업이 완료되었습니다. The Loop 마무리를 수행하세요:',
|
|
654
|
+
'',
|
|
655
|
+
'## ④ Knowledge 업데이트 (The Loop Step 4)',
|
|
656
|
+
'다음 중 해당하는 항목을 수행하세요:',
|
|
657
|
+
'- 본인 journal 업데이트 (`roles/' + roleId + '/journal/YYYY-MM-DD.md` — 오늘 날짜 파일)',
|
|
658
|
+
'- 구현 중 새로 발견한 패턴/아키텍처 결정이 있다면 관련 문서 업데이트',
|
|
659
|
+
' (예: architecture/web-app-ia.md, architecture/session-worktree-isolation.md 등)',
|
|
660
|
+
'- 중요한 기술 결정은 operations/decisions/ 또는 architecture/ 반영',
|
|
661
|
+
'',
|
|
662
|
+
'## ⑤ Task 상태 갱신 (The Loop Step 5)',
|
|
663
|
+
'- `projects/tycono-platform/tasks.md` (또는 관련 tasks 파일)에서 완료한 태스크 상태를 DONE으로 변경',
|
|
664
|
+
'- 다음 작업이 있다면 식별하여 메모',
|
|
665
|
+
'',
|
|
666
|
+
'⛔ **필수**: ④와 ⑤를 모두 수행해야 The Loop이 완료됩니다.',
|
|
667
|
+
'이제 ④⑤를 수행하세요 (Read, Edit 도구 사용).',
|
|
668
|
+
].join('\n');
|
|
669
|
+
|
|
670
|
+
messages.push({ role: 'user', content: postKPrompt });
|
|
671
|
+
|
|
672
|
+
// Run Post-K loop (최대 2턴)
|
|
673
|
+
const maxPostKRounds = 2;
|
|
674
|
+
for (let round = 0; round < maxPostKRounds && turns < maxTurns; round++) {
|
|
675
|
+
if (abortSignal?.aborted) break;
|
|
676
|
+
turns++;
|
|
677
|
+
|
|
678
|
+
const postKResponse = await llm.chat(context.systemPrompt, messages, tools, abortSignal);
|
|
679
|
+
totalInput += postKResponse.usage.inputTokens;
|
|
680
|
+
totalOutput += postKResponse.usage.outputTokens;
|
|
681
|
+
config.tokenLedger?.record({
|
|
682
|
+
ts: new Date().toISOString(),
|
|
683
|
+
sessionId: config.sessionId,
|
|
684
|
+
roleId,
|
|
685
|
+
model: config.model ?? 'unknown',
|
|
686
|
+
inputTokens: postKResponse.usage.inputTokens,
|
|
687
|
+
outputTokens: postKResponse.usage.outputTokens,
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
messages.push({ role: 'assistant', content: postKResponse.content });
|
|
691
|
+
for (const block of postKResponse.content) {
|
|
692
|
+
if (block.type === 'text' && block.text) {
|
|
693
|
+
outputParts.push(block.text);
|
|
694
|
+
onText?.(block.text);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// If no tool calls, Post-K is done
|
|
699
|
+
if (postKResponse.stopReason !== 'tool_use') break;
|
|
700
|
+
|
|
701
|
+
// Execute Post-K tool calls
|
|
702
|
+
const postKToolCalls = postKResponse.content.filter(
|
|
703
|
+
(b): b is MessageContent & { type: 'tool_use' } => b.type === 'tool_use',
|
|
704
|
+
);
|
|
705
|
+
const postKResults: ToolResult[] = [];
|
|
706
|
+
for (const tc of postKToolCalls) {
|
|
707
|
+
allToolCalls.push({ name: tc.name, input: tc.input });
|
|
708
|
+
const result = await executeTool(
|
|
709
|
+
{ id: tc.id, name: tc.name, input: tc.input },
|
|
710
|
+
toolExecOptions,
|
|
711
|
+
);
|
|
712
|
+
postKResults.push(result);
|
|
718
713
|
}
|
|
714
|
+
|
|
715
|
+
messages.push({
|
|
716
|
+
role: 'user',
|
|
717
|
+
content: postKResults.map((r) => ({
|
|
718
|
+
type: 'tool_result' as const,
|
|
719
|
+
tool_use_id: r.tool_use_id,
|
|
720
|
+
content: r.content,
|
|
721
|
+
is_error: r.is_error,
|
|
722
|
+
})) as unknown as MessageContent[],
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
onTurnComplete?.(turns);
|
|
719
726
|
}
|
|
720
727
|
}
|
|
721
728
|
}
|
|
@@ -138,6 +138,11 @@ Use the code repository path for all source code work (reading, writing, buildin
|
|
|
138
138
|
sections.push(buildSupervisionSection(node));
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
// Knowledge consistency management (C-Level responsibility)
|
|
142
|
+
if (node.level === 'c-level') {
|
|
143
|
+
sections.push(buildKnowledgeManagementSection(roleId));
|
|
144
|
+
}
|
|
145
|
+
|
|
141
146
|
// Dispatch 도구 안내 (하위 Role이 있는 경우)
|
|
142
147
|
if (subordinates.length > 0) {
|
|
143
148
|
sections.push(buildDispatchSection(orgTree, roleId, subordinates, options?.teamStatus));
|
|
@@ -526,36 +531,41 @@ ${subInfo}
|
|
|
526
531
|
|
|
527
532
|
## How to Dispatch
|
|
528
533
|
|
|
529
|
-
**Dispatch is async: start a job →
|
|
534
|
+
**Dispatch is async: start a job → supervise with watch → review → next task.**
|
|
530
535
|
|
|
531
536
|
\`\`\`bash
|
|
532
|
-
# Step 1: Dispatch (returns immediately with
|
|
537
|
+
# Step 1: Dispatch (returns immediately with session ID)
|
|
533
538
|
python3 "$DISPATCH_CMD" ${exampleSubId} "Task description here"
|
|
539
|
+
# → Session ID: ses-xxx
|
|
534
540
|
|
|
535
|
-
# Step 2:
|
|
536
|
-
|
|
541
|
+
# Step 2: Supervise with watch (preferred) or poll with --check
|
|
542
|
+
# Option A (preferred): Supervision watch — blocks server-side, returns digest
|
|
543
|
+
python3 "$SUPERVISION_CMD" watch ses-xxx --duration 120
|
|
544
|
+
# Option B (fallback): Poll for result
|
|
545
|
+
python3 "$DISPATCH_CMD" --check ses-xxx
|
|
537
546
|
\`\`\`
|
|
538
547
|
|
|
539
548
|
⛔ **NEVER use the Agent tool or Task tool to spawn sub-agents.** Those bypass the job tracking system. Use ONLY the dispatch command.
|
|
540
549
|
|
|
541
|
-
### The Pattern: Dispatch →
|
|
550
|
+
### The Pattern: Dispatch → Watch → Analyze → Act
|
|
542
551
|
|
|
543
552
|
\`\`\`bash
|
|
544
|
-
# 1. Dispatch
|
|
553
|
+
# 1. Dispatch tasks (save all session IDs)
|
|
545
554
|
python3 "$DISPATCH_CMD" ${exampleSubId} "Task A"
|
|
546
|
-
#
|
|
555
|
+
# → Session ID: ses-aaa
|
|
556
|
+
${subordinates.length > 1 ? `python3 "$DISPATCH_CMD" ${subordinates[1]} "Task B"\n# → Session ID: ses-bbb` : ''}
|
|
547
557
|
|
|
548
|
-
# 2.
|
|
549
|
-
python3 "$
|
|
550
|
-
#
|
|
551
|
-
# If DONE → read the result → proceed to next task
|
|
558
|
+
# 2. Enter supervision loop — watch ALL dispatched sessions
|
|
559
|
+
python3 "$SUPERVISION_CMD" watch ses-aaa${subordinates.length > 1 ? ',ses-bbb' : ''} --duration 120
|
|
560
|
+
# → Returns digest with significance score + activity summary
|
|
552
561
|
|
|
553
|
-
# 3.
|
|
554
|
-
|
|
555
|
-
python3 "$
|
|
556
|
-
#
|
|
562
|
+
# 3. Analyze digest → decide:
|
|
563
|
+
# - On track → watch again
|
|
564
|
+
# - Off track → amend: python3 "$SUPERVISION_CMD" amend ses-aaa "Fix: use adapter pattern"
|
|
565
|
+
# - Failed → abort: python3 "$SUPERVISION_CMD" abort ses-aaa --reason "wrong approach"
|
|
566
|
+
# - Need input → consult: python3 "$CONSULT_CMD" cbo "Is this direction right?"
|
|
557
567
|
|
|
558
|
-
# 4.
|
|
568
|
+
# 4. Repeat watch until ALL sessions complete
|
|
559
569
|
\`\`\`
|
|
560
570
|
|
|
561
571
|
### --check Status Values
|
|
@@ -605,44 +615,52 @@ When you receive a directive:
|
|
|
605
615
|
|
|
606
616
|
The loop:
|
|
607
617
|
\`\`\`
|
|
608
|
-
PLAN TASKS → DISPATCH →
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
618
|
+
PLAN TASKS → DISPATCH → SUPERVISION WATCH → ANALYZE DIGEST → DECIDE
|
|
619
|
+
├── On track → Watch again
|
|
620
|
+
├── Off track → Amend session
|
|
621
|
+
├── Failed → Abort + re-dispatch
|
|
622
|
+
└── ALL DONE → Update knowledge → Report
|
|
612
623
|
\`\`\`
|
|
613
624
|
|
|
614
625
|
### ⛔ CRITICAL: No Duplicate Dispatch
|
|
615
626
|
|
|
616
627
|
**NEVER dispatch the same or similar task to the same role twice.**
|
|
617
|
-
- If
|
|
628
|
+
- If watch shows sessions still running, keep watching — do NOT re-dispatch
|
|
618
629
|
- If a subordinate completed a task, accept the result — do NOT re-dispatch
|
|
619
630
|
- If the result is unsatisfactory, re-dispatch with SPECIFIC different instructions
|
|
620
|
-
- Track dispatched
|
|
631
|
+
- Track dispatched session IDs — never repeat the same task
|
|
621
632
|
- After 2 dispatches to the same role, accept the result or report to CEO
|
|
622
633
|
|
|
623
634
|
**Example: Full supervision session**
|
|
624
635
|
\`\`\`bash
|
|
625
636
|
# Task 1: Dispatch to engineer
|
|
626
637
|
python3 "$DISPATCH_CMD" engineer "Implement feature X. Read tasks.md first."
|
|
627
|
-
# →
|
|
638
|
+
# → Session ID: ses-001
|
|
639
|
+
|
|
640
|
+
# Supervision watch (blocks 120s, returns digest)
|
|
641
|
+
python3 "$SUPERVISION_CMD" watch ses-001 --duration 120
|
|
642
|
+
# → Digest: Engineer creating auth module (significance: 3, no anomalies)
|
|
643
|
+
# Judgment: On track, continue watching
|
|
628
644
|
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
#
|
|
632
|
-
python3 "$
|
|
633
|
-
|
|
645
|
+
python3 "$SUPERVISION_CMD" watch ses-001 --duration 120
|
|
646
|
+
# → Digest: Engineer importing external API directly (significance: 7, anomaly: scope_creep)
|
|
647
|
+
# Judgment: Wrong approach — amend!
|
|
648
|
+
python3 "$SUPERVISION_CMD" amend ses-001 "Use our adapter pattern, not direct API import"
|
|
649
|
+
|
|
650
|
+
python3 "$SUPERVISION_CMD" watch ses-001 --duration 120
|
|
651
|
+
# → Digest: Engineer completed (msg:done)
|
|
634
652
|
|
|
635
653
|
# Review result... looks good. Task 2 (QA):
|
|
636
654
|
python3 "$DISPATCH_CMD" qa "Test feature X that engineer just implemented."
|
|
637
|
-
# →
|
|
638
|
-
python3 "$
|
|
639
|
-
# →
|
|
655
|
+
# → Session ID: ses-002
|
|
656
|
+
python3 "$SUPERVISION_CMD" watch ses-002 --duration 120
|
|
657
|
+
# → Digest: QA found bugs (significance: 6)
|
|
640
658
|
|
|
641
659
|
# Re-dispatch with SPECIFIC fix:
|
|
642
660
|
python3 "$DISPATCH_CMD" engineer "Fix BUG: null check missing in auth.ts line 42"
|
|
643
|
-
# →
|
|
644
|
-
python3 "$
|
|
645
|
-
# →
|
|
661
|
+
# → Session ID: ses-003
|
|
662
|
+
python3 "$SUPERVISION_CMD" watch ses-003 --duration 120
|
|
663
|
+
# → DONE — all good. Update knowledge and report.
|
|
646
664
|
\`\`\`
|
|
647
665
|
|
|
648
666
|
⚠️ Do NOT use curl or other methods to create jobs — always use the dispatch command.
|
|
@@ -707,53 +725,110 @@ function buildSupervisionSection(node: OrgNode): string {
|
|
|
707
725
|
const hb = node.heartbeat ?? { enabled: true, intervalSec: 120, maxTicks: 60 };
|
|
708
726
|
return `# Supervision Mode (Heartbeat)
|
|
709
727
|
|
|
710
|
-
⛔ **
|
|
711
|
-
⛔ **
|
|
728
|
+
⛔ **After dispatching subordinates, you MUST enter supervision mode.**
|
|
729
|
+
⛔ **Use \`python3 "$SUPERVISION_CMD" watch\` — it blocks server-side at zero LLM cost and returns a digest.**
|
|
730
|
+
⛔ **Do NOT use sleep + \`--check\` polling. The supervision watch command is cheaper and gives better information.**
|
|
712
731
|
|
|
713
732
|
## Supervision Protocol
|
|
714
733
|
|
|
715
|
-
1. **Dispatch** subordinates with clear task descriptions
|
|
716
|
-
2. **
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
-
|
|
723
|
-
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
|
733
|
-
|
|
734
|
+
1. **Dispatch** subordinates with clear task descriptions. Save returned session IDs.
|
|
735
|
+
2. **Watch** with the supervision command:
|
|
736
|
+
\`\`\`bash
|
|
737
|
+
python3 "$SUPERVISION_CMD" watch <ses-id1>,<ses-id2> --duration ${hb.intervalSec}
|
|
738
|
+
\`\`\`
|
|
739
|
+
This blocks for ${hb.intervalSec}s (or until an alert event) and returns a digest summary.
|
|
740
|
+
3. **Analyze the digest** — each tick, you must think critically:
|
|
741
|
+
- ✅ **Direction check**: Are subordinates on track with the plan?
|
|
742
|
+
- ✅ **Quality check**: Is the approach correct? (e.g., right patterns, right tools)
|
|
743
|
+
- ✅ **Peer consult**: Unsure about business/market direction? → \`python3 "$CONSULT_CMD" cbo "question"\`
|
|
744
|
+
- ⚠️ **Course correct**: Wrong direction → \`python3 "$SUPERVISION_CMD" amend <ses-id> "new instruction"\`
|
|
745
|
+
- 🛑 **Abort**: Seriously wrong → \`python3 "$SUPERVISION_CMD" abort <ses-id> --reason "why"\`
|
|
746
|
+
- ✅ **All done**: Compile results and report to your superior
|
|
747
|
+
4. **Repeat** watch until all subordinates complete. Do NOT stop after one tick.
|
|
748
|
+
|
|
749
|
+
## Supervision Commands
|
|
750
|
+
|
|
751
|
+
| Command | Description |
|
|
752
|
+
|---------|-------------|
|
|
753
|
+
| \`python3 "$SUPERVISION_CMD" watch <ids> --duration ${hb.intervalSec}\` | Watch sessions (blocks ${hb.intervalSec}s, returns digest) |
|
|
754
|
+
| \`python3 "$SUPERVISION_CMD" amend <ses-id> "instruction"\` | Inject new instructions into running session |
|
|
755
|
+
| \`python3 "$SUPERVISION_CMD" abort <ses-id> --reason "why"\` | Kill a session going wrong |
|
|
756
|
+
| \`python3 "$SUPERVISION_CMD" peers --wave <waveId> --role <roleId>\` | Discover peer C-Level sessions |
|
|
757
|
+
| \`python3 "$CONSULT_CMD" <peer-role> "question"\` | Ask a peer C-Level for input |
|
|
734
758
|
|
|
735
759
|
## Digest Response
|
|
736
760
|
|
|
737
|
-
|
|
738
|
-
- **
|
|
739
|
-
- **
|
|
740
|
-
- **
|
|
741
|
-
|
|
761
|
+
The watch command returns a JSON digest with:
|
|
762
|
+
- **significanceScore** (0-10): How much attention this tick needs
|
|
763
|
+
- **anomalies**: Errors, stalls (3min+ no events), sessions awaiting input
|
|
764
|
+
- **text**: Human-readable summary of per-session activity
|
|
765
|
+
|
|
766
|
+
Score 0-1 = quiet (all normal). Score 5+ = needs attention. Score 8+ = likely needs intervention.
|
|
767
|
+
|
|
768
|
+
## Tick Quality (CRITICAL)
|
|
742
769
|
|
|
743
|
-
|
|
770
|
+
⛔ **Each tick, you must make a REAL judgment — not just "still running, continuing".**
|
|
771
|
+
|
|
772
|
+
Good tick response:
|
|
773
|
+
\`\`\`
|
|
774
|
+
Digest: Engineer working on auth module (seq 45), QA waiting.
|
|
775
|
+
Judgment: Engineer is importing external API directly — should use our adapter pattern.
|
|
776
|
+
Action: amend engineer session with instruction to use adapter.
|
|
777
|
+
\`\`\`
|
|
778
|
+
|
|
779
|
+
Bad tick response (DO NOT DO THIS):
|
|
780
|
+
\`\`\`
|
|
781
|
+
"Sessions are still running. Continuing to watch."
|
|
782
|
+
\`\`\`
|
|
744
783
|
|
|
745
784
|
## Budget
|
|
746
785
|
|
|
747
786
|
- Max ticks: ${hb.maxTicks} (${Math.round(hb.maxTicks * hb.intervalSec / 60)} minutes total)
|
|
748
|
-
- Quiet tick cost: ~$0.001
|
|
749
|
-
- Alert tick cost: ~$0.02-0.05 (intervention decision)
|
|
787
|
+
- Quiet tick cost: ~$0.001 | Alert tick cost: ~$0.02-0.05
|
|
750
788
|
|
|
751
789
|
## ⛔ Anti-Patterns
|
|
752
790
|
|
|
753
|
-
- ❌ Using \`
|
|
754
|
-
- ❌
|
|
791
|
+
- ❌ Using \`sleep\` + \`--check\` to poll — use supervision watch instead
|
|
792
|
+
- ❌ Saying "still RUNNING, continuing to wait" without real analysis
|
|
755
793
|
- ❌ Ignoring digest anomalies — always address errors and stalls
|
|
756
|
-
- ❌
|
|
794
|
+
- ❌ Stopping supervision after one tick — keep watching until ALL done
|
|
795
|
+
- ❌ Not consulting peers when business/market judgment is needed`;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
function buildKnowledgeManagementSection(roleId: string): string {
|
|
799
|
+
const domainScope = roleId === 'cto'
|
|
800
|
+
? '`architecture/`, `knowledge/` (technical docs)'
|
|
801
|
+
: roleId === 'cbo'
|
|
802
|
+
? '`knowledge/`, `company/` (business docs)'
|
|
803
|
+
: '`knowledge/` (your domain docs)';
|
|
804
|
+
|
|
805
|
+
return `# Knowledge Consistency Management (C-Level Responsibility)
|
|
806
|
+
|
|
807
|
+
⛔ **You are responsible for keeping your domain's knowledge current and consistent.**
|
|
808
|
+
|
|
809
|
+
## When to Check
|
|
810
|
+
|
|
811
|
+
- After completing any task (The Loop step ④)
|
|
812
|
+
- During supervision ticks when subordinates are progressing normally
|
|
813
|
+
- When you notice conflicting information during work
|
|
814
|
+
|
|
815
|
+
## Knowledge Gate
|
|
816
|
+
|
|
817
|
+
1. Check if changes conflict with existing documents (grep 3+ keywords)
|
|
818
|
+
2. Update or deprecate stale references — do NOT leave legacy docs pretending to be current
|
|
819
|
+
3. Verify new docs are registered in their Hub
|
|
820
|
+
4. Ensure cross-links between related documents
|
|
821
|
+
|
|
822
|
+
## AKB Linting
|
|
823
|
+
|
|
824
|
+
| Check | Description |
|
|
825
|
+
|-------|-------------|
|
|
826
|
+
| Orphan docs | Every document reachable from a Hub? |
|
|
827
|
+
| Stale content | Deprecated designs still described as current? Mark ⚠️ |
|
|
828
|
+
| Term consistency | Same concept called different names across docs? |
|
|
829
|
+
| Date freshness | Old dates/status without warning? |
|
|
830
|
+
|
|
831
|
+
**Your scope**: ${domainScope}`;
|
|
757
832
|
}
|
|
758
833
|
|
|
759
834
|
function buildConsultSection(orgTree: OrgTree, roleId: string): string | null {
|