@walwal-harness/cli 7.1.2 → 7.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,83 +1,118 @@
1
- # AGENTS.md — Project Context for AI Agents
1
+ # AGENTS.md — {{PROJECT_NAME}}
2
+ # walwal-harness v7.1 | Company Mode
3
+ # Installed: {{DATE}} | CLAUDE.md is a symlink to this file.
2
4
 
3
- > 이 파일은 모든 AI 에이전트(Claude, Cursor, Copilot, Windsurf 등)의 공통 진입점입니다.
4
- > CLAUDE.md는 이 파일의 심볼릭 링크입니다.
5
- > Generated by walwal-harness ({{DATE}})
5
+ ---
6
6
 
7
- ## Project
7
+ ## 1. Entry Points
8
8
 
9
- - **Name**: (Planner가 설정)
10
- - **Description**: (Planner가 설정)
11
- - **Phase**: INIT
12
- - **Harness**: `.harness/HARNESS.md` 참조
9
+ Two Owner-facing commands. Nothing else reaches the company.
13
10
 
14
- ## Tech Stack
11
+ | Command | When |
12
+ |---|---|
13
+ | `/goal` | Set, update, or extend a mission |
14
+ | `/hot-fix` | Emergency fix independent of the active goal |
15
15
 
16
- - Backend: (scan-project.sh가 감지)
17
- - Frontend: (scan-project.sh가 감지)
18
- - Database: (scan-project.sh가 감지)
16
+ `/ceo`, `/cto`, `/cqo`, `/coo`, `/cdo`, `/ops`, `/hiring` are not slash commands.
17
+ Internal routing uses agent/skill wiring only.
19
18
 
20
- ## IA-MAP (Information Architecture)
19
+ ---
21
20
 
22
- > Planner가 프로젝트 시작 시 확정합니다.
23
- > `[?]` 태그는 Planner가 분류해야 하는 미확인 경로입니다.
21
+ ## 2. Think Before Acting
22
+
23
+ Don't assume. Don't hide confusion.
24
+
25
+ - State assumptions before implementing. If uncertain, ask.
26
+ - If multiple approaches exist, name them — don't pick silently.
27
+ - Minimum change that solves the problem. No speculative scope.
28
+ - If something is unclear, stop. Name what is unclear. Ask.
29
+
30
+ For hot-fix: smallest correct patch only. Do not "improve" adjacent code.
31
+ For goal: define verifiable success criteria before CEO routes to CXX.
32
+
33
+ ---
34
+
35
+ ## 3. Company Structure
24
36
 
25
37
  ```
26
- /
27
- ├── AGENTS.md # [META] 프로젝트 컨텍스트 → Planner
28
- ├── CLAUDE.md # [META] → AGENTS.md 심볼릭 링크
29
- └── .harness/ # [HARNESS] 하네스 시스템 → Planner
38
+ Owner
39
+ └─ /goal or /hot-fix
40
+ └─ harness-ceo orchestrator — Owner's only contact
41
+ ├─ harness-coo research, hypothesis, service direction
42
+ ├─ harness-cdo branding, UI/UX, design review
43
+ ├─ harness-cto architecture, API, platform, implementation
44
+ ├─ harness-cqo quality gates, regression, archive, gotcha/convention
45
+ └─ harness-ops build monitoring, log analysis, service events
30
46
  ```
31
47
 
