tycono-server 0.1.0-beta.0
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/bin/cli.js +35 -0
- package/bin/server.ts +160 -0
- package/package.json +50 -0
- package/src/api/package.json +31 -0
- package/src/api/src/create-app.ts +90 -0
- package/src/api/src/create-server.ts +251 -0
- package/src/api/src/engine/agent-loop.ts +738 -0
- package/src/api/src/engine/authority-validator.ts +149 -0
- package/src/api/src/engine/context-assembler.ts +912 -0
- package/src/api/src/engine/index.ts +27 -0
- package/src/api/src/engine/knowledge-gate.ts +365 -0
- package/src/api/src/engine/llm-adapter.ts +304 -0
- package/src/api/src/engine/org-tree.ts +270 -0
- package/src/api/src/engine/role-lifecycle.ts +369 -0
- package/src/api/src/engine/runners/claude-cli.ts +796 -0
- package/src/api/src/engine/runners/direct-api.ts +66 -0
- package/src/api/src/engine/runners/index.ts +30 -0
- package/src/api/src/engine/runners/types.ts +95 -0
- package/src/api/src/engine/skill-template.ts +134 -0
- package/src/api/src/engine/tools/definitions.ts +201 -0
- package/src/api/src/engine/tools/executor.ts +611 -0
- package/src/api/src/routes/active-sessions.ts +134 -0
- package/src/api/src/routes/coins.ts +153 -0
- package/src/api/src/routes/company.ts +57 -0
- package/src/api/src/routes/cost.ts +141 -0
- package/src/api/src/routes/engine.ts +220 -0
- package/src/api/src/routes/execute.ts +1075 -0
- package/src/api/src/routes/git.ts +211 -0
- package/src/api/src/routes/knowledge.ts +378 -0
- package/src/api/src/routes/operations.ts +309 -0
- package/src/api/src/routes/preferences.ts +63 -0
- package/src/api/src/routes/presets.ts +123 -0
- package/src/api/src/routes/projects.ts +82 -0
- package/src/api/src/routes/quests.ts +41 -0
- package/src/api/src/routes/roles.ts +112 -0
- package/src/api/src/routes/save.ts +152 -0
- package/src/api/src/routes/sessions.ts +288 -0
- package/src/api/src/routes/setup.ts +437 -0
- package/src/api/src/routes/skills.ts +357 -0
- package/src/api/src/routes/speech.ts +959 -0
- package/src/api/src/routes/supervision.ts +136 -0
- package/src/api/src/routes/sync.ts +165 -0
- package/src/api/src/server.ts +59 -0
- package/src/api/src/services/activity-stream.ts +184 -0
- package/src/api/src/services/activity-tracker.ts +115 -0
- package/src/api/src/services/claude-md-manager.ts +94 -0
- package/src/api/src/services/company-config.ts +115 -0
- package/src/api/src/services/database.ts +77 -0
- package/src/api/src/services/digest-engine.ts +313 -0
- package/src/api/src/services/execution-manager.ts +1036 -0
- package/src/api/src/services/file-reader.ts +77 -0
- package/src/api/src/services/git-save.ts +614 -0
- package/src/api/src/services/job-manager.ts +16 -0
- package/src/api/src/services/knowledge-importer.ts +466 -0
- package/src/api/src/services/markdown-parser.ts +173 -0
- package/src/api/src/services/port-registry.ts +222 -0
- package/src/api/src/services/preferences.ts +150 -0
- package/src/api/src/services/preset-loader.ts +149 -0
- package/src/api/src/services/pricing.ts +34 -0
- package/src/api/src/services/scaffold.ts +546 -0
- package/src/api/src/services/session-store.ts +340 -0
- package/src/api/src/services/supervisor-heartbeat.ts +897 -0
- package/src/api/src/services/team-recommender.ts +382 -0
- package/src/api/src/services/token-ledger.ts +127 -0
- package/src/api/src/services/wave-messages.ts +194 -0
- package/src/api/src/services/wave-multiplexer.ts +356 -0
- package/src/api/src/services/wave-tracker.ts +359 -0
- package/src/api/src/utils/role-level.ts +31 -0
- package/src/core/scaffolder.ts +620 -0
- package/src/shared/types.ts +224 -0
- package/templates/CLAUDE.md.tmpl +239 -0
- package/templates/company.md.tmpl +17 -0
- package/templates/gitignore.tmpl +28 -0
- package/templates/roles.md.tmpl +8 -0
- package/templates/skills/_manifest.json +23 -0
- package/templates/skills/agent-browser/SKILL.md +159 -0
- package/templates/skills/agent-browser/meta.json +19 -0
- package/templates/skills/akb-linter/SKILL.md +125 -0
- package/templates/skills/akb-linter/meta.json +12 -0
- package/templates/skills/knowledge-gate/SKILL.md +120 -0
- package/templates/skills/knowledge-gate/meta.json +12 -0
- package/templates/teams/agency.json +58 -0
- package/templates/teams/research.json +58 -0
- package/templates/teams/startup.json +58 -0
|
@@ -0,0 +1,912 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { readPreferences } from '../services/preferences.js';
|
|
4
|
+
import { readConfig, resolveCodeRoot } from '../services/company-config.js';
|
|
5
|
+
import {
|
|
6
|
+
type OrgTree,
|
|
7
|
+
type OrgNode,
|
|
8
|
+
getSubordinates,
|
|
9
|
+
getChainOfCommand,
|
|
10
|
+
formatOrgChart,
|
|
11
|
+
canConsult,
|
|
12
|
+
} from './org-tree.js';
|
|
13
|
+
import { extractKeywords, searchRelatedDocs } from './knowledge-gate.js';
|
|
14
|
+
|
|
15
|
+
/* ─── Types ──────────────────────────────────── */
|
|
16
|
+
|
|
17
|
+
export interface AssembledContext {
|
|
18
|
+
systemPrompt: string;
|
|
19
|
+
task: string;
|
|
20
|
+
sourceRole: string;
|
|
21
|
+
targetRole: string;
|
|
22
|
+
metadata: {
|
|
23
|
+
orgPath: string[];
|
|
24
|
+
knowledgeScope: string[];
|
|
25
|
+
authorityLevel: string;
|
|
26
|
+
subordinates: string[];
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* ─── Context Assembly ───────────────────────── */
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 9단계 시스템 프롬프트 조립 파이프라인
|
|
34
|
+
*
|
|
35
|
+
* 1. CLAUDE.md (전사 규칙)
|
|
36
|
+
* 2. Org Context (현재 조직도, 이 Role의 위치)
|
|
37
|
+
* 3. Role Persona
|
|
38
|
+
* 4. Authority Rules
|
|
39
|
+
* 5. Knowledge Scope
|
|
40
|
+
* 6. SKILL.md
|
|
41
|
+
* 7. Hub Docs (라우팅 테이블의 "먼저 읽기" 경로)
|
|
42
|
+
* 8. CEO Decisions (전사 공지 — Approved 결정만)
|
|
43
|
+
* 9. Task
|
|
44
|
+
*/
|
|
45
|
+
export type { TeamStatus } from '../../../shared/types.js';
|
|
46
|
+
import { type RoleStatus, type TeamStatus, isRoleActive } from '../../../shared/types.js';
|
|
47
|
+
|
|
48
|
+
export function assembleContext(
|
|
49
|
+
companyRoot: string,
|
|
50
|
+
roleId: string,
|
|
51
|
+
task: string,
|
|
52
|
+
sourceRole: string,
|
|
53
|
+
orgTree: OrgTree,
|
|
54
|
+
options?: { teamStatus?: TeamStatus; targetRoles?: string[]; presetId?: string },
|
|
55
|
+
): AssembledContext {
|
|
56
|
+
const node = orgTree.nodes.get(roleId);
|
|
57
|
+
if (!node) {
|
|
58
|
+
throw new Error(`Role not found in org tree: ${roleId}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const sections: string[] = [];
|
|
62
|
+
|
|
63
|
+
// 1. Company Rules (CLAUDE.md + custom-rules.md + company.md)
|
|
64
|
+
const companyRules = loadCompanyRules(companyRoot);
|
|
65
|
+
if (companyRules) {
|
|
66
|
+
sections.push(companyRules);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 2. Org Context
|
|
70
|
+
sections.push(buildOrgContextSection(orgTree, node));
|
|
71
|
+
|
|
72
|
+
// 3. Role Persona
|
|
73
|
+
sections.push(buildPersonaSection(node));
|
|
74
|
+
|
|
75
|
+
// 4. Authority Rules
|
|
76
|
+
sections.push(buildAuthoritySection(node));
|
|
77
|
+
|
|
78
|
+
// 5. Knowledge Scope
|
|
79
|
+
sections.push(buildKnowledgeSection(node));
|
|
80
|
+
|
|
81
|
+
// 6. SKILL.md (Role-specific + equipped shared skills)
|
|
82
|
+
const skillContent = loadSkillMd(companyRoot, roleId);
|
|
83
|
+
if (skillContent) {
|
|
84
|
+
sections.push('# Skills & Tools\n\n' + skillContent);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 6b. Shared Skills (from role.yaml skills field)
|
|
88
|
+
const sharedSkills = loadSharedSkills(companyRoot, node.skills);
|
|
89
|
+
if (sharedSkills) {
|
|
90
|
+
sections.push('# Equipped Skills\n\n' + sharedSkills);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 7. Hub Docs (요약)
|
|
94
|
+
const hubSummary = loadHubSummaries(companyRoot, node);
|
|
95
|
+
if (hubSummary) {
|
|
96
|
+
sections.push('# Reference Documents\n\n' + hubSummary);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// 8. CEO Decisions (전사 공지)
|
|
100
|
+
const ceoDecisions = loadCeoDecisions(companyRoot);
|
|
101
|
+
if (ceoDecisions) {
|
|
102
|
+
sections.push('# CEO Decisions (전사 공지)\n\n' + ceoDecisions);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 9. Code Root (코드 프로젝트 경로)
|
|
106
|
+
const codeRoot = resolveCodeRoot(companyRoot);
|
|
107
|
+
sections.push(`# Code Project
|
|
108
|
+
|
|
109
|
+
The code repository is located at: \`${codeRoot}\` (env: $TYCONO_CODE_ROOT)
|
|
110
|
+
The AKB (knowledge) directory is at: \`${companyRoot}\` (env: $TYCONO_AKB_ROOT)
|
|
111
|
+
|
|
112
|
+
Use the code repository path for all source code work (reading, writing, building, testing).
|
|
113
|
+
|
|
114
|
+
## Git Worktree Rules (CRITICAL)
|
|
115
|
+
- Your cwd is already set to the code repository. When creating worktrees, use relative paths or \`$TYCONO_CODE_ROOT\`.
|
|
116
|
+
- **NEVER run \`git worktree add\` in \`$TYCONO_AKB_ROOT\`** — the AKB directory is not a code repository.
|
|
117
|
+
- Recommended worktree path: \`$TYCONO_CODE_ROOT/.worktrees/{branch-name}\`
|
|
118
|
+
- Example: \`git worktree add .worktrees/feature-xyz -b feature/xyz\` (from cwd, which is already code repo)`);
|
|
119
|
+
|
|
120
|
+
// 10. Pre-Knowledging: 작업 관련 문서 자동 탐색
|
|
121
|
+
const preKSection = buildPreKnowledgingSection(companyRoot, task);
|
|
122
|
+
if (preKSection) {
|
|
123
|
+
sections.push(preKSection);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// 11. Preset Knowledge (wave-scoped preset docs)
|
|
127
|
+
if (options?.presetId && options.presetId !== 'default') {
|
|
128
|
+
const presetKnowledge = loadPresetKnowledge(companyRoot, options.presetId);
|
|
129
|
+
if (presetKnowledge) {
|
|
130
|
+
sections.push('# Preset Knowledge\n\n' + presetKnowledge);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Task는 별도 필드로 분리
|
|
135
|
+
let subordinates = getSubordinates(orgTree, roleId);
|
|
136
|
+
|
|
137
|
+
// Filter subordinates by targetRoles ONLY for CEO (wave dispatch scope)
|
|
138
|
+
// C-Level roles should always see their own subordinates regardless of targetRoles
|
|
139
|
+
if (options?.targetRoles && options.targetRoles.length > 0 && roleId === 'ceo') {
|
|
140
|
+
subordinates = subordinates.filter(id => options.targetRoles!.includes(id));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Supervision prompt (SV-11, SV-12: C-Level heartbeat mode)
|
|
144
|
+
const heartbeatEnabled = node.heartbeat?.enabled === true;
|
|
145
|
+
if (heartbeatEnabled && subordinates.length > 0) {
|
|
146
|
+
sections.push(buildSupervisionSection(node));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Knowledge consistency management (C-Level responsibility)
|
|
150
|
+
if (node.level === 'c-level') {
|
|
151
|
+
sections.push(buildKnowledgeManagementSection(roleId));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Dispatch 도구 안내 (하위 Role이 있는 경우)
|
|
155
|
+
if (subordinates.length > 0) {
|
|
156
|
+
sections.push(buildDispatchSection(orgTree, roleId, subordinates, options?.teamStatus));
|
|
157
|
+
} else if (node.level === 'c-level') {
|
|
158
|
+
// C-level with no subordinates — clarify authority boundaries
|
|
159
|
+
sections.push(`# Team Structure
|
|
160
|
+
|
|
161
|
+
⚠️ **You have no direct reports.** You are an individual contributor at the C-level.
|
|
162
|
+
|
|
163
|
+
- You CANNOT dispatch tasks to other roles (no subordinates)
|
|
164
|
+
- You CAN consult other roles for information (see Consult section below)
|
|
165
|
+
- You MUST do the work yourself — research, analyze, write, decide
|
|
166
|
+
- If implementation requires another role (e.g., engineering work), recommend it to CEO
|
|
167
|
+
- Make decisions within your authority autonomously — do NOT ask CEO for decisions you can make yourself`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Consult 도구 안내 (상담 가능한 Role이 있는 경우)
|
|
171
|
+
const consultSection = buildConsultSection(orgTree, roleId);
|
|
172
|
+
if (consultSection) {
|
|
173
|
+
sections.push(consultSection);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Language preference (default: English)
|
|
177
|
+
const prefs = readPreferences(companyRoot);
|
|
178
|
+
const lang = prefs.language && prefs.language !== 'auto' ? prefs.language : 'en';
|
|
179
|
+
const langNames: Record<string, string> = { en: 'English', ko: 'Korean (한국어)', ja: 'Japanese (日本語)' };
|
|
180
|
+
const langName = langNames[lang] ?? lang;
|
|
181
|
+
sections.push(`# Language (CRITICAL)
|
|
182
|
+
|
|
183
|
+
You MUST respond in **${langName}**.
|
|
184
|
+
|
|
185
|
+
This applies to ALL output without exception:
|
|
186
|
+
- Status updates, reports, and analysis
|
|
187
|
+
- Journal entries and standup notes
|
|
188
|
+
- Decision logs and knowledge documents
|
|
189
|
+
- User-facing messages and explanations
|
|
190
|
+
- Git commit messages and PR descriptions
|
|
191
|
+
|
|
192
|
+
Code (variable names, comments in code) may remain in English for readability.
|
|
193
|
+
Everything else MUST be in ${langName}.`);
|
|
194
|
+
|
|
195
|
+
// Execution behavior rules (prevents infinite exploration loops in -p mode)
|
|
196
|
+
sections.push(`# Execution Rules (CRITICAL)
|
|
197
|
+
|
|
198
|
+
## Interpreting Tasks
|
|
199
|
+
- A [CEO Wave] is a directive from the CEO. Interpret it based on your role's expertise.
|
|
200
|
+
- If the directive is vague, focus on what YOUR ROLE can contribute. Don't try to cover everything.
|
|
201
|
+
- Break ambiguous directives into concrete actions within your authority scope.
|
|
202
|
+
- If you truly cannot determine what to do, state your interpretation and proceed with it.
|
|
203
|
+
- **If you have subordinates, your FIRST action should be decomposing the task and dispatching.** Do NOT attempt implementation yourself — delegate to the appropriate team member.
|
|
204
|
+
- Review the "Available Team Members" section to understand each subordinate's capabilities before dispatching.
|
|
205
|
+
|
|
206
|
+
## Efficiency
|
|
207
|
+
- Read ONLY files directly relevant to your task. Do NOT explore the codebase broadly.
|
|
208
|
+
- If a file doesn't exist at the expected path, try at most 2 alternatives, then move on.
|
|
209
|
+
- Do NOT use \`find\` or \`ls\` to scan entire directory trees. Use the Project Structure above.
|
|
210
|
+
- Never \`sleep\` or poll in loops. If something isn't ready, report it and move on.
|
|
211
|
+
|
|
212
|
+
## When Stuck
|
|
213
|
+
- If you cannot find what you need after 3 search attempts, STOP searching immediately.
|
|
214
|
+
- Do NOT retry the same failing command or approach.
|
|
215
|
+
- Summarize what you found, what you couldn't find, and deliver your best answer with what you have.
|
|
216
|
+
|
|
217
|
+
## Output
|
|
218
|
+
- Always produce a concrete deliverable: code change, report, analysis, or clear status update.
|
|
219
|
+
- End with a brief summary of what you did and any unresolved items.
|
|
220
|
+
|
|
221
|
+
## Sub-task Efficiency (when dispatched by a superior)
|
|
222
|
+
- Focus ONLY on the assigned task — nothing else.
|
|
223
|
+
- Do NOT update journals, knowledge docs, or tasks.md — your superior handles that.
|
|
224
|
+
- Do NOT read CLAUDE.md or explore unrelated files — go straight to the target file.
|
|
225
|
+
- If tsc/tests fail, fix the specific error. Do NOT refactor surrounding code.
|
|
226
|
+
|
|
227
|
+
## Commit Rule (when you modify code files)
|
|
228
|
+
- After completing code changes, you MUST commit your work.
|
|
229
|
+
- Use a descriptive commit message: \`git commit -m "type(scope): description"\`
|
|
230
|
+
- Common types: feat, fix, refactor, test, chore
|
|
231
|
+
- This ensures your work is not lost in uncommitted changes.
|
|
232
|
+
- Do NOT push — just commit locally. Your superior or the system handles push/PR.`);
|
|
233
|
+
|
|
234
|
+
const systemPrompt = sections.join('\n\n---\n\n');
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
systemPrompt,
|
|
238
|
+
task,
|
|
239
|
+
sourceRole,
|
|
240
|
+
targetRole: roleId,
|
|
241
|
+
metadata: {
|
|
242
|
+
orgPath: getChainOfCommand(orgTree, roleId),
|
|
243
|
+
knowledgeScope: [...node.knowledge.reads, ...node.knowledge.writes],
|
|
244
|
+
authorityLevel: node.level,
|
|
245
|
+
subordinates,
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* ─── Section Builders ───────────────────────── */
|
|
251
|
+
|
|
252
|
+
function buildPreKnowledgingSection(companyRoot: string, task: string): string | null {
|
|
253
|
+
// Extract keywords from the task directive
|
|
254
|
+
const keywords = extractKeywords(task);
|
|
255
|
+
if (keywords.length < 2) return null; // Too few keywords to be meaningful
|
|
256
|
+
|
|
257
|
+
const related = searchRelatedDocs(companyRoot, keywords);
|
|
258
|
+
if (related.length === 0) return null;
|
|
259
|
+
|
|
260
|
+
const docList = related
|
|
261
|
+
.map(doc => `- \`${doc.path}\` — ${doc.preview} (relevance: ${doc.matches})`)
|
|
262
|
+
.join('\n');
|
|
263
|
+
|
|
264
|
+
return `# 📚 Pre-Knowledging: Related Documents
|
|
265
|
+
|
|
266
|
+
The following existing documents are related to this task. **Read relevant ones before starting work** to avoid duplicating knowledge or missing existing context.
|
|
267
|
+
|
|
268
|
+
${docList}
|
|
269
|
+
|
|
270
|
+
> **Knowledging Rule**: Check these documents first. If your work produces new knowledge, update existing docs or create new ones with cross-links.`;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Load knowledge docs from a preset's knowledge/ directory.
|
|
275
|
+
* Returns concatenated content (capped at 2000 chars per doc).
|
|
276
|
+
*/
|
|
277
|
+
function loadPresetKnowledge(companyRoot: string, presetId: string): string | null {
|
|
278
|
+
const knowledgeDir = path.join(companyRoot, 'knowledge', 'presets', presetId, 'knowledge');
|
|
279
|
+
if (!fs.existsSync(knowledgeDir)) return null;
|
|
280
|
+
|
|
281
|
+
const parts: string[] = [];
|
|
282
|
+
try {
|
|
283
|
+
const entries = fs.readdirSync(knowledgeDir).filter(f => f.endsWith('.md'));
|
|
284
|
+
for (const file of entries.slice(0, 10)) { // Cap at 10 docs
|
|
285
|
+
const content = fs.readFileSync(path.join(knowledgeDir, file), 'utf-8');
|
|
286
|
+
const preview = content.slice(0, 2000);
|
|
287
|
+
parts.push(`## ${file}\n\n${preview}${content.length > 2000 ? '\n\n... (truncated)' : ''}`);
|
|
288
|
+
}
|
|
289
|
+
} catch { /* ignore */ }
|
|
290
|
+
|
|
291
|
+
return parts.length > 0 ? parts.join('\n\n---\n\n') : null;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function loadCompanyRules(companyRoot: string): string | null {
|
|
295
|
+
const parts: string[] = [];
|
|
296
|
+
|
|
297
|
+
// 1. System rules (CLAUDE.md — Tycono managed)
|
|
298
|
+
const claudeMdPath = path.join(companyRoot, 'CLAUDE.md');
|
|
299
|
+
if (fs.existsSync(claudeMdPath)) {
|
|
300
|
+
parts.push(fs.readFileSync(claudeMdPath, 'utf-8'));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// 2. User custom rules (knowledge/custom-rules.md — user owned, git tracked)
|
|
304
|
+
const customPath = path.join(companyRoot, 'knowledge', 'custom-rules.md');
|
|
305
|
+
if (fs.existsSync(customPath)) {
|
|
306
|
+
const custom = fs.readFileSync(customPath, 'utf-8').trim();
|
|
307
|
+
if (custom) {
|
|
308
|
+
parts.push('---\n\n## Company Custom Rules\n\n' + custom);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// 3. Company info (knowledge/company.md — user owned)
|
|
313
|
+
const companyMdPath = path.join(companyRoot, 'knowledge', 'company.md');
|
|
314
|
+
if (fs.existsSync(companyMdPath)) {
|
|
315
|
+
const companyInfo = fs.readFileSync(companyMdPath, 'utf-8').trim();
|
|
316
|
+
if (companyInfo) {
|
|
317
|
+
parts.push('---\n\n## Company Info\n\n' + companyInfo);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return parts.length > 0 ? parts.join('\n\n') : null;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function buildOrgContextSection(orgTree: OrgTree, node: OrgNode): string {
|
|
325
|
+
const chart = formatOrgChart(orgTree, node.id);
|
|
326
|
+
const chain = getChainOfCommand(orgTree, node.id);
|
|
327
|
+
|
|
328
|
+
return `# Organization
|
|
329
|
+
|
|
330
|
+
## Org Chart
|
|
331
|
+
\`\`\`
|
|
332
|
+
${chart}
|
|
333
|
+
\`\`\`
|
|
334
|
+
|
|
335
|
+
## Your Position
|
|
336
|
+
- **Role**: ${node.name} (${node.id})
|
|
337
|
+
- **Level**: ${node.level}
|
|
338
|
+
- **Reports To**: ${node.reportsTo}
|
|
339
|
+
- **Chain of Command**: ${chain.join(' → ')}
|
|
340
|
+
- **Direct Reports**: ${node.children.length > 0 ? node.children.join(', ') : 'None'}`;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function buildPersonaSection(node: OrgNode): string {
|
|
344
|
+
return `# Persona
|
|
345
|
+
|
|
346
|
+
You are **${node.name}** of this company.
|
|
347
|
+
|
|
348
|
+
${node.persona}`;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function buildAuthoritySection(node: OrgNode): string {
|
|
352
|
+
const autoList = node.authority.autonomous.map((a) => `- ✅ ${a}`).join('\n');
|
|
353
|
+
const approvalList = node.authority.needsApproval.map((a) => `- ⚠️ ${a}`).join('\n');
|
|
354
|
+
|
|
355
|
+
return `# Authority
|
|
356
|
+
|
|
357
|
+
## Autonomous Actions (proceed without approval)
|
|
358
|
+
${autoList || '- None defined'}
|
|
359
|
+
|
|
360
|
+
## Requires Approval from ${node.reportsTo || 'CEO'}
|
|
361
|
+
${approvalList || '- None defined'}
|
|
362
|
+
|
|
363
|
+
**Important**: Actions outside your authority must be tagged with [APPROVAL_NEEDED].`;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function buildKnowledgeSection(node: OrgNode): string {
|
|
367
|
+
const reads = node.knowledge.reads.map((p) => `- \`${p}\``).join('\n');
|
|
368
|
+
const writes = node.knowledge.writes.map((p) => `- \`${p}\``).join('\n');
|
|
369
|
+
|
|
370
|
+
const hasKnowledgeWrite = node.knowledge.writes.some((p) =>
|
|
371
|
+
p === '*' || p.startsWith('knowledge') || p === 'knowledge/*'
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
return `# Knowledge Scope
|
|
375
|
+
|
|
376
|
+
## Readable Paths
|
|
377
|
+
${reads || '- None'}
|
|
378
|
+
|
|
379
|
+
## Writable Paths
|
|
380
|
+
${writes || '- None'}
|
|
381
|
+
|
|
382
|
+
Only access files within your knowledge scope. For information outside your scope, ask your manager.${hasKnowledgeWrite ? `
|
|
383
|
+
|
|
384
|
+
## Knowledge Base 문서 작성 규칙
|
|
385
|
+
|
|
386
|
+
보고서, 분석 결과, 리서치 등 **공유 가치가 있는 문서**는 반드시 \`knowledge/\` 디렉토리에 작성하세요.
|
|
387
|
+
|
|
388
|
+
\`\`\`yaml
|
|
389
|
+
---
|
|
390
|
+
title: "문서 제목"
|
|
391
|
+
akb_type: node
|
|
392
|
+
status: active
|
|
393
|
+
tags: ["tag1", "tag2"]
|
|
394
|
+
domain: tech|market|process|strategy|financial|competitor|general
|
|
395
|
+
---
|
|
396
|
+
\`\`\`
|
|
397
|
+
|
|
398
|
+
- 파일 경로: \`knowledge/{category}/{filename}.md\`
|
|
399
|
+
- 반드시 위 YAML frontmatter를 포함할 것
|
|
400
|
+
- journal/에는 일지만, knowledge/에는 공유 문서를 작성` : ''}`;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function loadSkillMd(companyRoot: string, roleId: string): string | null {
|
|
404
|
+
const skillPath = path.join(companyRoot, 'knowledge', '.claude', 'skills', roleId, 'SKILL.md');
|
|
405
|
+
if (!fs.existsSync(skillPath)) return null;
|
|
406
|
+
return fs.readFileSync(skillPath, 'utf-8');
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function loadSharedSkills(companyRoot: string, skillIds?: string[]): string | null {
|
|
410
|
+
if (!skillIds?.length) return null;
|
|
411
|
+
|
|
412
|
+
const sections: string[] = [];
|
|
413
|
+
for (const skillId of skillIds) {
|
|
414
|
+
const skillPath = path.join(companyRoot, 'knowledge', '.claude', 'skills', '_shared', skillId, 'SKILL.md');
|
|
415
|
+
if (!fs.existsSync(skillPath)) continue;
|
|
416
|
+
const content = fs.readFileSync(skillPath, 'utf-8');
|
|
417
|
+
// Extract just the key sections (skip frontmatter)
|
|
418
|
+
const body = content.replace(/^---[\s\S]*?---\n*/, '').trim();
|
|
419
|
+
sections.push(`## [Skill: ${skillId}]\n\n${body}`);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return sections.length > 0 ? sections.join('\n\n---\n\n') : null;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function loadHubSummaries(companyRoot: string, node: OrgNode): string | null {
|
|
426
|
+
const hubPaths = new Set<string>();
|
|
427
|
+
|
|
428
|
+
// Determine which hub docs to include based on knowledge scope
|
|
429
|
+
for (const readPath of node.knowledge.reads) {
|
|
430
|
+
const base = readPath.replace(/\*$/, '').replace(/\/$/, '');
|
|
431
|
+
const hubFile = path.join(companyRoot, base, `${path.basename(base)}.md`);
|
|
432
|
+
if (fs.existsSync(hubFile)) {
|
|
433
|
+
hubPaths.add(hubFile);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (hubPaths.size === 0) return null;
|
|
438
|
+
|
|
439
|
+
const summaries: string[] = [];
|
|
440
|
+
for (const hubPath of hubPaths) {
|
|
441
|
+
const content = fs.readFileSync(hubPath, 'utf-8');
|
|
442
|
+
// Extract TL;DR or first 500 chars
|
|
443
|
+
const tldr = content.match(/## TL;DR[\s\S]*?(?=\n## [^#])/);
|
|
444
|
+
const summary = tldr ? tldr[0] : content.slice(0, 500);
|
|
445
|
+
const relativePath = path.relative(companyRoot, hubPath);
|
|
446
|
+
summaries.push(`### ${relativePath}\n${summary.trim()}`);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
return summaries.join('\n\n');
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function loadCeoDecisions(companyRoot: string): string | null {
|
|
453
|
+
const decisionsDir = path.join(companyRoot, 'knowledge', 'decisions');
|
|
454
|
+
if (!fs.existsSync(decisionsDir)) return null;
|
|
455
|
+
|
|
456
|
+
const files = fs.readdirSync(decisionsDir)
|
|
457
|
+
.filter((f) => f.endsWith('.md') && f !== 'decisions.md')
|
|
458
|
+
.sort();
|
|
459
|
+
|
|
460
|
+
if (files.length === 0) return null;
|
|
461
|
+
|
|
462
|
+
const summaries: string[] = [];
|
|
463
|
+
|
|
464
|
+
for (const file of files) {
|
|
465
|
+
const content = fs.readFileSync(path.join(decisionsDir, file), 'utf-8');
|
|
466
|
+
|
|
467
|
+
// Only include Approved decisions
|
|
468
|
+
const statusMatch = content.match(/>\s*Status:\s*(.+)/i);
|
|
469
|
+
if (!statusMatch || !statusMatch[1].toLowerCase().includes('approved')) continue;
|
|
470
|
+
|
|
471
|
+
// Extract title from first heading
|
|
472
|
+
const titleMatch = content.match(/^#\s+(.+)/m);
|
|
473
|
+
const title = titleMatch ? titleMatch[1].trim() : file;
|
|
474
|
+
|
|
475
|
+
// Extract Decision section (first paragraph after ## Decision)
|
|
476
|
+
const decisionMatch = content.match(/## Decision\s*\n\n([^\n]+)/);
|
|
477
|
+
const summary = decisionMatch ? decisionMatch[1].trim() : '';
|
|
478
|
+
|
|
479
|
+
if (summary) {
|
|
480
|
+
summaries.push(`- **${title}**: ${summary}`);
|
|
481
|
+
} else {
|
|
482
|
+
// Fallback: use first 3 content lines after front matter
|
|
483
|
+
const lines = content.split('\n').filter((l) => l.trim() && !l.startsWith('>') && !l.startsWith('#'));
|
|
484
|
+
summaries.push(`- **${title}**: ${lines.slice(0, 1).join(' ').trim() || '(상세 내용은 파일 참조)'}`);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (summaries.length === 0) return null;
|
|
489
|
+
|
|
490
|
+
return `아래는 CEO가 승인한 전사 결정 사항입니다. 모든 Role은 이 결정을 인지하고 준수해야 합니다.\n\n${summaries.join('\n')}`;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
function buildDispatchSection(orgTree: OrgTree, roleId: string, subordinates: string[], teamStatus?: TeamStatus): string {
|
|
494
|
+
const node = orgTree.nodes.get(roleId);
|
|
495
|
+
const isCLevel = node?.level === 'c-level';
|
|
496
|
+
|
|
497
|
+
const subInfo = subordinates.map((id) => {
|
|
498
|
+
const sub = orgTree.nodes.get(id);
|
|
499
|
+
if (!sub) return `- ${id} — (unknown role)`;
|
|
500
|
+
|
|
501
|
+
const lines: string[] = [];
|
|
502
|
+
|
|
503
|
+
// Header: name, id, persona summary
|
|
504
|
+
const st = teamStatus?.[id];
|
|
505
|
+
const status = st?.status && isRoleActive(st.status)
|
|
506
|
+
? `🔴 Working${st.task ? ` — "${st.task.slice(0, 60)}"` : ''}`
|
|
507
|
+
: '🟢 Idle';
|
|
508
|
+
lines.push(`### ${sub.name} (\`${id}\`) — ${status}`);
|
|
509
|
+
lines.push(`> ${sub.persona.split('\n')[0]}`);
|
|
510
|
+
|
|
511
|
+
// Level & model
|
|
512
|
+
lines.push(`- **Level**: ${sub.level} | **Model**: ${sub.model ?? 'default'}`);
|
|
513
|
+
|
|
514
|
+
// Skills
|
|
515
|
+
if (sub.skills && sub.skills.length > 0) {
|
|
516
|
+
lines.push(`- **Skills**: ${sub.skills.join(', ')}`);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Authority — what they can do autonomously
|
|
520
|
+
if (sub.authority.autonomous.length > 0) {
|
|
521
|
+
lines.push(`- **Can do**: ${sub.authority.autonomous.join(', ')}`);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Knowledge scope — what they can read/write
|
|
525
|
+
if (sub.knowledge.reads.length > 0) {
|
|
526
|
+
lines.push(`- **Reads**: ${sub.knowledge.reads.join(', ')}`);
|
|
527
|
+
}
|
|
528
|
+
if (sub.knowledge.writes.length > 0) {
|
|
529
|
+
lines.push(`- **Writes**: ${sub.knowledge.writes.join(', ')}`);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Their own subordinates (for chain delegation visibility)
|
|
533
|
+
const grandchildren = orgTree.nodes.get(id)?.children ?? [];
|
|
534
|
+
if (grandchildren.length > 0) {
|
|
535
|
+
const gcNames = grandchildren.map(gc => {
|
|
536
|
+
const gcNode = orgTree.nodes.get(gc);
|
|
537
|
+
return gcNode ? `${gcNode.name} (${gc})` : gc;
|
|
538
|
+
});
|
|
539
|
+
lines.push(`- **Their reports**: ${gcNames.join(', ')}`);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
return lines.join('\n');
|
|
543
|
+
}).join('\n\n');
|
|
544
|
+
|
|
545
|
+
const exampleSubId = subordinates[0] ?? 'engineer';
|
|
546
|
+
|
|
547
|
+
let section = `# Dispatch (Team Management)
|
|
548
|
+
|
|
549
|
+
⛔ **YOU HAVE SUBORDINATES. YOU MUST USE THEM.**
|
|
550
|
+
⛔ **For ANY directive — whether it's "do X", "review Y", or even "what do you think about Z" — dispatch to your team first, THEN synthesize their input into your response.**
|
|
551
|
+
⛔ **Reading files and giving your own opinion WITHOUT dispatching is NEVER acceptable when you have a team.**
|
|
552
|
+
|
|
553
|
+
Even for opinion/analysis requests:
|
|
554
|
+
- Dispatch to relevant subordinates: "Analyze X from your perspective and report findings"
|
|
555
|
+
- Poll for results → Synthesize their input with your own analysis
|
|
556
|
+
- Your value is ORCHESTRATION, not solo work
|
|
557
|
+
|
|
558
|
+
## Available Team Members
|
|
559
|
+
${subInfo}
|
|
560
|
+
|
|
561
|
+
## How to Dispatch
|
|
562
|
+
|
|
563
|
+
**Dispatch is async: start a job → supervise with watch → review → next task.**
|
|
564
|
+
|
|
565
|
+
\`\`\`bash
|
|
566
|
+
# Step 1: Dispatch (returns immediately with session ID)
|
|
567
|
+
python3 "$DISPATCH_CMD" ${exampleSubId} "Task description here"
|
|
568
|
+
# → Session ID: ses-xxx
|
|
569
|
+
|
|
570
|
+
# Step 2: Supervise with watch (preferred) or poll with --check
|
|
571
|
+
# Option A (preferred): Supervision watch — blocks server-side, returns digest
|
|
572
|
+
python3 "$SUPERVISION_CMD" watch ses-xxx --duration 120
|
|
573
|
+
# Option B (fallback): Poll for result
|
|
574
|
+
python3 "$DISPATCH_CMD" --check ses-xxx
|
|
575
|
+
\`\`\`
|
|
576
|
+
|
|
577
|
+
⛔ **NEVER use the Agent tool or Task tool to spawn sub-agents.** Those bypass the job tracking system. Use ONLY the dispatch command.
|
|
578
|
+
|
|
579
|
+
### The Pattern: Dispatch → Watch → Analyze → Act
|
|
580
|
+
|
|
581
|
+
\`\`\`bash
|
|
582
|
+
# 1. Dispatch tasks (save all session IDs)
|
|
583
|
+
python3 "$DISPATCH_CMD" ${exampleSubId} "Task A"
|
|
584
|
+
# → Session ID: ses-aaa
|
|
585
|
+
${subordinates.length > 1 ? `python3 "$DISPATCH_CMD" ${subordinates[1]} "Task B"\n# → Session ID: ses-bbb` : ''}
|
|
586
|
+
|
|
587
|
+
# 2. Enter supervision loop — watch ALL dispatched sessions
|
|
588
|
+
python3 "$SUPERVISION_CMD" watch ses-aaa${subordinates.length > 1 ? ',ses-bbb' : ''} --duration 120
|
|
589
|
+
# → Returns digest with significance score + activity summary
|
|
590
|
+
|
|
591
|
+
# 3. Analyze digest → decide:
|
|
592
|
+
# - On track → watch again
|
|
593
|
+
# - Off track → amend: python3 "$SUPERVISION_CMD" amend ses-aaa "Fix: use adapter pattern"
|
|
594
|
+
# - Failed → abort: python3 "$SUPERVISION_CMD" abort ses-aaa --reason "wrong approach"
|
|
595
|
+
# - Need input → consult: python3 "$CONSULT_CMD" cbo "Is this direction right?"
|
|
596
|
+
|
|
597
|
+
# 4. Repeat watch until ALL sessions complete
|
|
598
|
+
\`\`\`
|
|
599
|
+
|
|
600
|
+
### --check Status Values
|
|
601
|
+
- **RUNNING** — Subordinate still working → poll again in 10-30s
|
|
602
|
+
- **DONE** — Task completed, result is printed
|
|
603
|
+
- **ERROR** — Task failed (re-dispatch with different instructions or report)
|
|
604
|
+
- **AWAITING_INPUT** — Subordinate has a question for you
|
|
605
|
+
|
|
606
|
+
### ⛔ CRITICAL Rules
|
|
607
|
+
- **NEVER re-dispatch the same task.** If --check shows RUNNING, just keep polling.
|
|
608
|
+
- **NEVER dispatch and immediately finish.** The dispatch→check→review loop must continue until ALL work is complete.
|
|
609
|
+
- **Save the job ID** from each dispatch to use with --check.`;
|
|
610
|
+
|
|
611
|
+
// C-level roles get mandatory delegation rules
|
|
612
|
+
if (isCLevel) {
|
|
613
|
+
section += `
|
|
614
|
+
|
|
615
|
+
## C-Level Delegation Protocol (MANDATORY)
|
|
616
|
+
|
|
617
|
+
⛔ **You are a MANAGER. You do NOT write code, tests, or implementation yourself.**
|
|
618
|
+
⛔ **Your job is to PLAN, DELEGATE, REVIEW, and UPDATE KNOWLEDGE.**
|
|
619
|
+
|
|
620
|
+
### Core Rule: Always Delegate Down
|
|
621
|
+
|
|
622
|
+
When you receive a directive:
|
|
623
|
+
1. **Analyze** — Break it into sub-tasks appropriate for each subordinate
|
|
624
|
+
2. **Dispatch** — Assign tasks to subordinates with clear acceptance criteria
|
|
625
|
+
3. **Monitor** — Poll for results, review quality
|
|
626
|
+
4. **Verify** — Check git status: did subordinate commit? What files changed?
|
|
627
|
+
5. **Follow up** — If output doesn't meet criteria, dispatch back with feedback
|
|
628
|
+
6. **Report** — Synthesize results with change summary (files, commits, branch)
|
|
629
|
+
|
|
630
|
+
### What You Do vs What Subordinates Do
|
|
631
|
+
|
|
632
|
+
| YOU (C-Level) | SUBORDINATES (Members) |
|
|
633
|
+
|---------------|----------------------|
|
|
634
|
+
| Plan & decompose tasks | Implement code/design/tests |
|
|
635
|
+
| Dispatch with clear specs | Execute and return results |
|
|
636
|
+
| Review output quality | Fix issues when told |
|
|
637
|
+
| Update knowledge & tasks | Update their own journals |
|
|
638
|
+
| Report to superior | Report to you |
|
|
639
|
+
|
|
640
|
+
### The Supervision Loop (CRITICAL — DO NOT SKIP)
|
|
641
|
+
|
|
642
|
+
⛔ **You MUST keep running until ALL planned tasks are dispatched, reviewed, and completed.**
|
|
643
|
+
⛔ **NEVER dispatch once and stop. That leaves work half-done.**
|
|
644
|
+
|
|
645
|
+
The loop:
|
|
646
|
+
\`\`\`
|
|
647
|
+
PLAN TASKS → DISPATCH → SUPERVISION WATCH → ANALYZE DIGEST → DECIDE
|
|
648
|
+
├── On track → Watch again
|
|
649
|
+
├── Off track → Amend session
|
|
650
|
+
├── Failed → Abort + re-dispatch
|
|
651
|
+
└── ALL DONE → Update knowledge → Report
|
|
652
|
+
\`\`\`
|
|
653
|
+
|
|
654
|
+
### ⛔ CRITICAL: No Duplicate Dispatch
|
|
655
|
+
|
|
656
|
+
**NEVER dispatch the same or similar task to the same role twice.**
|
|
657
|
+
- If watch shows sessions still running, keep watching — do NOT re-dispatch
|
|
658
|
+
- If a subordinate completed a task, accept the result — do NOT re-dispatch
|
|
659
|
+
- If the result is unsatisfactory, re-dispatch with SPECIFIC different instructions
|
|
660
|
+
- Track dispatched session IDs — never repeat the same task
|
|
661
|
+
- After 2 dispatches to the same role, accept the result or report to CEO
|
|
662
|
+
|
|
663
|
+
**Example: Full supervision session**
|
|
664
|
+
\`\`\`bash
|
|
665
|
+
# Task 1: Dispatch to engineer
|
|
666
|
+
python3 "$DISPATCH_CMD" engineer "Implement feature X. Read tasks.md first."
|
|
667
|
+
# → Session ID: ses-001
|
|
668
|
+
|
|
669
|
+
# Supervision watch (blocks 120s, returns digest)
|
|
670
|
+
python3 "$SUPERVISION_CMD" watch ses-001 --duration 120
|
|
671
|
+
# → Digest: Engineer creating auth module (significance: 3, no anomalies)
|
|
672
|
+
# Judgment: On track, continue watching
|
|
673
|
+
|
|
674
|
+
python3 "$SUPERVISION_CMD" watch ses-001 --duration 120
|
|
675
|
+
# → Digest: Engineer importing external API directly (significance: 7, anomaly: scope_creep)
|
|
676
|
+
# Judgment: Wrong approach — amend!
|
|
677
|
+
python3 "$SUPERVISION_CMD" amend ses-001 "Use our adapter pattern, not direct API import"
|
|
678
|
+
|
|
679
|
+
python3 "$SUPERVISION_CMD" watch ses-001 --duration 120
|
|
680
|
+
# → Digest: Engineer completed (msg:done)
|
|
681
|
+
|
|
682
|
+
# Review result... looks good. Task 2 (QA):
|
|
683
|
+
python3 "$DISPATCH_CMD" qa "Test feature X that engineer just implemented."
|
|
684
|
+
# → Session ID: ses-002
|
|
685
|
+
python3 "$SUPERVISION_CMD" watch ses-002 --duration 120
|
|
686
|
+
# → Digest: QA found bugs (significance: 6)
|
|
687
|
+
|
|
688
|
+
# Re-dispatch with SPECIFIC fix:
|
|
689
|
+
python3 "$DISPATCH_CMD" engineer "Fix BUG: null check missing in auth.ts line 42"
|
|
690
|
+
# → Session ID: ses-003
|
|
691
|
+
python3 "$SUPERVISION_CMD" watch ses-003 --duration 120
|
|
692
|
+
# → DONE — all good. Update knowledge and report.
|
|
693
|
+
\`\`\`
|
|
694
|
+
|
|
695
|
+
⚠️ Do NOT use curl or other methods to create jobs — always use the dispatch command.
|
|
696
|
+
|
|
697
|
+
### Dispatch Quality Requirements
|
|
698
|
+
|
|
699
|
+
Every dispatch MUST include:
|
|
700
|
+
- **Context**: What documents/files to read first (CLAUDE.md + relevant Hub + SKILL.md)
|
|
701
|
+
- **Task**: Specific deliverable with acceptance criteria
|
|
702
|
+
- **Constraints**: File paths, standards, what NOT to do
|
|
703
|
+
- **AKB instruction**: "⛔ AKB Rule: Read CLAUDE.md before starting work."
|
|
704
|
+
|
|
705
|
+
### Anti-Patterns (NEVER do these)
|
|
706
|
+
|
|
707
|
+
- ❌ **Dispatching once and stopping** — you MUST keep working until directive is complete
|
|
708
|
+
- ❌ **Dispatching and NOT polling with --check** — you must poll for results
|
|
709
|
+
- ❌ **Re-dispatching when --check shows RUNNING** — just poll again
|
|
710
|
+
- ❌ Writing code yourself instead of dispatching to engineer
|
|
711
|
+
- ❌ Dispatching without acceptance criteria
|
|
712
|
+
- ❌ Accepting output without reviewing it
|
|
713
|
+
- ❌ Forgetting to update knowledge/tasks after work completes
|
|
714
|
+
- ❌ Doing only 1 dispatch when you should chain multiple (Engineer → QA)
|
|
715
|
+
- ❌ Reporting to superior without synthesizing subordinate outputs
|
|
716
|
+
|
|
717
|
+
### Post-Dispatch Verification (CRITICAL)
|
|
718
|
+
|
|
719
|
+
After a subordinate completes a code task, you MUST verify the work is preserved:
|
|
720
|
+
|
|
721
|
+
\`\`\`bash
|
|
722
|
+
# 1. Check if subordinate committed their work
|
|
723
|
+
git log --oneline -3
|
|
724
|
+
|
|
725
|
+
# 2. If NOT committed (changes are unstaged), commit on their behalf
|
|
726
|
+
git add -A && git commit -m "feat(scope): description of subordinate's work"
|
|
727
|
+
|
|
728
|
+
# 3. Include in your report to CEO:
|
|
729
|
+
# - What files were changed
|
|
730
|
+
# - Commit hash (if committed)
|
|
731
|
+
# - Whether the changes compile (tsc --noEmit)
|
|
732
|
+
\`\`\`
|
|
733
|
+
|
|
734
|
+
⛔ **Uncommitted work = lost work.** If the subordinate didn't commit, YOU must commit before reporting.
|
|
735
|
+
Your final report MUST include a **Change Summary** with files changed and commit status.`;
|
|
736
|
+
} else {
|
|
737
|
+
section += `
|
|
738
|
+
|
|
739
|
+
## Delegation Rules (MANDATORY)
|
|
740
|
+
|
|
741
|
+
⛔ **You have subordinates — USE THEM before doing work yourself.**
|
|
742
|
+
|
|
743
|
+
- **Always dispatch first.** Break the directive into sub-tasks and assign to your team.
|
|
744
|
+
- Only do work yourself if NO subordinate can handle it (e.g., cross-cutting decisions).
|
|
745
|
+
- Include clear task description, acceptance criteria, and relevant file paths in every dispatch.
|
|
746
|
+
- After receiving results, synthesize and report back.
|
|
747
|
+
- Your output should reference subordinate findings, not just your own file reads.`;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
return section;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
function buildSupervisionSection(node: OrgNode): string {
|
|
754
|
+
const hb = node.heartbeat ?? { enabled: true, intervalSec: 120, maxTicks: 60 };
|
|
755
|
+
return `# Supervision Mode (Heartbeat)
|
|
756
|
+
|
|
757
|
+
⛔ **After dispatching subordinates, you MUST enter supervision mode.**
|
|
758
|
+
⛔ **Use \`python3 "$SUPERVISION_CMD" watch\` — it blocks server-side at zero LLM cost and returns a digest.**
|
|
759
|
+
⛔ **Do NOT use sleep + \`--check\` polling. The supervision watch command is cheaper and gives better information.**
|
|
760
|
+
|
|
761
|
+
## Supervision Protocol
|
|
762
|
+
|
|
763
|
+
1. **Dispatch** subordinates with clear task descriptions. Save returned session IDs.
|
|
764
|
+
2. **Watch** with the supervision command:
|
|
765
|
+
\`\`\`bash
|
|
766
|
+
python3 "$SUPERVISION_CMD" watch <ses-id1>,<ses-id2> --duration ${hb.intervalSec}
|
|
767
|
+
\`\`\`
|
|
768
|
+
This blocks for ${hb.intervalSec}s (or until an alert event) and returns a digest summary.
|
|
769
|
+
3. **Analyze the digest** — each tick, you must think critically:
|
|
770
|
+
- ✅ **Direction check**: Are subordinates on track with the plan?
|
|
771
|
+
- ✅ **Quality check**: Is the approach correct? (e.g., right patterns, right tools)
|
|
772
|
+
- ✅ **Peer consult**: Unsure about business/market direction? → \`python3 "$CONSULT_CMD" cbo "question"\`
|
|
773
|
+
- ⚠️ **Course correct**: Wrong direction → \`python3 "$SUPERVISION_CMD" amend <ses-id> "new instruction"\`
|
|
774
|
+
- 🛑 **Abort**: Seriously wrong → \`python3 "$SUPERVISION_CMD" abort <ses-id> --reason "why"\`
|
|
775
|
+
- ✅ **All done?** → Before reporting done, **verify deliverables** (see Quality Gate below)
|
|
776
|
+
4. **Repeat** watch until all subordinates complete. Do NOT stop after one tick.
|
|
777
|
+
5. **Quality Gate**: When subordinates report done, **run and test** the output:
|
|
778
|
+
- For web apps/games: start a local server and open in browser to verify it actually works
|
|
779
|
+
- Try the core user interactions — if basic things don't work, it's NOT done
|
|
780
|
+
- Check that required libraries/tools mentioned in the task are actually used
|
|
781
|
+
- If gaps found → re-dispatch with **specific, actionable** feedback (not "improve quality")
|
|
782
|
+
- There is NO time limit. Non-working code is worse than less code that works.
|
|
783
|
+
|
|
784
|
+
## Supervision Commands
|
|
785
|
+
|
|
786
|
+
| Command | Description |
|
|
787
|
+
|---------|-------------|
|
|
788
|
+
| \`python3 "$SUPERVISION_CMD" watch <ids> --duration ${hb.intervalSec}\` | Watch sessions (blocks ${hb.intervalSec}s, returns digest) |
|
|
789
|
+
| \`python3 "$SUPERVISION_CMD" amend <ses-id> "instruction"\` | Inject new instructions into running session |
|
|
790
|
+
| \`python3 "$SUPERVISION_CMD" abort <ses-id> --reason "why"\` | Kill a session going wrong |
|
|
791
|
+
| \`python3 "$SUPERVISION_CMD" peers --wave <waveId> --role <roleId>\` | Discover peer C-Level sessions |
|
|
792
|
+
| \`python3 "$CONSULT_CMD" <peer-role> "question"\` | Ask a peer C-Level for input |
|
|
793
|
+
|
|
794
|
+
## Digest Response
|
|
795
|
+
|
|
796
|
+
The watch command returns a JSON digest with:
|
|
797
|
+
- **significanceScore** (0-10): How much attention this tick needs
|
|
798
|
+
- **anomalies**: Errors, stalls (3min+ no events), sessions awaiting input
|
|
799
|
+
- **text**: Human-readable summary of per-session activity
|
|
800
|
+
|
|
801
|
+
Score 0-1 = quiet (all normal). Score 5+ = needs attention. Score 8+ = likely needs intervention.
|
|
802
|
+
|
|
803
|
+
## Tick Quality (CRITICAL)
|
|
804
|
+
|
|
805
|
+
⛔ **Each tick, you must make a REAL judgment — not just "still running, continuing".**
|
|
806
|
+
|
|
807
|
+
Good tick response:
|
|
808
|
+
\`\`\`
|
|
809
|
+
Digest: Engineer working on auth module (seq 45), QA waiting.
|
|
810
|
+
Judgment: Engineer is importing external API directly — should use our adapter pattern.
|
|
811
|
+
Action: amend engineer session with instruction to use adapter.
|
|
812
|
+
\`\`\`
|
|
813
|
+
|
|
814
|
+
Bad tick response (DO NOT DO THIS):
|
|
815
|
+
\`\`\`
|
|
816
|
+
"Sessions are still running. Continuing to watch."
|
|
817
|
+
\`\`\`
|
|
818
|
+
|
|
819
|
+
## Budget
|
|
820
|
+
|
|
821
|
+
- Max ticks: ${hb.maxTicks} (${Math.round(hb.maxTicks * hb.intervalSec / 60)} minutes total)
|
|
822
|
+
- Quiet tick cost: ~$0.001 | Alert tick cost: ~$0.02-0.05
|
|
823
|
+
|
|
824
|
+
## ⛔ Anti-Patterns
|
|
825
|
+
|
|
826
|
+
- ❌ Using \`sleep\` + \`--check\` to poll — use supervision watch instead
|
|
827
|
+
- ❌ Saying "still RUNNING, continuing to wait" without real analysis
|
|
828
|
+
- ❌ Ignoring digest anomalies — always address errors and stalls
|
|
829
|
+
- ❌ Stopping supervision after one tick — keep watching until ALL done
|
|
830
|
+
- ❌ Not consulting peers when business/market judgment is needed`;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
function buildKnowledgeManagementSection(roleId: string): string {
|
|
834
|
+
const domainScope = roleId === 'cto'
|
|
835
|
+
? '`architecture/`, `knowledge/` (technical docs)'
|
|
836
|
+
: roleId === 'cbo'
|
|
837
|
+
? '`knowledge/` (business docs)'
|
|
838
|
+
: '`knowledge/` (your domain docs)';
|
|
839
|
+
|
|
840
|
+
return `# Knowledge Consistency Management (C-Level Responsibility)
|
|
841
|
+
|
|
842
|
+
⛔ **You are responsible for keeping your domain's knowledge current and consistent.**
|
|
843
|
+
|
|
844
|
+
## When to Check
|
|
845
|
+
|
|
846
|
+
- After completing any task (The Loop step ④)
|
|
847
|
+
- During supervision ticks when subordinates are progressing normally
|
|
848
|
+
- When you notice conflicting information during work
|
|
849
|
+
|
|
850
|
+
## Knowledge Gate
|
|
851
|
+
|
|
852
|
+
1. Check if changes conflict with existing documents (grep 3+ keywords)
|
|
853
|
+
2. Update or deprecate stale references — do NOT leave legacy docs pretending to be current
|
|
854
|
+
3. Verify new docs are registered in their Hub
|
|
855
|
+
4. Ensure cross-links between related documents
|
|
856
|
+
|
|
857
|
+
## AKB Linting
|
|
858
|
+
|
|
859
|
+
| Check | Description |
|
|
860
|
+
|-------|-------------|
|
|
861
|
+
| Orphan docs | Every document reachable from a Hub? |
|
|
862
|
+
| Stale content | Deprecated designs still described as current? Mark ⚠️ |
|
|
863
|
+
| Term consistency | Same concept called different names across docs? |
|
|
864
|
+
| Date freshness | Old dates/status without warning? |
|
|
865
|
+
|
|
866
|
+
**Your scope**: ${domainScope}`;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
function buildConsultSection(orgTree: OrgTree, roleId: string): string | null {
|
|
870
|
+
// Build list of roles this agent can consult
|
|
871
|
+
const consultable: string[] = [];
|
|
872
|
+
for (const [id] of orgTree.nodes) {
|
|
873
|
+
if (id !== roleId && canConsult(orgTree, roleId, id)) {
|
|
874
|
+
consultable.push(id);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
if (consultable.length === 0) return null;
|
|
879
|
+
|
|
880
|
+
const roleList = consultable.map((id) => {
|
|
881
|
+
const n = orgTree.nodes.get(id);
|
|
882
|
+
if (!n) return `- \`${id}\``;
|
|
883
|
+
const firstLine = n.persona.split('\n')[0] || n.name;
|
|
884
|
+
return `- **${n.name}** (\`${id}\`): ${firstLine}`;
|
|
885
|
+
}).join('\n');
|
|
886
|
+
|
|
887
|
+
return `# Consult (Ask Colleagues)
|
|
888
|
+
|
|
889
|
+
You can ask questions to other roles using the \`consult\` tool:
|
|
890
|
+
|
|
891
|
+
${roleList}
|
|
892
|
+
|
|
893
|
+
## How to Consult
|
|
894
|
+
|
|
895
|
+
Use the \`consult\` tool:
|
|
896
|
+
\`\`\`json
|
|
897
|
+
{ "roleId": "designer", "question": "What color scheme are you using for the dashboard?" }
|
|
898
|
+
\`\`\`
|
|
899
|
+
|
|
900
|
+
The consulted role will answer your question in read-only mode and return the response to you.
|
|
901
|
+
|
|
902
|
+
## When to Use
|
|
903
|
+
- Need technical decisions or clarifications from your manager
|
|
904
|
+
- Need design/implementation details from a peer
|
|
905
|
+
- Need domain expertise from another team member
|
|
906
|
+
- Unsure about architecture or conventions — ask before guessing
|
|
907
|
+
|
|
908
|
+
## Rules
|
|
909
|
+
- The consulted role answers in **read-only mode** (no file modifications)
|
|
910
|
+
- Keep questions specific and concise for better answers
|
|
911
|
+
- Don't consult for tasks that should be dispatched (use dispatch for work assignments)`;
|
|
912
|
+
}
|