@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.
- package/HR-Resource/cdo/SKILL.md +2 -2
- package/HR-Resource/ceo/SKILL.md +22 -1
- package/HR-Resource/coo/SKILL.md +2 -2
- package/HR-Resource/cqo/SKILL.md +12 -7
- package/HR-Resource/cto/SKILL.md +9 -6
- package/HR-Resource/hiring/SKILL.md +11 -8
- package/HR-Resource/ops/SKILL.md +2 -2
- package/HR-Resource/resource-manager/SKILL.md +8 -5
- package/README.md +95 -343
- package/assets/templates/AGENTS-ko.md.template +160 -0
- package/assets/templates/AGENTS.md.template +107 -72
- package/bin/init.js +170 -3
- package/commands/goal.md +2 -0
- package/commands/hot-fix.md +10 -7
- package/package.json +1 -1
- package/scripts/harness-worker-evidence-validate.sh +22 -7
|
@@ -1,83 +1,118 @@
|
|
|
1
|
-
# AGENTS.md —
|
|
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
|
-
|
|
4
|
-
> CLAUDE.md는 이 파일의 심볼릭 링크입니다.
|
|
5
|
-
> Generated by walwal-harness ({{DATE}})
|
|
5
|
+
---
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## 1. Entry Points
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
- **Description**: (Planner가 설정)
|
|
11
|
-
- **Phase**: INIT
|
|
12
|
-
- **Harness**: `.harness/HARNESS.md` 참조
|
|
9
|
+
Two Owner-facing commands. Nothing else reaches the company.
|
|
13
10
|
|
|
14
|
-
|
|
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
|
-
|
|
17
|
-
|
|
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
|
-
|
|
19
|
+
---
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
|
70
|
-
|
|
71
|
-
|
|
|
72
|
-
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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)
|
|
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)
|
|
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
|
```
|
package/commands/hot-fix.md
CHANGED
|
@@ -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
|
|
15
|
-
5.
|
|
16
|
-
6.
|
|
17
|
-
7.
|
|
18
|
-
8.
|
|
19
|
-
9.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
39
|
+
if ! has_worker_report "$mission_dir" "$cxx"; then
|
|
40
|
+
violations+=("$mission_name:$cxx.md")
|
|
41
|
+
fi
|
|
27
42
|
done
|
|
28
43
|
|
|
29
|
-
|
|
30
|
-
if ! has_worker_report "$mission_dir"; then
|
|
31
|
-
violations+=("$mission_name
|
|
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 "
|
|
55
|
-
echo " required:
|
|
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
|
|