32
- ## Rules (모든 에이전트 공통)
33
-
34
- ### 읽기/쓰기 권한
35
-
36
- | 파일 | 읽기 | 쓰기 |
37
- |------|------|------|
38
- | AGENTS.md | 전체 | Planner만 |
39
- | .harness/actions/api-contract.json | 전체 | Planner만 |
40
- | .harness/actions/feature-list.json | 전체 | passes: Generator, 나머지: Planner |
41
- | .harness/progress.json | 전체 | 전체 (Session Boundary Protocol에 따라 업데이트) |
42
- | `[BE]` 소유 경로 | 전체 | Generator-Backend만 |
43
- | `[FE]` 소유 경로 | 전체 | Generator-Frontend만 |
44
- | .harness/archive/ | 전체 | 쓰기 금지 (불변) |
45
- | .harness/gotchas/ | 전체 | Dispatcher만 |
46
-
47
- ### 금지 사항
48
-
49
- - AGENTS.md를 Planner 외 에이전트가 수정
50
- - 서비스 간 직접 DB 접근
51
- - 테스트 삭제/약화
52
- - archive/ 내 파일 수정
53
- - 아티팩트 상태가 `draft` 미만인 선행 아티팩트에 의존하여 작업 시작
54
-
55
- ### 품질 게이트 (v3.1)
56
-
57
- | 게이트 | 시점 | 내용 |
58
- |--------|------|------|
59
- | **Pre-Eval Gate** | Generator → Evaluator 전환 | tsc, eslint, jest/vitest 자동 실행. 실패 시 Generator 리라우팅 |
60
- | **파일 소유권 검증** | 에이전트 전환 시 | git diff로 권한 밖 파일 수정 감지 |
61
- | **아티팩트 선행조건** | 에이전트 시작 전 | progress.json.artifacts 상태 확인 |
62
- | **에스컬레이션** | 3회 연속 실패 | Planner에게 scope 축소/접근 변경 요청 |
63
-
64
- ### Evaluation System (v3.2)
65
-
66
- | 설정 | 값 |
67
- |------|------|
68
- | PASS 기준 | **2.80 / 3.00 이상** |
69
- | FAIL 기준 | 2.79 이하 (예외 없음) |
70
- | Evidence 없는 Score | 0점 강제 |
71
- | AC 부분 통과 | FAIL (100% 필수) |
72
- | Regression 실패 1건+ | FAIL (신규 점수 무관) |
73
-
74
- - Planner는 feature-list.json에 **Executable AC** (type: api/visual/e2e + verify 조건) 필수 작성
75
- - Evaluator는 Adversarial Rules에 따라 적대적으로 검증 (rubber-stamping 금지)
76
- - 이전 Sprint PASS 기능은 Regression Checkpoint로 재검증
77
- - Eval-Functional ↔ Eval-Visual 간 Cross-Validation으로 불일치 감지
78
-
79
- ### 메모리 오염 방어
80
-
81
- - gotcha/memory 항목은 `unverified` 상태로 시작, Planner 리뷰 후 `verified` 승격
82
- - TTL 만료 항목은 Planner 스프린트 전환 시 리뷰 (갱신 또는 삭제)
83
- - 코드/git으로 검증 불가한 항목은 즉시 삭제
48
+ Each CXX:
49
+ - Runs in a **fresh session context** — no shared memory with CEO's session
50
+ - Records decisions in `.harness/documents/{mission_name}/{cxx}.md`
51
+ - Delegates all specialist work to hired workers — never executes directly
52
+ - If a required worker is absent, invokes `harness-hiring` before assigning
53
+
54
+ CEO rejects any CXX report that contains completed deliverables without matching worker records.
55
+
56
+ ---
57
+
58
+ ## 4. Mission Flow
59
+
60
+ ### Goal
61
+
62
+ 1. CEO reads the Owner request. Decides: brainstorm first, or assign immediately.
63
+ 2. CEO sends scoped questions to relevant CXX only.
64
+ 3. Each CXX hires workers, collects reports, records decisions in `{cxx}.md`.
65
+ 4. CEO aggregates CXX outputs, routes to next CXX or reports to Owner.
66
+
67
+ **Complete when:** `.harness/documents/{mission_name}/ceo.md` contains a final Owner report.
68
+
69
+ ### Hot Fix
70
+
71
+ 1. CEO receives emergency request. Immediately summons CTO and CQO.
72
+ 2. CTO designs the minimum patch path. Hires implementation workers.
73
+ 3. Workers implement. CTO verifies evidence, writes `cto.md`.
74
+ 4. CQO runs regression gate. Registers a lesson in `.harness/gotchas/` or `.harness/conventions/`. Writes `cqo.md`.
75
+ 5. Archive only after CQO verdict: **PASS**.
76
+
77
+ **Complete when:** `cto.md`, `cqo.md`, and at least one new gotcha or convention entry exist.
78
+
79
+ Note: A docmeta skip decision on harness documents (ceo.md, cto.md, cqo.md, worker reports) does not authorize skipping any mission protocol step. These are mission records, not derived output documents.
80
+
81
+ ---
82
+
83
+ ## 5. Harness Runtime
84
+
85
+ | Path | Role |
86
+ |---|---|
87
+ | `.harness/documents/{mission}/` | CXX decisions and worker reports per mission |
88
+ | `.harness/conventions/` | Durable rules (CQO writes, survives missions) |
89
+ | `.harness/gotchas/` | Recurrence-prevention records (CQO writes per hot-fix) |
90
+ | `.harness/memories/` | Long-term shared context |
91
+ | `.harness/shared/HR-Resource/` | Hireable worker skill pool |
92
+ | `.harness/archive/` | CQO-approved completed missions (immutable) |
93
+ | `.harness/logs/YYYY-MM-DD/` | OPS exception logs (non-happy-path only) |
94
+
95
+ `.harness/` is the mission state store. Not a build artifact. Do not delete.
96
+
97
+ ---
98
+
99
+ ## 6. Hard Rules
100
+
101
+ 1. **No source edit without `{mission}/cto.md`** — CTO scope sign-off is required before any source file is modified.
102
+ 2. **No CXX impersonation** — The active model must not act as CEO/CTO/CQO inline. Use installed harness skills in fresh sessions.
103
+ 3. **No unnamed workers** — All specialist work routes through `harness-hiring` → `harness-resource-manager`.
104
+ 4. **No archive without CQO verdict** — `{mission}/cqo.md` with explicit PASS must exist.
105
+ 5. **No gotcha skip** — Every hot-fix produces at least one `.harness/gotchas/` or `.harness/conventions/` entry.
106
+ 6. **This file is read-only during missions** — Raise a separate `/goal` to update AGENTS.md.
107
+ 7. **CEO routes only to CXX — never to workers** — CEO must not dispatch, hire, or brief specialist workers directly. Implementation workers are hired by CTO. Evaluator/tester workers are hired by CQO.
108
+ 8. **No CXX self-execution** — CXX agents coordinate and manage only. A CXX that produces deliverables without matching worker records has violated its scope. CEO must reject such reports.
109
+ 9. **No verdict without worker evidence** — CQO cannot issue ACCEPTED/REJECTED without a Worker Evidence Manifest referencing at least one evaluator worker. Self-inspection by CQO is not valid evidence.
110
+ 10. **Hierarchical worker ownership** — Hired workers are installed under `.claude/skills/{owning-cxx}/{worker}/` and `.codex/skills/{owning-cxx}/{worker}/`; mission worker reports live under `.harness/documents/{mission}/{owning-cxx}/workers/`. Flat `{mission}/workers/` reports are legacy and signal an ownership violation unless explicitly migrated.
111
+
112
+ ---
113
+
114
+ ## 7. Project Context
115
+
116
+ - **Tech Stack**: {{TECH_STACK}}
117
+ - **Structure**: {{PROJECT_STRUCTURE}}
118
+ - **Harness installed**: {{DATE}}
package/bin/init.js CHANGED
@@ -21,6 +21,17 @@ const isAuto = args.includes('--auto');
21
21
  const isForce = args.includes('--force');
