tycono 0.3.42 → 0.3.43-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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tycono",
3
- "version": "0.3.42",
3
+ "version": "0.3.43-beta.0",
4
4
  "description": "Build an AI company. Watch them work.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -185,8 +185,8 @@ export function createExpressApp(): express.Application {
185
185
  let companyName: string | null = null;
186
186
  if (initialized) {
187
187
  try {
188
- // Read company name from company/company.md (user-owned data)
189
- const companyMdPath = path.join(COMPANY_ROOT, 'company', 'company.md');
188
+ // Read company name from knowledge/company.md (user-owned data)
189
+ const companyMdPath = path.join(COMPANY_ROOT, 'knowledge', 'company.md');
190
190
  const content = fs.readFileSync(companyMdPath, 'utf-8');
191
191
  const match = content.match(/^#\s+(.+)/m);
192
192
  if (match) companyName = match[1].trim();
@@ -655,10 +655,10 @@ export async function runAgentLoop(config: AgentConfig): Promise<AgentResult> {
655
655
  '',
656
656
  '## ④ Knowledge 업데이트 (The Loop Step 4)',
657
657
  '다음 중 해당하는 항목을 수행하세요:',
658
- '- 본인 journal 업데이트 (`roles/' + roleId + '/journal/YYYY-MM-DD.md` — 오늘 날짜 파일)',
658
+ '- 본인 journal 업데이트 (`knowledge/roles/' + roleId + '/journal/YYYY-MM-DD.md` — 오늘 날짜 파일)',
659
659
  '- 구현 중 새로 발견한 패턴/아키텍처 결정이 있다면 관련 문서 업데이트',
660
- ' (예: architecture/web-app-ia.md, architecture/session-worktree-isolation.md 등)',
661
- '- 중요한 기술 결정은 operations/decisions/ 또는 architecture/ 반영',
660
+ ' (예: knowledge/architecture/web-app-ia.md, knowledge/architecture/session-worktree-isolation.md 등)',
661
+ '- 중요한 기술 결정은 knowledge/decisions/ 또는 knowledge/architecture/ 반영',
662
662
  '',
663
663
  '## ⑤ Task 상태 갱신 (The Loop Step 5)',
664
664
  '- `projects/tycono-platform/tasks.md` (또는 관련 tasks 파일)에서 완료한 태스크 상태를 DONE으로 변경',
@@ -275,7 +275,7 @@ ${docList}
275
275
  * Returns concatenated content (capped at 2000 chars per doc).
276
276
  */
277
277
  function loadPresetKnowledge(companyRoot: string, presetId: string): string | null {
278
- const knowledgeDir = path.join(companyRoot, 'company', 'presets', presetId, 'knowledge');
278
+ const knowledgeDir = path.join(companyRoot, 'knowledge', 'presets', presetId, 'knowledge');
279
279
  if (!fs.existsSync(knowledgeDir)) return null;
280
280
 
281
281
  const parts: string[] = [];
@@ -309,8 +309,8 @@ function loadCompanyRules(companyRoot: string): string | null {
309
309
  }
310
310
  }
311
311
 
312
- // 3. Company info (company/company.md — user owned)
313
- const companyMdPath = path.join(companyRoot, 'company', 'company.md');
312
+ // 3. Company info (knowledge/company.md — user owned)
313
+ const companyMdPath = path.join(companyRoot, 'knowledge', 'company.md');
314
314
  if (fs.existsSync(companyMdPath)) {
315
315
  const companyInfo = fs.readFileSync(companyMdPath, 'utf-8').trim();
316
316
  if (companyInfo) {
@@ -450,7 +450,7 @@ function loadHubSummaries(companyRoot: string, node: OrgNode): string | null {
450
450
  }
451
451
 
452
452
  function loadCeoDecisions(companyRoot: string): string | null {
453
- const decisionsDir = path.join(companyRoot, 'operations', 'decisions');
453
+ const decisionsDir = path.join(companyRoot, 'knowledge', 'decisions');
454
454
  if (!fs.existsSync(decisionsDir)) return null;
455
455
 
456
456
  const files = fs.readdirSync(decisionsDir)
@@ -834,7 +834,7 @@ function buildKnowledgeManagementSection(roleId: string): string {
834
834
  const domainScope = roleId === 'cto'
835
835
  ? '`architecture/`, `knowledge/` (technical docs)'
836
836
  : roleId === 'cbo'
837
- ? '`knowledge/`, `company/` (business docs)'
837
+ ? '`knowledge/` (business docs)'
838
838
  : '`knowledge/` (your domain docs)';
839
839
 
840
840
  return `# Knowledge Consistency Management (C-Level Responsibility)
@@ -88,7 +88,7 @@ export function extractKeywords(text: string): string[] {
88
88
  export function searchRelatedDocs(companyRoot: string, keywords: string[]): RelatedDoc[] {
89
89
  if (keywords.length === 0) return [];
90
90
 
91
- const searchDirs = ['knowledge', 'architecture', 'projects'];
91
+ const searchDirs = ['knowledge', 'knowledge/architecture', 'knowledge/projects'];
92
92
  const results: RelatedDoc[] = [];
93
93
 
94
94
  for (const dir of searchDirs) {
@@ -222,7 +222,7 @@ export function postKnowledgingCheck(
222
222
 
223
223
  // Categorize
224
224
  // We can't tell new vs modified from just file list, so check if it's a knowledge/architecture doc
225
- if (file.startsWith('knowledge/') || file.startsWith('architecture/') || file.startsWith('projects/')) {
225
+ if (file.startsWith('knowledge/') || file.startsWith('knowledge/architecture/') || file.startsWith('knowledge/projects/')) {
226
226
  modifiedDocs.push(file);
227
227
  }
228
228
 
@@ -257,7 +257,7 @@ export function postKnowledgingCheck(
257
257
 
258
258
  /** Scan for orphan docs (not registered in Hub) and broken links */
259
259
  export function detectDecay(companyRoot: string): DecayReport {
260
- const searchDirs = ['knowledge', 'architecture'];
260
+ const searchDirs = ['knowledge', 'knowledge/architecture'];
261
261
  const orphanDocs: string[] = [];
262
262
  const staleDocs: string[] = [];
263
263
  const brokenLinks: Array<{ file: string; link: string }> = [];
@@ -86,7 +86,7 @@ interface RawRoleYaml {
86
86
  /* ─── Build ──────────────────────────────────── */
87
87
 
88
88
  export function buildOrgTree(companyRoot: string, presetId?: string): OrgTree {
89
- const rolesDir = path.join(companyRoot, 'roles');
89
+ const rolesDir = path.join(companyRoot, 'knowledge', 'roles');
90
90
  const tree: OrgTree = { root: 'ceo', nodes: new Map() };
91
91
 
92
92
  // CEO is implicit (not a role.yaml file)
@@ -108,7 +108,7 @@ export function buildOrgTree(companyRoot: string, presetId?: string): OrgTree {
108
108
 
109
109
  // If preset specified, also scan preset's roles directory
110
110
  if (presetId && presetId !== 'default') {
111
- const presetRolesDir = path.join(companyRoot, 'company', 'presets', presetId, 'roles');
111
+ const presetRolesDir = path.join(companyRoot, 'knowledge', 'presets', presetId, 'roles');
112
112
  if (fs.existsSync(presetRolesDir)) roleDirs.push(presetRolesDir);
113
113
  }
114
114
 
@@ -57,7 +57,7 @@ export class RoleLifecycleManager {
57
57
  * Create a new Role: role.yaml + SKILL.md + profile.md + journal/
58
58
  */
59
59
  async createRole(def: RoleDefinition): Promise<void> {
60
- const roleDir = path.join(this.companyRoot, 'roles', def.id);
60
+ const roleDir = path.join(this.companyRoot, 'knowledge', 'roles', def.id);
61
61
  const skillDir = path.join(this.companyRoot, '.claude', 'skills', def.id);
62
62
  const journalDir = path.join(roleDir, 'journal');
63
63
 
@@ -105,7 +105,7 @@ export class RoleLifecycleManager {
105
105
  * Update an existing Role's definition
106
106
  */
107
107
  async updateRole(id: string, changes: Partial<RoleDefinition>): Promise<void> {
108
- const yamlPath = path.join(this.companyRoot, 'roles', id, 'role.yaml');
108
+ const yamlPath = path.join(this.companyRoot, 'knowledge', 'roles', id, 'role.yaml');
109
109
  if (!fs.existsSync(yamlPath)) {
110
110
  throw new Error(`Role not found: ${id}`);
111
111
  }
@@ -145,7 +145,7 @@ export class RoleLifecycleManager {
145
145
  * Remove a Role and all its files
146
146
  */
147
147
  async removeRole(id: string): Promise<void> {
148
- const roleDir = path.join(this.companyRoot, 'roles', id);
148
+ const roleDir = path.join(this.companyRoot, 'knowledge', 'roles', id);
149
149
  const skillDir = path.join(this.companyRoot, '.claude', 'skills', id);
150
150
 
151
151
  if (fs.existsSync(roleDir)) {
@@ -180,7 +180,7 @@ export class RoleLifecycleManager {
180
180
  validateRole(id: string): RoleValidationResult {
181
181
  const issues: RoleValidationResult['issues'] = [];
182
182
 
183
- const roleDir = path.join(this.companyRoot, 'roles', id);
183
+ const roleDir = path.join(this.companyRoot, 'knowledge', 'roles', id);
184
184
  const yamlPath = path.join(roleDir, 'role.yaml');
185
185
  const profilePath = path.join(roleDir, 'profile.md');
186
186
  const journalDir = path.join(roleDir, 'journal');
@@ -223,7 +223,7 @@ export class RoleLifecycleManager {
223
223
  */
224
224
  validateAll(): Map<string, RoleValidationResult> {
225
225
  const results = new Map<string, RoleValidationResult>();
226
- const rolesDir = path.join(this.companyRoot, 'roles');
226
+ const rolesDir = path.join(this.companyRoot, 'knowledge', 'roles');
227
227
 
228
228
  if (!fs.existsSync(rolesDir)) return results;
229
229
 
@@ -319,7 +319,7 @@ ${def.authority.needsApproval.map((a) => `- ${a}`).join('\n')}
319
319
  }
320
320
 
321
321
  private addToRolesHub(def: RoleDefinition): void {
322
- const hubPath = path.join(this.companyRoot, 'roles', 'roles.md');
322
+ const hubPath = path.join(this.companyRoot, 'knowledge', 'roles', 'roles.md');
323
323
  if (!fs.existsSync(hubPath)) return;
324
324
 
325
325
  const content = fs.readFileSync(hubPath, 'utf-8');
@@ -333,7 +333,7 @@ ${def.authority.needsApproval.map((a) => `- ${a}`).join('\n')}
333
333
  }
334
334
 
335
335
  private removeFromRolesHub(id: string): void {
336
- const hubPath = path.join(this.companyRoot, 'roles', 'roles.md');
336
+ const hubPath = path.join(this.companyRoot, 'knowledge', 'roles', 'roles.md');
337
337
  if (!fs.existsSync(hubPath)) return;
338
338
 
339
339
  const content = fs.readFileSync(hubPath, 'utf-8');
@@ -10,7 +10,7 @@ export const READ_TOOLS: ToolDefinition[] = [
10
10
  input_schema: {
11
11
  type: 'object',
12
12
  properties: {
13
- path: { type: 'string', description: 'File path relative to company root (e.g., "roles/cto/role.yaml")' },
13
+ path: { type: 'string', description: 'File path relative to company root (e.g., "knowledge/roles/cto/role.yaml")' },
14
14
  },
15
15
  required: ['path'],
16
16
  },
@@ -8,7 +8,7 @@ export const companyRouter = Router();
8
8
  // GET /api/company — 회사 기본 정보
9
9
  companyRouter.get('/', (_req: Request, res: Response, next: NextFunction) => {
10
10
  try {
11
- const companyContent = readFile('company/company.md');
11
+ const companyContent = readFile('knowledge/company.md');
12
12
  const kv = extractBoldKeyValues(companyContent);
13
13
 
14
14
  // blockquote에서 미션 추출
@@ -16,7 +16,7 @@ companyRouter.get('/', (_req: Request, res: Response, next: NextFunction) => {
16
16
  const mission = missionMatch ? missionMatch[1].trim() : '';
17
17
 
18
18
  // Role 목록
19
- const rolesContent = readFile('roles/roles.md');
19
+ const rolesContent = readFile('knowledge/roles/roles.md');
20
20
  const roleRows = parseMarkdownTable(rolesContent);
21
21
  const roles = roleRows
22
22
  .filter(row => (row.id ?? '').toLowerCase() !== 'ceo')
@@ -25,7 +25,7 @@ companyRouter.get('/', (_req: Request, res: Response, next: NextFunction) => {
25
25
  let name = row.role ?? row.name ?? '';
26
26
 
27
27
  // role.yaml의 name이 있으면 우선 사용 (커스텀 이름 반영)
28
- const yamlPath = `roles/${id}/role.yaml`;
28
+ const yamlPath = `knowledge/roles/${id}/role.yaml`;
29
29
  if (id && fileExists(yamlPath)) {
30
30
  try {
31
31
  const raw = YAML.parse(readFile(yamlPath)) as Record<string, unknown>;
@@ -325,7 +325,7 @@ function handleSaveWave(body: Record<string, unknown>, res: ServerResponse): voi
325
325
  );
326
326
 
327
327
  // Scan activity-streams for sessions belonging to this wave
328
- const streamsDir = path.join(COMPANY_ROOT, 'operations', 'activity-streams');
328
+ const streamsDir = path.join(COMPANY_ROOT, '.tycono', 'activity-streams');
329
329
  if (fs.existsSync(streamsDir)) {
330
330
  const waveTimestamp = waveId.replace('wave-', '');
331
331
  for (const file of fs.readdirSync(streamsDir)) {
@@ -407,7 +407,7 @@ function handleSaveWave(body: Record<string, unknown>, res: ServerResponse): voi
407
407
  rolesData.push({ roleId, roleName, sessionId: sid, status, events, childSessions });
408
408
  }
409
409
 
410
- const wavesDir = path.join(COMPANY_ROOT, 'operations', 'waves');
410
+ const wavesDir = path.join(COMPANY_ROOT, '.tycono', 'waves');
411
411
  if (!fs.existsSync(wavesDir)) {
412
412
  fs.mkdirSync(wavesDir, { recursive: true });
413
413
  }
@@ -477,7 +477,7 @@ function handleSaveWave(body: Record<string, unknown>, res: ServerResponse): voi
477
477
  } catch { /* non-critical */ }
478
478
  }
479
479
 
480
- jsonResponse(res, 200, { ok: true, path: `operations/waves/${baseName}.json` });
480
+ jsonResponse(res, 200, { ok: true, path: `.tycono/waves/${baseName}.json` });
481
481
  }
482
482
 
483
483
  /* ─── GET /api/waves/:waveId/stream ── */
@@ -11,12 +11,12 @@ export const operationsRouter = Router();
11
11
  // --- Standups ---
12
12
  operationsRouter.get('/standups', (_req: Request, res: Response, next: NextFunction) => {
13
13
  try {
14
- const files = listFiles('operations/standup');
14
+ const files = listFiles('.tycono/standup');
15
15
  const standups = files
16
16
  .filter(f => f.endsWith('.md'))
17
17
  .map(f => {
18
18
  const date = path.basename(f, '.md');
19
- const content = readFile(`operations/standup/${f}`);
19
+ const content = readFile(`.tycono/standup/${f}`);
20
20
  return { date, content };
21
21
  })
22
22
  .sort((a, b) => b.date.localeCompare(a.date));
@@ -30,7 +30,7 @@ operationsRouter.get('/standups', (_req: Request, res: Response, next: NextFunct
30
30
  operationsRouter.get('/standups/:date', (req: Request, res: Response, next: NextFunction) => {
31
31
  try {
32
32
  const { date } = req.params;
33
- const filePath = `operations/standup/${date}.md`;
33
+ const filePath = `.tycono/standup/${date}.md`;
34
34
  if (!fileExists(filePath)) {
35
35
  res.status(404).json({ error: `Standup not found: ${date}` });
36
36
  return;
@@ -45,12 +45,12 @@ operationsRouter.get('/standups/:date', (req: Request, res: Response, next: Next
45
45
  // --- Waves (JSON-only) ---
46
46
  operationsRouter.get('/waves', (_req: Request, res: Response, next: NextFunction) => {
47
47
  try {
48
- const files = listFiles('operations/waves', '*.json');
48
+ const files = listFiles('.tycono/waves', '*.json');
49
49
  const waves = files
50
50
  .map(f => {
51
51
  const id = path.basename(f, '.json');
52
52
  try {
53
- const data = JSON.parse(readFile(`operations/waves/${f}`));
53
+ const data = JSON.parse(readFile(`.tycono/waves/${f}`));
54
54
  const roles = data.roles ?? [];
55
55
  const hasRunning = roles.some((r: { status?: string }) => r.status && isMessageActive(r.status as MessageStatus));
56
56
  return {
@@ -78,7 +78,7 @@ operationsRouter.get('/waves', (_req: Request, res: Response, next: NextFunction
78
78
  operationsRouter.get('/waves/:id', (req: Request, res: Response, next: NextFunction) => {
79
79
  try {
80
80
  const { id } = req.params;
81
- const jsonPath = `operations/waves/${id}.json`;
81
+ const jsonPath = `.tycono/waves/${id}.json`;
82
82
 
83
83
  if (!fileExists(jsonPath)) {
84
84
  res.status(404).json({ error: `Wave not found: ${id}` });
@@ -96,7 +96,7 @@ operationsRouter.get('/waves/:id', (req: Request, res: Response, next: NextFunct
96
96
  operationsRouter.patch('/waves/:id', (req: Request, res: Response, next: NextFunction) => {
97
97
  try {
98
98
  const { id } = req.params;
99
- const jsonPath = `operations/waves/${id}.json`;
99
+ const jsonPath = `.tycono/waves/${id}.json`;
100
100
 
101
101
  if (!fileExists(jsonPath)) {
102
102
  res.status(404).json({ error: `Wave not found: ${id}` });
@@ -119,12 +119,12 @@ operationsRouter.patch('/waves/:id', (req: Request, res: Response, next: NextFun
119
119
  // --- Decisions ---
120
120
  operationsRouter.get('/decisions', (_req: Request, res: Response, next: NextFunction) => {
121
121
  try {
122
- const files = listFiles('operations/decisions');
122
+ const files = listFiles('knowledge/decisions');
123
123
  const decisions = files
124
124
  .filter(f => f.endsWith('.md'))
125
125
  .map(f => {
126
126
  const id = path.basename(f, '.md');
127
- const content = readFile(`operations/decisions/${f}`);
127
+ const content = readFile(`knowledge/decisions/${f}`);
128
128
  const firstLine = content.split('\n').find(l => l.startsWith('# '));
129
129
  const title = firstLine ? firstLine.replace(/^#\s+/, '') : id;
130
130
  const kv = extractBoldKeyValues(content);
@@ -146,7 +146,7 @@ operationsRouter.put('/decisions/:id', (req: Request, res: Response, next: NextF
146
146
  res.status(400).json({ error: 'content (string) is required' });
147
147
  return;
148
148
  }
149
- const filePath = `operations/decisions/${id}.md`;
149
+ const filePath = `knowledge/decisions/${id}.md`;
150
150
  const absPath = path.resolve(COMPANY_ROOT, filePath);
151
151
  // Ensure parent directory exists
152
152
  fs.mkdirSync(path.dirname(absPath), { recursive: true });
@@ -165,7 +165,7 @@ operationsRouter.put('/decisions/:id', (req: Request, res: Response, next: NextF
165
165
  operationsRouter.delete('/decisions/:id', (req: Request, res: Response, next: NextFunction) => {
166
166
  try {
167
167
  const { id } = req.params;
168
- const filePath = `operations/decisions/${id}.md`;
168
+ const filePath = `knowledge/decisions/${id}.md`;
169
169
  const absPath = path.resolve(COMPANY_ROOT, filePath);
170
170
  if (!fs.existsSync(absPath)) {
171
171
  res.status(404).json({ error: `Decision not found: ${id}` });
@@ -62,7 +62,7 @@ presetsRouter.post('/install', (req, res) => {
62
62
  }
63
63
 
64
64
  // Create preset directory and write preset.yaml
65
- const presetDir = path.join(COMPANY_ROOT, 'company', 'presets', id);
65
+ const presetDir = path.join(COMPANY_ROOT, 'knowledge', 'presets', id);
66
66
  fs.mkdirSync(presetDir, { recursive: true });
67
67
 
68
68
  // Write preset.yaml
@@ -92,7 +92,7 @@ presetsRouter.post('/install', (req, res) => {
92
92
  }
93
93
  }
94
94
 
95
- res.json({ ok: true, id, path: `company/presets/${id}` });
95
+ res.json({ ok: true, id, path: `knowledge/presets/${id}` });
96
96
  } catch (err) {
97
97
  res.status(500).json({ error: `Install failed: ${err instanceof Error ? err.message : 'unknown'}` });
98
98
  }
@@ -107,7 +107,7 @@ presetsRouter.delete('/:id', (req, res) => {
107
107
  return;
108
108
  }
109
109
 
110
- const presetDir = path.join(COMPANY_ROOT, 'company', 'presets', id);
110
+ const presetDir = path.join(COMPANY_ROOT, 'knowledge', 'presets', id);
111
111
  if (!fs.existsSync(presetDir)) {
112
112
  res.status(404).json({ error: `Preset not found: ${id}` });
113
113
  return;
@@ -7,7 +7,7 @@ export const projectsRouter = Router();
7
7
  // GET /api/projects — 프로젝트 목록
8
8
  projectsRouter.get('/', (_req: Request, res: Response, next: NextFunction) => {
9
9
  try {
10
- const content = readFile('projects/projects.md');
10
+ const content = readFile('knowledge/projects/projects.md');
11
11
  const rows = parseMarkdownTable(content);
12
12
 
13
13
  const projects = rows.map(row => {
@@ -33,7 +33,7 @@ projectsRouter.get('/:id', (req: Request, res: Response, next: NextFunction) =>
33
33
  const { id } = req.params;
34
34
 
35
35
  // 기본 정보
36
- const listContent = readFile('projects/projects.md');
36
+ const listContent = readFile('knowledge/projects/projects.md');
37
37
  const rows = parseMarkdownTable(listContent);
38
38
  const projectRow = rows.find(r => {
39
39
  const name = r.project ?? '';
@@ -56,13 +56,13 @@ projectsRouter.get('/:id', (req: Request, res: Response, next: NextFunction) =>
56
56
  };
57
57
 
58
58
  // PRD 읽기
59
- const prdPath = `projects/${id}/prd.md`;
59
+ const prdPath = `knowledge/projects/${id}/prd.md`;
60
60
  if (fileExists(prdPath)) {
61
61
  project.prd = readFile(prdPath);
62
62
  }
63
63
 
64
64
  // Tasks 읽기
65
- const tasksPath = `projects/${id}/tasks.md`;
65
+ const tasksPath = `knowledge/projects/${id}/tasks.md`;
66
66
  if (fileExists(tasksPath)) {
67
67
  const tasksContent = readFile(tasksPath);
68
68
  const taskRows = parseMarkdownTable(tasksContent);
@@ -8,7 +8,7 @@ export const rolesRouter = Router();
8
8
  // GET /api/roles — Role 목록
9
9
  rolesRouter.get('/', (_req: Request, res: Response, next: NextFunction) => {
10
10
  try {
11
- const content = readFile('roles/roles.md');
11
+ const content = readFile('knowledge/roles/roles.md');
12
12
  const rows = parseMarkdownTable(content);
13
13
 
14
14
  const roles = rows.map(row => {
@@ -16,7 +16,7 @@ rolesRouter.get('/', (_req: Request, res: Response, next: NextFunction) => {
16
16
  let name = row.role ?? row.name ?? '';
17
17
 
18
18
  // role.yaml의 name이 있으면 우선 사용 (rename 반영)
19
- const yamlPath = `roles/${id}/role.yaml`;
19
+ const yamlPath = `knowledge/roles/${id}/role.yaml`;
20
20
  if (id && fileExists(yamlPath)) {
21
21
  try {
22
22
  const raw = YAML.parse(readFile(yamlPath)) as Record<string, unknown>;
@@ -45,7 +45,7 @@ rolesRouter.get('/:id', (req: Request, res: Response, next: NextFunction) => {
45
45
  const { id } = req.params;
46
46
 
47
47
  // 기본 정보 (roles.md 테이블에서)
48
- const listContent = readFile('roles/roles.md');
48
+ const listContent = readFile('knowledge/roles/roles.md');
49
49
  const rows = parseMarkdownTable(listContent);
50
50
  const roleRow = rows.find(r => r.id === id);
51
51
 
@@ -66,7 +66,7 @@ rolesRouter.get('/:id', (req: Request, res: Response, next: NextFunction) => {
66
66
  };
67
67
 
68
68
  // role.yaml에서 name + persona + authority + skills 읽기
69
- const yamlPath = `roles/${id}/role.yaml`;
69
+ const yamlPath = `knowledge/roles/${id}/role.yaml`;
70
70
  if (fileExists(yamlPath)) {
71
71
  const raw = YAML.parse(readFile(yamlPath)) as Record<string, unknown>;
72
72
  if (raw.name) role.name = raw.name;
@@ -100,7 +100,7 @@ rolesRouter.get('/:id', (req: Request, res: Response, next: NextFunction) => {
100
100
 
101
101
  // 오늘 저널 읽기
102
102
  const today = new Date().toISOString().slice(0, 10);
103
- const journalPath = `roles/${id}/journal/${today}.md`;
103
+ const journalPath = `knowledge/roles/${id}/journal/${today}.md`;
104
104
  if (fileExists(journalPath)) {
105
105
  role.journal = readFile(journalPath).slice(0, 3000);
106
106
  }
@@ -226,7 +226,7 @@ skillsRouter.post('/role/:roleId', (req: Request, res: Response, next: NextFunct
226
226
  }
227
227
 
228
228
  // Add to role.yaml skills array
229
- const yamlPath = path.join(COMPANY_ROOT, 'roles', roleId, 'role.yaml');
229
+ const yamlPath = path.join(COMPANY_ROOT, 'knowledge', 'roles', roleId, 'role.yaml');
230
230
  if (!fs.existsSync(yamlPath)) {
231
231
  res.status(404).json({ error: `Role not found: ${roleId}` });
232
232
  return;
@@ -256,7 +256,7 @@ skillsRouter.delete('/role/:roleId/:skillId', (req: Request, res: Response, next
256
256
  const roleId = req.params.roleId as string;
257
257
  const skillId = req.params.skillId as string;
258
258
 
259
- const yamlPath = path.join(COMPANY_ROOT, 'roles', roleId, 'role.yaml');
259
+ const yamlPath = path.join(COMPANY_ROOT, 'knowledge', 'roles', roleId, 'role.yaml');
260
260
  if (!fs.existsSync(yamlPath)) {
261
261
  res.status(404).json({ error: `Role not found: ${roleId}` });
262
262
  return;
@@ -307,7 +307,7 @@ function installSkillFromTemplate(skillId: string): void {
307
307
  }
308
308
 
309
309
  function getRoleSkills(roleId: string): string[] {
310
- const yamlPath = path.join(COMPANY_ROOT, 'roles', roleId, 'role.yaml');
310
+ const yamlPath = path.join(COMPANY_ROOT, 'knowledge', 'roles', roleId, 'role.yaml');
311
311
  if (!fs.existsSync(yamlPath)) return [];
312
312
 
313
313
  const raw = YAML.parse(fs.readFileSync(yamlPath, 'utf-8')) as Record<string, unknown>;
@@ -100,7 +100,7 @@ const AKB_TOOLS: ToolDefinition[] = [
100
100
  type: 'object' as const,
101
101
  properties: {
102
102
  query: { type: 'string', description: 'Search keywords (e.g. "landing deploy", "refactoring decision", "Store Import")' },
103
- path: { type: 'string', description: 'Optional subdirectory to search in (e.g. "operations/decisions", "projects", "knowledge"). Defaults to entire AKB.' },
103
+ path: { type: 'string', description: 'Optional subdirectory to search in (e.g. "knowledge/decisions", "knowledge/projects", "knowledge"). Defaults to entire AKB.' },
104
104
  },
105
105
  required: ['query'],
106
106
  },
@@ -111,18 +111,18 @@ const AKB_TOOLS: ToolDefinition[] = [
111
111
  input_schema: {
112
112
  type: 'object' as const,
113
113
  properties: {
114
- path: { type: 'string', description: 'File path relative to AKB root (e.g. "operations/decisions/008-repo-structure.md", "projects/projects.md")' },
114
+ path: { type: 'string', description: 'File path relative to AKB root (e.g. "knowledge/decisions/008-repo-structure.md", "knowledge/projects/projects.md")' },
115
115
  },
116
116
  required: ['path'],
117
117
  },
118
118
  },
119
119
  {
120
120
  name: 'list_files',
121
- description: 'List files in a directory. Useful to discover what exists (e.g. "operations/waves/", "roles/engineer/journal/").',
121
+ description: 'List files in a directory. Useful to discover what exists (e.g. ".tycono/waves/", "knowledge/roles/engineer/journal/").',
122
122
  input_schema: {
123
123
  type: 'object' as const,
124
124
  properties: {
125
- path: { type: 'string', description: 'Directory path relative to AKB root (e.g. "operations/standups", "roles/pm/journal")' },
125
+ path: { type: 'string', description: 'Directory path relative to AKB root (e.g. ".tycono/standup", "knowledge/roles/pm/journal")' },
126
126
  pattern: { type: 'string', description: 'Glob pattern (default: "*.md")' },
127
127
  },
128
128
  required: ['path'],
@@ -257,7 +257,7 @@ function buildCompanyContext(): string {
257
257
 
258
258
  // 1. Company info (name, mission)
259
259
  try {
260
- const companyContent = readFile('company/company.md');
260
+ const companyContent = readFile('knowledge/company.md');
261
261
  const companyName = companyContent.split('\n').find(l => l.startsWith('# '))?.replace(/^#\s+/, '') ?? '';
262
262
  const missionMatch = companyContent.match(/^>\s*(.+)/m);
263
263
  const mission = missionMatch ? missionMatch[1].trim() : '';
@@ -283,7 +283,7 @@ function buildCompanyContext(): string {
283
283
 
284
284
  // 3. Active projects + current phase from tasks.md
285
285
  try {
286
- const projectsContent = readFile('projects/projects.md');
286
+ const projectsContent = readFile('knowledge/projects/projects.md');
287
287
  const rows = parseMarkdownTable(projectsContent);
288
288
  const activeProjects = rows
289
289
  .filter(r => (r.status ?? r.상태 ?? '').toLowerCase() !== 'archived')
@@ -335,7 +335,7 @@ function buildCompanyContext(): string {
335
335
 
336
336
  // 5. Recent CEO decisions (max 5)
337
337
  try {
338
- const decisionsDir = path.join(COMPANY_ROOT, 'operations', 'decisions');
338
+ const decisionsDir = path.join(COMPANY_ROOT, 'knowledge', 'decisions');
339
339
  if (fs.existsSync(decisionsDir)) {
340
340
  const files = fs.readdirSync(decisionsDir)
341
341
  .filter(f => f.endsWith('.md') && f !== 'decisions.md')
@@ -370,7 +370,7 @@ function buildRoleContext(roleId: string): string {
370
370
 
371
371
  // 0. Role profile — gives the agent its identity and work context
372
372
  try {
373
- const profilePath = path.join(COMPANY_ROOT, 'roles', roleId, 'profile.md');
373
+ const profilePath = path.join(COMPANY_ROOT, 'knowledge', 'roles', roleId, 'profile.md');
374
374
  if (fs.existsSync(profilePath)) {
375
375
  const content = fs.readFileSync(profilePath, 'utf-8').trim();
376
376
  if (content.length > 20) {
@@ -381,7 +381,7 @@ function buildRoleContext(roleId: string): string {
381
381
 
382
382
  // 1. Role's journal — latest entry only, compact summary (not full header dump)
383
383
  try {
384
- const journalDir = path.join(COMPANY_ROOT, 'roles', roleId, 'journal');
384
+ const journalDir = path.join(COMPANY_ROOT, 'knowledge', 'roles', roleId, 'journal');
385
385
  if (fs.existsSync(journalDir)) {
386
386
  const files = fs.readdirSync(journalDir)
387
387
  .filter(f => f.endsWith('.md'))
@@ -399,7 +399,7 @@ function buildRoleContext(roleId: string): string {
399
399
 
400
400
  // 2. Current tasks assigned to this role (from all project tasks.md files)
401
401
  try {
402
- const projectsDir = path.join(COMPANY_ROOT, 'projects');
402
+ const projectsDir = path.join(COMPANY_ROOT, 'knowledge', 'projects');
403
403
  if (fs.existsSync(projectsDir)) {
404
404
  const taskFiles = glob.sync('**/tasks.md', { cwd: projectsDir, absolute: false });
405
405
  const roleTasks: string[] = [];
@@ -425,7 +425,7 @@ function buildRoleContext(roleId: string): string {
425
425
 
426
426
  // 3. Recent waves — only from last 7 days (stale waves cause repetitive references)
427
427
  try {
428
- const wavesDir = path.join(COMPANY_ROOT, 'operations', 'waves');
428
+ const wavesDir = path.join(COMPANY_ROOT, '.tycono', 'waves');
429
429
  if (fs.existsSync(wavesDir)) {
430
430
  const tree = buildOrgTree(COMPANY_ROOT);
431
431
  const node = tree.nodes.get(roleId);
@@ -473,7 +473,7 @@ function buildRoleContext(roleId: string): string {
473
473
 
474
474
  // 4. Recent standup (latest, this role's section)
475
475
  try {
476
- const standupDir = path.join(COMPANY_ROOT, 'operations', 'standup');
476
+ const standupDir = path.join(COMPANY_ROOT, '.tycono', 'standup');
477
477
  if (fs.existsSync(standupDir)) {
478
478
  const files = fs.readdirSync(standupDir).filter(f => f.endsWith('.md')).sort().slice(-1);
479
479
  for (const file of files) {
@@ -489,7 +489,7 @@ function buildRoleContext(roleId: string): string {
489
489
 
490
490
  // 5. Recent decisions (last 3)
491
491
  try {
492
- const decisionsDir = path.join(COMPANY_ROOT, 'operations', 'decisions');
492
+ const decisionsDir = path.join(COMPANY_ROOT, 'knowledge', 'decisions');
493
493
  if (fs.existsSync(decisionsDir)) {
494
494
  const files = fs.readdirSync(decisionsDir)
495
495
  .filter(f => f.endsWith('.md') && f !== 'decisions.md')
@@ -863,7 +863,7 @@ ${companyCtx}
863
863
  ${roleCtx}
864
864
 
865
865
  You have search_akb, read_file, list_files tools. AKB root: ${COMPANY_ROOT}/
866
- Optionally explore 1-2 for fresh context: operations/waves/, operations/decisions/, roles/${roleId}/journal/
866
+ Optionally explore 1-2 for fresh context: .tycono/waves/, knowledge/decisions/, knowledge/roles/${roleId}/journal/
867
867
 
868
868
  RULES:
869
869
  1. Match the tone and length from the example conversations above. 1-3 sentences MAX.
@@ -65,7 +65,7 @@ syncRouter.post('/apply', async (req: Request, res: Response, next: NextFunction
65
65
 
66
66
  // Update source.upstream_version if provided
67
67
  if (upstreamVersion) {
68
- const yamlPath = path.join(COMPANY_ROOT, 'roles', roleId, 'role.yaml');
68
+ const yamlPath = path.join(COMPANY_ROOT, 'knowledge', 'roles', roleId, 'role.yaml');
69
69
  const raw = YAML.parse(fs.readFileSync(yamlPath, 'utf-8')) as Record<string, unknown>;
70
70
  if (raw.source && typeof raw.source === 'object') {
71
71
  (raw.source as Record<string, unknown>).upstream_version = upstreamVersion;
@@ -10,7 +10,7 @@ import type { ActivityEventType, ActivityEvent } from '../../../shared/types.js'
10
10
  /* ─── Constants ──────────────────────────── */
11
11
 
12
12
  function streamsDir(): string {
13
- return path.join(COMPANY_ROOT, 'operations', 'activity-streams');
13
+ return path.join(COMPANY_ROOT, '.tycono', 'activity-streams');
14
14
  }
15
15
 
16
16
  function ensureDir(): void {
@@ -4,7 +4,7 @@ import { COMPANY_ROOT } from './file-reader.js';
4
4
  import type { RoleStatus } from '../../../shared/types.js';
5
5
 
6
6
  function activityDir(): string {
7
- return path.join(COMPANY_ROOT, 'operations', 'activity');
7
+ return path.join(COMPANY_ROOT, '.tycono', 'activity');
8
8
  }
9
9
 
10
10
  export interface RoleActivity {
@@ -124,7 +124,7 @@ class ExecutionManager {
124
124
  const session = getSession(params.sessionId);
125
125
  if (session?.waveId) {
126
126
  try {
127
- const wavePath = path.join(COMPANY_ROOT, 'operations', 'waves', `${session.waveId}.json`);
127
+ const wavePath = path.join(COMPANY_ROOT, '.tycono', 'waves', `${session.waveId}.json`);
128
128
  if (fs.existsSync(wavePath)) {
129
129
  const waveData = JSON.parse(fs.readFileSync(wavePath, 'utf-8'));
130
130
  presetId = waveData.preset;
@@ -698,7 +698,7 @@ class ExecutionManager {
698
698
  const deadSession = getSession(deadExecution.sessionId);
699
699
  if (deadSession?.waveId) {
700
700
  try {
701
- const wp = path.join(COMPANY_ROOT, 'operations', 'waves', `${deadSession.waveId}.json`);
701
+ const wp = path.join(COMPANY_ROOT, '.tycono', 'waves', `${deadSession.waveId}.json`);
702
702
  if (fs.existsSync(wp)) {
703
703
  recoveryPresetId = JSON.parse(fs.readFileSync(wp, 'utf-8')).preset;
704
704
  }
@@ -73,16 +73,7 @@ export interface SyncStatus {
73
73
  * See: knowledge/data-persistence-architecture.md §2
74
74
  */
75
75
  const SAVE_PATHS = [
76
- 'roles/',
77
- 'projects/',
78
76
  'knowledge/',
79
- 'architecture/',
80
- 'company/',
81
- 'operations/standup/',
82
- 'operations/waves/',
83
- 'operations/decisions/',
84
- 'operations/cost/',
85
- 'operations/activity-streams/',
86
77
  '.claude/skills/',
87
78
  '.tycono/',
88
79
  'CLAUDE.md',
@@ -1,8 +1,8 @@
1
1
  /**
2
- * preset-loader.ts — Load presets from company/presets/
2
+ * preset-loader.ts — Load presets from knowledge/presets/
3
3
  *
4
- * Scans company/presets/ for:
5
- * - _default.yaml (auto-generated from existing roles/)
4
+ * Scans knowledge/presets/ for:
5
+ * - _default.yaml (auto-generated from existing knowledge/roles/)
6
6
  * - {name}/preset.yaml (installed presets with roles/skills/knowledge)
7
7
  *
8
8
  * Returns PresetSummary[] for TUI display and full LoadedPreset for wave creation.
@@ -12,7 +12,7 @@ import path from 'node:path';
12
12
  import YAML from 'yaml';
13
13
  import type { PresetDefinition, LoadedPreset, PresetSummary } from '../../../shared/types.js';
14
14
 
15
- const PRESETS_DIR = 'company/presets';
15
+ const PRESETS_DIR = 'knowledge/presets';
16
16
  const DEFAULT_PRESET_FILE = '_default.yaml';
17
17
 
18
18
  /**
@@ -20,7 +20,7 @@ const DEFAULT_PRESET_FILE = '_default.yaml';
20
20
  * This is generated on-the-fly — no need to persist _default.yaml.
21
21
  */
22
22
  function buildDefaultPreset(companyRoot: string): LoadedPreset {
23
- const rolesDir = path.join(companyRoot, 'roles');
23
+ const rolesDir = path.join(companyRoot, 'knowledge', 'roles');
24
24
  const roles: string[] = [];
25
25
 
26
26
  if (fs.existsSync(rolesDir)) {
@@ -314,12 +314,12 @@ export function scaffold(config: ScaffoldConfig): string[] {
314
314
 
315
315
  // Create directories
316
316
  const dirs = [
317
- 'company', 'roles', 'projects', 'architecture',
318
- 'operations', 'operations/standup', 'operations/waves',
319
- 'operations/decisions', 'operations/activity-streams',
320
- 'operations/sessions', 'operations/cost',
321
- 'knowledge', 'methodologies', '.claude/skills',
322
- '.claude/skills/_shared', '.tycono', 'company/presets',
317
+ 'knowledge', 'knowledge/roles', 'knowledge/projects',
318
+ 'knowledge/architecture', 'knowledge/methodologies',
319
+ 'knowledge/decisions', 'knowledge/presets',
320
+ '.tycono/waves', '.tycono/sessions', '.tycono/standup',
321
+ '.tycono/activity-streams', '.tycono/cost', '.tycono/activity',
322
+ '.claude/skills', '.claude/skills/_shared', '.tycono',
323
323
  ];
324
324
  for (const dir of dirs) {
325
325
  fs.mkdirSync(path.join(root, dir), { recursive: true });
@@ -343,15 +343,15 @@ export function scaffold(config: ScaffoldConfig): string[] {
343
343
  created.push('.tycono/custom-rules.md');
344
344
  }
345
345
 
346
- // Write company/company.md
346
+ // Write knowledge/company.md
347
347
  const companyTmpl = loadTemplate('company.md.tmpl');
348
- fs.writeFileSync(path.join(root, 'company', 'company.md'), renderTemplate(companyTmpl, vars));
349
- created.push('company/company.md');
348
+ fs.writeFileSync(path.join(root, 'knowledge', 'company.md'), renderTemplate(companyTmpl, vars));
349
+ created.push('knowledge/company.md');
350
350
 
351
- // Write roles/roles.md
351
+ // Write knowledge/roles/roles.md
352
352
  const rolesTmpl = loadTemplate('roles.md.tmpl');
353
- fs.writeFileSync(path.join(root, 'roles', 'roles.md'), renderTemplate(rolesTmpl, vars));
354
- created.push('roles/roles.md');
353
+ fs.writeFileSync(path.join(root, 'knowledge', 'roles', 'roles.md'), renderTemplate(rolesTmpl, vars));
354
+ created.push('knowledge/roles/roles.md');
355
355
 
356
356
  // Write .gitignore
357
357
  const giTmpl = loadTemplate('gitignore.tmpl');
@@ -400,14 +400,14 @@ export function scaffold(config: ScaffoldConfig): string[] {
400
400
  // Create roles with skill references
401
401
  for (const role of roles) {
402
402
  createRole(root, role);
403
- created.push(`roles/${role.id}/`);
403
+ created.push(`knowledge/roles/${role.id}/`);
404
404
  }
405
405
  }
406
406
 
407
407
  // Hub files
408
408
  const hubs: Record<string, string> = {
409
- 'projects/projects.md': `# Projects\n\nProject listing for ${config.companyName}.\n\n| Project | Status | Lead |\n|---------|--------|------|\n`,
410
- 'architecture/architecture.md': `# Architecture\n\nTechnical architecture for ${config.companyName}.\n`,
409
+ 'knowledge/projects/projects.md': `# Projects\n\nProject listing for ${config.companyName}.\n\n| Project | Status | Lead |\n|---------|--------|------|\n`,
410
+ 'knowledge/architecture/architecture.md': `# Architecture\n\nTechnical architecture for ${config.companyName}.\n`,
411
411
  'knowledge/knowledge.md': `# Knowledge Base\n\nDomain knowledge for ${config.companyName}.\n`,
412
412
  };
413
413
  for (const [filePath, content] of Object.entries(hubs)) {
@@ -419,15 +419,15 @@ export function scaffold(config: ScaffoldConfig): string[] {
419
419
  }
420
420
 
421
421
  // Methodology documents
422
- const methodologiesHub = path.join(root, 'methodologies', 'methodologies.md');
422
+ const methodologiesHub = path.join(root, 'knowledge', 'methodologies', 'methodologies.md');
423
423
  if (!fs.existsSync(methodologiesHub)) {
424
424
  fs.writeFileSync(methodologiesHub, `# Methodologies\n\n> Frameworks and principles that guide how AI agents work in this organization.\n\n## Documents\n\n| Document | Description |\n|----------|-------------|\n| [agentic-knowledge-base.md](./agentic-knowledge-base.md) | AKB — the file-based knowledge protocol for AI agents |\n\n---\n\n*Managed by: All*\n`);
425
- created.push('methodologies/methodologies.md');
425
+ created.push('knowledge/methodologies/methodologies.md');
426
426
  }
427
- const akbDoc = path.join(root, 'methodologies', 'agentic-knowledge-base.md');
427
+ const akbDoc = path.join(root, 'knowledge', 'methodologies', 'agentic-knowledge-base.md');
428
428
  if (!fs.existsSync(akbDoc)) {
429
429
  fs.writeFileSync(akbDoc, AKB_METHODOLOGY_CONTENT);
430
- created.push('methodologies/agentic-knowledge-base.md');
430
+ created.push('knowledge/methodologies/agentic-knowledge-base.md');
431
431
  }
432
432
 
433
433
  // Set default appearances for team roles
@@ -445,14 +445,14 @@ export function scaffold(config: ScaffoldConfig): string[] {
445
445
 
446
446
  // Brownfield: note existing project path
447
447
  if (config.existingProjectPath) {
448
- const targetDir = path.join(root, 'projects', 'existing');
448
+ const targetDir = path.join(root, 'knowledge', 'projects', 'existing');
449
449
  if (!fs.existsSync(targetDir)) {
450
450
  fs.mkdirSync(targetDir, { recursive: true });
451
451
  fs.writeFileSync(
452
452
  path.join(targetDir, 'prd.md'),
453
453
  `# Existing Project\n\nImported from: ${config.existingProjectPath}\n`
454
454
  );
455
- created.push('projects/existing/');
455
+ created.push('knowledge/projects/existing/');
456
456
  }
457
457
  }
458
458
 
@@ -481,7 +481,7 @@ export function scaffold(config: ScaffoldConfig): string[] {
481
481
  }
482
482
 
483
483
  function createRole(root: string, role: TeamRole): void {
484
- const roleDir = path.join(root, 'roles', role.id);
484
+ const roleDir = path.join(root, 'knowledge', 'roles', role.id);
485
485
  const skillDir = path.join(root, '.claude', 'skills', role.id);
486
486
  const journalDir = path.join(roleDir, 'journal');
487
487
 
@@ -533,7 +533,7 @@ function createRole(root: string, role: TeamRole): void {
533
533
  fs.writeFileSync(path.join(skillDir, 'SKILL.md'), skill);
534
534
 
535
535
  // Append to roles.md
536
- const rolesHubPath = path.join(root, 'roles', 'roles.md');
536
+ const rolesHubPath = path.join(root, 'knowledge', 'roles', 'roles.md');
537
537
  if (fs.existsSync(rolesHubPath)) {
538
538
  const hubContent = fs.readFileSync(rolesHubPath, 'utf-8');
539
539
  const row = `| ${role.name} | ${role.id} | ${role.level} | ${role.reportsTo} | Active |`;
@@ -65,7 +65,7 @@ export interface Session {
65
65
  /* ─── Session directory ─────────────────── */
66
66
 
67
67
  function sessionsDir(): string {
68
- return path.join(COMPANY_ROOT, 'operations', 'sessions');
68
+ return path.join(COMPANY_ROOT, '.tycono', 'sessions');
69
69
  }
70
70
 
71
71
  function ensureDir(): void {
@@ -123,7 +123,7 @@ class SupervisorHeartbeat {
123
123
  */
124
124
  private saveWaveFile(waveId: string, directive: string, preset?: string): void {
125
125
  try {
126
- const wavesDir = path.join(COMPANY_ROOT, 'operations', 'waves');
126
+ const wavesDir = path.join(COMPANY_ROOT, '.tycono', 'waves');
127
127
  if (!fs.existsSync(wavesDir)) fs.mkdirSync(wavesDir, { recursive: true });
128
128
  const wavePath = path.join(wavesDir, `${waveId}.json`);
129
129
  if (!fs.existsSync(wavePath)) {
@@ -185,7 +185,7 @@ class SupervisorHeartbeat {
185
185
  let originalDirective = '';
186
186
  let originalPreset: string | undefined;
187
187
  try {
188
- const waveFile = path.join(COMPANY_ROOT, 'operations', 'waves', `${waveId}.json`);
188
+ const waveFile = path.join(COMPANY_ROOT, '.tycono', 'waves', `${waveId}.json`);
189
189
  if (fs.existsSync(waveFile)) {
190
190
  const waveData = JSON.parse(fs.readFileSync(waveFile, 'utf-8'));
191
191
  originalDirective = waveData.directive ?? '';
@@ -820,7 +820,7 @@ ${state.continuous ? `## Continuous Improvement Mode (ON)
820
820
  }
821
821
  }
822
822
 
823
- // Auto-save the completed wave to operations/waves/
823
+ // Auto-save the completed wave to .tycono/waves/
824
824
  try {
825
825
  const result = saveCompletedWave(state.waveId, state.directive);
826
826
  if (result.ok) {
@@ -37,7 +37,7 @@ export class TokenLedger {
37
37
  private filePath: string;
38
38
 
39
39
  constructor(companyRoot: string) {
40
- const dir = path.join(companyRoot, 'operations', 'cost');
40
+ const dir = path.join(companyRoot, '.tycono', 'cost');
41
41
  if (!fs.existsSync(dir)) {
42
42
  fs.mkdirSync(dir, { recursive: true });
43
43
  }
@@ -13,7 +13,7 @@ import { type WaveRoleStatus, eventTypeToMessageStatus } from '../../../shared/t
13
13
  /* ─── Find wave file ──────────────────────── */
14
14
 
15
15
  export function findWaveFile(waveId: string): string | null {
16
- const wavesDir = path.join(COMPANY_ROOT, 'operations', 'waves');
16
+ const wavesDir = path.join(COMPANY_ROOT, '.tycono', 'waves');
17
17
  if (!fs.existsSync(wavesDir)) return null;
18
18
 
19
19
  const direct = path.join(wavesDir, `${waveId}.json`);
@@ -159,7 +159,7 @@ export function updateFollowUpInWave(waveId: string, sessionId: string, roleId:
159
159
  }
160
160
  }
161
161
 
162
- /* ─── Save completed wave to operations/waves/ ── */
162
+ /* ─── Save completed wave to .tycono/waves/ ── */
163
163
 
164
164
  /**
165
165
  * Auto-save a completed wave to disk.
@@ -178,7 +178,7 @@ export function saveCompletedWave(waveId: string, directive: string): { ok: bool
178
178
  // Scan activity-streams for ALL sessions belonging to this wave.
179
179
  // Wave sessions share a traceId chain: CEO → C-Level → subordinates.
180
180
  // We find the CEO session (waveId timestamp embedded in its ID), then follow dispatch:start events.
181
- const streamsDir = path.join(COMPANY_ROOT, 'operations', 'activity-streams');
181
+ const streamsDir = path.join(COMPANY_ROOT, '.tycono', 'activity-streams');
182
182
  if (fs.existsSync(streamsDir)) {
183
183
  // Find all activity stream files and check if they belong to this wave
184
184
  const waveTimestamp = waveId.replace('wave-', '');
@@ -260,7 +260,7 @@ export function saveCompletedWave(waveId: string, directive: string): { ok: bool
260
260
  rolesData.push({ roleId, roleName, sessionId: sid, status, events, childSessions });
261
261
  }
262
262
 
263
- const wavesDir = path.join(COMPANY_ROOT, 'operations', 'waves');
263
+ const wavesDir = path.join(COMPANY_ROOT, '.tycono', 'waves');
264
264
  if (!fs.existsSync(wavesDir)) {
265
265
  fs.mkdirSync(wavesDir, { recursive: true });
266
266
  }
@@ -325,7 +325,7 @@ export function saveCompletedWave(waveId: string, directive: string): { ok: bool
325
325
  if (existingPreset) waveJson.preset = existingPreset;
326
326
  fs.writeFileSync(jsonPath, JSON.stringify(waveJson, null, 2), 'utf-8');
327
327
 
328
- const relativePath = `operations/waves/${baseName}.json`;
328
+ const relativePath = `.tycono/waves/${baseName}.json`;
329
329
  console.log(`[WaveTracker] Wave saved: ${relativePath} (${rolesData.length} roles)`);
330
330
 
331
331
  // Earn coins for wave completion (non-critical)
@@ -8,13 +8,13 @@
8
8
 
9
9
  | Task | Read First | Role |
10
10
  |------|-----------|------|
11
- | Product planning | `projects/` | PM |
12
- | Technical design | `architecture/` | CTO |
13
- | Implementation | `projects/*/tasks.md` | Engineer |
14
- | UI/UX Design | `projects/*/design/` | Designer |
15
- | Testing/QA | `projects/*/tasks.md` | QA |
16
- | Operations | `operations/` | PM |
17
- | Business/Revenue | `company/` | CBO |
11
+ | Product planning | `knowledge/projects/` | PM |
12
+ | Technical design | `knowledge/architecture/` | CTO |
13
+ | Implementation | `knowledge/projects/*/tasks.md` | Engineer |
14
+ | UI/UX Design | `knowledge/projects/*/design/` | Designer |
15
+ | Testing/QA | `knowledge/projects/*/tasks.md` | QA |
16
+ | Operations | `.tycono/` | PM |
17
+ | Business/Revenue | `knowledge/company.md` | CBO |
18
18
  | Domain knowledge | `knowledge/` | CBO |
19
19
 
20
20
  ---
@@ -23,7 +23,7 @@
23
23
 
24
24
  > **AKB** = A file-based knowledge system where AI uses **search (Grep/Glob)** to find and **contextual links** to navigate
25
25
  >
26
- > Full reference: `methodologies/agentic-knowledge-base.md`
26
+ > Full reference: `knowledge/methodologies/agentic-knowledge-base.md`
27
27
 
28
28
  | Layer | Role | AI Usage |
29
29
  |-------|------|----------|
@@ -203,30 +203,30 @@ After completing any task, check:
203
203
  | +-- preferences.json <- UI preferences (auto-generated)
204
204
  | +-- custom-rules.md <- Company custom rules (user owned)
205
205
  | +-- rules-version <- Current CLAUDE.md version
206
- +-- company/
207
- | +-- company.md <- Mission, vision, company info
208
- +-- roles/
209
- | +-- roles.md <- Role listing (Hub)
210
- | +-- {role-id}/
211
- | +-- role.yaml <- Role definition
212
- | +-- profile.md <- Role profile
213
- | +-- journal/ <- Work journal
214
- +-- projects/
215
- | +-- projects.md <- Project listing (Hub)
216
- +-- architecture/
217
- | +-- architecture.md <- Technical architecture (Hub)
218
- +-- operations/
219
- | +-- standup/ <- Daily standups
220
206
  | +-- waves/ <- Wave execution logs
221
- | +-- decisions/ <- Decision log
222
- | +-- activity-streams/ <- SSE activity event logs
223
207
  | +-- sessions/ <- Session state
208
+ | +-- standup/ <- Daily standups
209
+ | +-- activity-streams/ <- SSE activity event logs
224
210
  | +-- cost/ <- Token usage ledger
211
+ | +-- activity/ <- Activity logs
225
212
  +-- knowledge/
226
213
  | +-- knowledge.md <- Domain knowledge (Hub)
227
- +-- methodologies/
228
- | +-- methodologies.md <- Methodology listing (Hub)
229
- | +-- agentic-knowledge-base.md <- AKB protocol reference
214
+ | +-- company.md <- Mission, vision, company info
215
+ | +-- roles/
216
+ | | +-- roles.md <- Role listing (Hub)
217
+ | | +-- {role-id}/
218
+ | | +-- role.yaml <- Role definition
219
+ | | +-- profile.md <- Role profile
220
+ | | +-- journal/ <- Work journal
221
+ | +-- projects/
222
+ | | +-- projects.md <- Project listing (Hub)
223
+ | +-- architecture/
224
+ | | +-- architecture.md <- Technical architecture (Hub)
225
+ | +-- decisions/ <- Decision log
226
+ | +-- presets/ <- Preset configurations
227
+ | +-- methodologies/
228
+ | +-- methodologies.md <- Methodology listing (Hub)
229
+ | +-- agentic-knowledge-base.md <- AKB protocol reference
230
230
  +-- .claude/skills/
231
231
  +-- _shared/ <- Shared skill plugins
232
232
  +-- {role-id}/SKILL.md <- Role-specific skill guides