22
22
  const isHelp = args.includes('--help') || args.includes('-h');
23
23
 
24
+ function getOptionValue(name) {
25
+ const eqPrefix = `${name}=`;
26
+ const eqArg = args.find((a) => a.startsWith(eqPrefix));
27
+ if (eqArg) return eqArg.slice(eqPrefix.length);
28
+ const idx = args.indexOf(name);
29
+ if (idx !== -1 && args[idx + 1] && !args[idx + 1].startsWith('-')) {
30
+ return args[idx + 1];
31
+ }
32
+ return null;
33
+ }
34
+
24
35
  // ─────────────────────────────────────────
25
36
  // Resolve project root
26
37
  // ─────────────────────────────────────────
@@ -28,6 +39,9 @@ const isHelp = args.includes('--help') || args.includes('-h');
28
39
  // inside node_modules, NOT the consumer project root.
29
40
  // We detect this and walk up to find the actual project root.
30
41
  function resolveProjectRoot() {
42
+ const explicitRoot = getOptionValue('--project-root');
43
+ if (explicitRoot) return path.resolve(explicitRoot);
44
+
31
45
  let cwd = process.cwd();
32
46
 
33
47
  // If we're running inside node_modules, walk up to the project root
@@ -430,12 +444,12 @@ function scaffoldHarness() {
430
444
  }
431
445
 
432
446
  const rosterPath = path.join(HARNESS_DIR, 'shared', 'hr-roster.json');
433
- if (!fileExists(rosterPath) || isForce) {
447
+ if (!fileExists(rosterPath)) {
434
448
  fs.writeFileSync(rosterPath, JSON.stringify({ hired: [] }, null, 2) + '\n');
435
449
  }
436
450
 
437
451
  const resourceIndexPath = path.join(HARNESS_DIR, 'shared', 'resource-index.json');
438
- if (!fileExists(resourceIndexPath) || isForce) {
452
+ if (!fileExists(resourceIndexPath)) {
439
453
  fs.writeFileSync(resourceIndexPath, JSON.stringify({ aliases: {}, keywords: {} }, null, 2) + '\n');
440
454
  }
441
455
 
@@ -1183,17 +1197,40 @@ function detectMigrationNeeded() {
1183
1197
  const configPath = path.join(HARNESS_DIR, 'config.json');
1184
1198
  const memoryPath = path.join(HARNESS_DIR, 'memory.md');
1185
1199
  const memoryTplPath = path.join(PKG_ROOT, 'assets', 'templates', 'memory.md');
1200
+ const rosterPath = path.join(HARNESS_DIR, 'shared', 'hr-roster.json');
1201
+ const resourceIndexPath = path.join(HARNESS_DIR, 'shared', 'resource-index.json');
1186
1202
  const flags = {
1187
1203
  progressV3toV4: false,
1188
1204
  progressLegacyRouting: false,
1189
1205
  configMissingCompanyMode: false,
1190
1206
  configLegacyRouting: false,
1207
+ coreSkillsStale: false,
1208
+ hrResourcePoolStale: false,
1209
+ rosterCodexPathsMissing: false,
1210
+ resourceIndexCodexWordingMissing: false,
1191
1211
  memoryMissingSystemEntries: [],
1192
1212
  gotchaMissingEntries: {}, // { "<filename>": [G-IDs...] }
1193
1213
  conventionMissingEntries: {}, // { "<filename>": [C-IDs...] }
1194
1214
  bundleVersionStale: null, // { current, installed }
1195
1215
  };
1196
1216
 
1217
+ const coreSkills = ['ceo', 'coo', 'cdo', 'cto', 'cqo', 'ops', 'hiring', 'resource-manager', 'brick-office'];
1218
+ for (const skill of coreSkills) {
1219
+ const srcPath = path.join(PKG_ROOT, 'HR-Resource', skill, 'SKILL.md');
1220
+ if (!fs.existsSync(srcPath)) continue;
1221
+ const srcBody = fs.readFileSync(srcPath, 'utf8');
1222
+ for (const root of [CLAUDE_SKILLS_DIR, CODEX_SKILLS_DIR]) {
1223
+ const destPath = path.join(root, `harness-${skill}`, 'SKILL.md');
1224
+ if (!fs.existsSync(destPath) || fs.readFileSync(destPath, 'utf8') !== srcBody) {
1225
+ flags.coreSkillsStale = true;
1226
+ }
1227
+ }
1228
+ const poolPath = path.join(HARNESS_DIR, 'shared', 'HR-Resource', skill, 'SKILL.md');
1229
+ if (fs.existsSync(path.dirname(poolPath)) && (!fs.existsSync(poolPath) || fs.readFileSync(poolPath, 'utf8') !== srcBody)) {
1230
+ flags.hrResourcePoolStale = true;
1231
+ }
1232
+ }
1233
+
1197
1234
  // Gotcha entry-level diff: for each bundled gotcha file, compare entry IDs.
1198
1235
  // 사용자가 직접 추가한 [G-NNN] 은 절대 건드리지 않으며, 패키지에서 새로
1199
1236
  // 도입된 시스템 entry 만 append 대상.
@@ -1266,6 +1303,27 @@ function detectMigrationNeeded() {
1266
1303
  ) flags.configLegacyRouting = true;
1267
1304
  } catch {}
1268
1305
  }
1306
+ if (fs.existsSync(rosterPath)) {
1307
+ try {
1308
+ const roster = JSON.parse(fs.readFileSync(rosterPath, 'utf8'));
1309
+ const hired = Array.isArray(roster.hired) ? roster.hired : [];
1310
+ flags.rosterCodexPathsMissing = hired.some((entry) => {
1311
+ if (!entry || typeof entry !== 'object' || !entry.worker) return false;
1312
+ const owner = entry.owner || entry.owningCxx;
1313
+ const flatClaude = /^\.claude\/skills\/[^/]+\/SKILL\.md$/.test(entry.skillPaths?.claude || '');
1314
+ const flatCodex = /^\.codex\/skills\/[^/]+\/SKILL\.md$/.test(entry.skillPaths?.codex || '');
1315
+ return !owner || !entry.skillPaths?.codex || !entry.skillPaths?.claude || /^\.claude\/skills\//.test(entry.skillPath || '') || flatClaude || flatCodex;
1316
+ });
1317
+ } catch {}
1318
+ }
1319
+ if (fs.existsSync(resourceIndexPath)) {
1320
+ try {
1321
+ const idx = JSON.parse(fs.readFileSync(resourceIndexPath, 'utf8'));
1322
+ if (!idx.invocation || !idx.invocation.codex || !idx.invocation.claude) {
1323
+ flags.resourceIndexCodexWordingMissing = true;
1324
+ }
1325
+ } catch {}
1326
+ }
1269
1327
  if (fs.existsSync(memoryPath) && fs.existsSync(memoryTplPath)) {
1270
1328
  try {
1271
1329
  const userMem = fs.readFileSync(memoryPath, 'utf8');
@@ -1355,6 +1413,18 @@ function showMigrationProposal(flags) {
1355
1413
  if (flags.configLegacyRouting) {
1356
1414
  console.log(' • config.json: legacy dispatcher/conductor wording → v7 CEO/CXX wording');
1357
1415
  }
1416
+ if (flags.coreSkillsStale) {
1417
+ console.log(' • .claude/.codex skills: harness-* core skills 최신 패키지로 refresh');
1418
+ }
1419
+ if (flags.hrResourcePoolStale) {
1420
+ console.log(' • .harness/shared/HR-Resource: core HR pool 최신 패키지로 refresh');
1421
+ }
1422
+ if (flags.rosterCodexPathsMissing) {
1423
+ console.log(' • hr-roster.json: 기존 hired worker 보존 + Claude/Codex skillPaths 보강');
1424
+ }
1425
+ if (flags.resourceIndexCodexWordingMissing) {
1426
+ console.log(' • resource-index.json: Claude/Codex skill invocation wording 보강');
1427
+ }
1358
1428
  if (flags.memoryMissingSystemEntries && flags.memoryMissingSystemEntries.length) {
1359
1429
  console.log(' • memory.md: 시스템 entry 누락 — append 가능');
1360
1430
  console.log(' [' + flags.memoryMissingSystemEntries.join(', ') + ']');
@@ -1397,6 +1467,10 @@ function runMigrate(opts = {}) {
1397
1467
  !flags.progressLegacyRouting &&
1398
1468
  !flags.configMissingCompanyMode &&
1399
1469
  !flags.configLegacyRouting &&
1470
+ !flags.coreSkillsStale &&
1471
+ !flags.hrResourcePoolStale &&
1472
+ !flags.rosterCodexPathsMissing &&
1473
+ !flags.resourceIndexCodexWordingMissing &&
1400
1474
  (!flags.memoryMissingSystemEntries || flags.memoryMissingSystemEntries.length === 0) &&
1401
1475
  gotchaMissingTotal === 0 &&
1402
1476
  conventionMissingTotal === 0 &&
@@ -1405,7 +1479,7 @@ function runMigrate(opts = {}) {
1405
1479
  console.log('');
1406
1480
  let pkgVer = 'unknown';
1407
1481
  try { pkgVer = JSON.parse(fs.readFileSync(path.join(PKG_ROOT, 'package.json'), 'utf8')).version; } catch {}
1408
- log(`이미 최신 — bundle v${pkgVer} 일치, progress v${TARGET_PROGRESS_VERSION} v7 routing, config.company_mode, memory 시스템 entry, gotcha entry 모두 sync.`);
1482
+ log(`이미 최신 — bundle v${pkgVer} 일치, progress v${TARGET_PROGRESS_VERSION} v7 routing, config.company_mode, Codex skill wiring, memory 시스템 entry, gotcha entry 모두 sync.`);
1409
1483
  return;
1410
1484
  }
1411
1485
 
@@ -1474,6 +1548,99 @@ function runMigrate(opts = {}) {
1474
1548
  }
1475
1549
  }
1476
1550
 
1551
+ // 2a. Refresh installed core harness skills and HR core pool without
1552
+ // touching hired worker skills or roster state.
1553
+ if (flags.hrResourcePoolStale) {
1554
+ const hrResourceSrc = path.join(PKG_ROOT, 'HR-Resource');
1555
+ const hrResourceDest = path.join(HARNESS_DIR, 'shared', 'HR-Resource');
1556
+ if (fs.existsSync(hrResourceSrc)) {
1557
+ log(' .harness/shared/HR-Resource: core pool refresh');
1558
+ if (!dryRun) copyDir(hrResourceSrc, hrResourceDest);
1559
+ }
1560
+ }
1561
+ if (flags.coreSkillsStale) {
1562
+ log(' .claude/.codex skills: harness-* core skills refresh');
1563
+ if (!dryRun) installSkills();
1564
+ }
1565
+
1566
+ // 2b. hr-roster.json — preserve hired worker history, add tool-specific
1567
+ // paths so Codex can reuse existing hires without relying on .claude.
1568
+ const rosterPath = path.join(HARNESS_DIR, 'shared', 'hr-roster.json');
1569
+ if (flags.rosterCodexPathsMissing && fs.existsSync(rosterPath)) {
1570
+ const original = fs.readFileSync(rosterPath, 'utf8');
1571
+ try {
1572
+ const roster = JSON.parse(original);
1573
+ const hired = Array.isArray(roster.hired) ? roster.hired : [];
1574
+ let changed = false;
1575
+ roster.hired = hired.map((entry) => {
1576
+ if (!entry || typeof entry !== 'object' || !entry.worker) return entry;
1577
+ const worker = entry.worker;
1578
+ const owner = entry.owner || entry.owningCxx || 'unknown';
1579
+ const scopedPrefix = owner ? `${owner}/` : '';
1580
+ const claudePath = entry.skillPaths?.claude || (
1581
+ /^\.claude\/skills\//.test(entry.skillPath || '')
1582
+ ? entry.skillPath
1583
+ : `.claude/skills/${scopedPrefix}${worker}/SKILL.md`
1584
+ );
1585
+ const codexPath = entry.skillPaths?.codex || (
1586
+ /^\.codex\/skills\//.test(entry.skillPath || '')
1587
+ ? entry.skillPath
1588
+ : `.codex/skills/${scopedPrefix}${worker}/SKILL.md`
1589
+ );
1590
+ const next = {
1591
+ ...entry,
1592
+ owner,
1593
+ skillPath: `.harness/shared/HR-Resource/${worker}/SKILL.md`,
1594
+ skillPaths: {
1595
+ ...(entry.skillPaths || {}),
1596
+ claude: /^\.claude\/skills\/[^/]+\/SKILL\.md$/.test(claudePath)
1597
+ ? `.claude/skills/${scopedPrefix}${worker}/SKILL.md`
1598
+ : claudePath,
1599
+ codex: /^\.codex\/skills\/[^/]+\/SKILL\.md$/.test(codexPath)
1600
+ ? `.codex/skills/${scopedPrefix}${worker}/SKILL.md`
1601
+ : codexPath,
1602
+ source: `.harness/shared/HR-Resource/${worker}/SKILL.md`,
1603
+ },
1604
+ };
1605
+ if (JSON.stringify(next) !== JSON.stringify(entry)) changed = true;
1606
+ return next;
1607
+ });
1608
+ if (changed) {
1609
+ log(` hr-roster.json: ${roster.hired.length}개 hired worker에 Codex 경로 보강`);
1610
+ if (!dryRun) {
1611
+ fs.writeFileSync(path.join(backupDir, 'hr-roster.json'), original);
1612
+ fs.writeFileSync(rosterPath, JSON.stringify(roster, null, 2) + '\n');
1613
+ }
1614
+ }
1615
+ } catch (e) {
1616
+ log(` WARNING: hr-roster.json parse failed, skipped (${e.message})`);
1617
+ }
1618
+ }
1619
+
1620
+ // 2c. resource-index.json — keep aliases/keywords, add tool wording.
1621
+ const resourceIndexPath = path.join(HARNESS_DIR, 'shared', 'resource-index.json');
1622
+ if (flags.resourceIndexCodexWordingMissing && fs.existsSync(resourceIndexPath)) {
1623
+ const original = fs.readFileSync(resourceIndexPath, 'utf8');
1624
+ try {
1625
+ const idx = JSON.parse(original);
1626
+ idx.aliases = idx.aliases || {};
1627
+ idx.keywords = idx.keywords || {};
1628
+ idx.invocation = {
1629
+ ...(idx.invocation || {}),
1630
+ claude: 'Invoke the installed skill by name from .claude/skills/{owning-cxx}/{worker}/SKILL.md.',
1631
+ codex: 'Use the installed skill by name from .codex/skills/{owning-cxx}/{worker}/SKILL.md.',
1632
+ source: 'Candidate pool lives in .harness/shared/HR-Resource/{worker}/SKILL.md.',
1633
+ };
1634
+ log(' resource-index.json: Claude/Codex invocation wording 보강');
1635
+ if (!dryRun) {
1636
+ fs.writeFileSync(path.join(backupDir, 'resource-index.json'), original);
1637
+ fs.writeFileSync(resourceIndexPath, JSON.stringify(idx, null, 2) + '\n');
1638
+ }
1639
+ } catch (e) {
1640
+ log(` WARNING: resource-index.json parse failed, skipped (${e.message})`);
1641
+ }
1642
+ }
1643
+
1477
1644
  // 3. memory.md — append missing system entries (M-NEXUS-*, M-SYS-*) only.
1478
1645
  // User-added [M-NNN] entries are NEVER touched.
1479
1646
  const memoryPath = path.join(HARNESS_DIR, 'memory.md');
package/commands/goal.md CHANGED
@@ -18,6 +18,8 @@ Required flow:
18
18
  8. CEO must require worker report paths under `.harness/documents/{mission_name}/workers/` before accepting CXX completion.
19
19
  9. Do not invoke internal roles through slash commands; commands are Owner entrypoints only.
20
20
 
21
+ Note: Harness documents (ceo.md, cto.md, cqo.md, worker reports) are mission records, not derived output documents. A docmeta skip decision on these files does not authorize skipping any harness protocol step.
22
+
21
23
  Owner request:
22
24
 
23
25
  ```
@@ -9,14 +9,17 @@ Route the Owner request to the installed `harness-ceo` agent/skill as an emergen
9
9
 
10
10
  Required flow:
11
11
  1. Create `.harness/documents/{hotfix_name}/ceo.md`.
12
- 2. CEO summons CTO and CQO; summon COO/CDO only when planning or UX decisions are involved.
12
+ 2. CEO summons CTO and CQO first; summon COO/CDO only when planning or UX decisions are involved.
13
13
  3. CTO applies the smallest correct patch path through hired implementation skills.
14
- 4. CXX roles must not directly execute specialist deliverables. They must use hired workers for implementation, QA, ops checks, and documentation even when the fix is small.
15
- 5. If a required worker is missing, CEO or the responsible CXX must invoke the installed `harness-hiring` skill before assigning the work.
16
- 6. CQO records regression coverage and recurrence prevention with worker report paths under `.harness/documents/{hotfix_name}/workers/`.
17
- 7. Register durable lessons in `.harness/gotchas/`, `.harness/conventions/`, or `.harness/memories/` as appropriate.
18
- 8. Archive only after CQO has accepted the fix.
19
- 9. Do not invoke internal roles through slash commands; commands are Owner entrypoints only.
14
+ 4. CXX roles must start in a fresh session context. Do not let the default model impersonate a missing CXX or worker.
15
+ 5. CXX roles must not directly execute specialist deliverables. They must use hired workers for implementation, QA, ops checks, and documentation even when the fix is small.
16
+ 6. If a required worker is missing, CEO or the responsible CXX must invoke the installed `harness-hiring` skill before assigning the work.
17
+ 7. CEO must require worker report paths under `.harness/documents/{hotfix_name}/workers/` before accepting CXX completion.
18
+ 8. CQO must register durable lessons in `.harness/gotchas/`, `.harness/conventions/`, or `.harness/memories/`. This step is mandatory, not optional, even for small fixes.
19
+ 9. Archive only after CQO has accepted the fix.
20
+ 10. Do not invoke internal roles through slash commands; commands are Owner entrypoints only.
21
+
22
+ Note: Harness documents (ceo.md, cto.md, cqo.md, worker reports) are mission records, not derived output documents. A docmeta skip decision on these files does not authorize skipping any harness protocol step.
20
23
 
21
24
  Hot-fix request:
22
25
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@walwal-harness/cli",
3
- "version": "7.1.2",
3
+ "version": "7.1.6",
4
4
  "description": "Company-style AI agent harness for Claude and Codex. Installs commands, CXX agents, skills, HR-Resource hiring pool, and project-local .harness runtime state.",
5
5
  "bin": {
6
6
  "walwal-harness": "bin/init.js"
@@ -11,6 +11,16 @@ mode="${2:-text}"
11
11
  violations=()
12
12
 
13
13
  has_worker_report() {
14
+ local mission_dir="$1"
15
+ local owner="${2:-}"
16
+ if [ -n "$owner" ]; then
17
+ find "$mission_dir/$owner/workers" -maxdepth 1 -type f -name '*.md' 2>/dev/null | grep -q .
18
+ else
19
+ find "$mission_dir"/{coo,cdo,cto,cqo,ops}/workers -maxdepth 1 -type f -name '*.md' 2>/dev/null | grep -q .
20
+ fi
21
+ }
22
+
23
+ has_legacy_flat_worker_report() {
14
24
  local mission_dir="$1"
15
25
  find "$mission_dir/workers" -maxdepth 1 -type f -name '*.md' 2>/dev/null | grep -q .
16
26
  }
@@ -19,16 +29,21 @@ for mission_dir in "$DOC_ROOT"/*; do
19
29
  [ -d "$mission_dir" ] || continue
20
30
  mission_name="$(basename "$mission_dir")"
21
31
 
22
- cxx_docs=()
32
+ if has_legacy_flat_worker_report "$mission_dir"; then
33
+ violations+=("$mission_name:legacy-flat-workers")
34
+ fi
35
+
23
36
  for cxx in coo cdo cto cqo ops; do
24
37
  cxx_path="$mission_dir/$cxx.md"
25
38
  [ -s "$cxx_path" ] || continue
26
- cxx_docs+=("$cxx.md")
39
+ if ! has_worker_report "$mission_dir" "$cxx"; then
40
+ violations+=("$mission_name:$cxx.md")
41
+ fi
27
42
  done
28
43
 
29
- [ "${#cxx_docs[@]}" -gt 0 ] || continue
30
- if ! has_worker_report "$mission_dir"; then
31
- violations+=("$mission_name:${cxx_docs[*]}")
44
+ cqo_path="$mission_dir/cqo.md"
45
+ if [ -s "$cqo_path" ] && grep -Eq '\b(ACCEPTED|REJECTED|PASS|FAIL)\b' "$cqo_path" && ! has_worker_report "$mission_dir" "cqo"; then
46
+ violations+=("$mission_name:cqo-verdict-without-evaluator")
32
47
  fi
33
48
  done
34
49
 
@@ -51,8 +66,8 @@ else
51
66
  mission="${violation%%:*}"
52
67
  docs="${violation#*:}"
53
68
  echo "- mission: $mission"
54
- echo " cxx_docs: $docs"
55
- echo " required: at least one .harness/documents/$mission/workers/{worker-name}.md report"
69
+ echo " issue: $docs"
70
+ echo " required: worker reports under .harness/documents/$mission/{cxx}/workers/{worker-name}.md"
56
71
  done
57
72
  fi
58
73