@walwal-harness/cli 7.1.24 → 7.1.25
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/CHANGELOG.md +10 -0
- package/README.md +1 -0
- package/assets/templates/AGENTS.md.template +12 -0
- package/bin/init.js +78 -13
- package/commands/goal.md +5 -0
- package/commands/hot-fix.md +5 -0
- package/commands/submission.md +5 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -31,6 +31,16 @@ docmeta:
|
|
|
31
31
|
|
|
32
32
|
## Unreleased
|
|
33
33
|
|
|
34
|
+
## 7.1.25 — Absolute Claude hook paths + Codex adapter docs (2026-05-26)
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
- Claude hooks and statusline now install with project-root absolute script paths, preventing `UserPromptSubmit hook error: scripts/harness-user-prompt-submit.sh: No such file or directory` when Claude runs hooks outside the project root.
|
|
38
|
+
- Existing relative-path harness hooks are migrated to absolute paths on re-init.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
- Codex command and AGENTS templates now explain that `.codex/skills/**/SKILL.md` is the Codex runtime protocol and `.codex/agents/` is not required.
|
|
42
|
+
- `migrate` appends a Codex Runtime Adapter block to existing AGENTS.md files when missing.
|
|
43
|
+
|
|
34
44
|
## 7.1.24 — Hourly CEO wake loop + migrate script refresh (2026-05-22)
|
|
35
45
|
|
|
36
46
|
### Changed
|
package/README.md
CHANGED
|
@@ -215,6 +215,7 @@ Hourly autonomous wake:
|
|
|
215
215
|
- `HARNESS_WAKE_MODEL=<model>` optionally pins the Claude model for wake ticks.
|
|
216
216
|
- Each wake tick prompts CEO to convene CXX + OPS, collect progress and decisions, dispatch the next action without asking Owner, and require CQO/OPS verification until the active goal works.
|
|
217
217
|
- `npx @walwal-harness/cli migrate` refreshes package-owned runtime scripts, so existing projects receive wake prompt updates without a full re-init.
|
|
218
|
+
- In Codex, `.codex/skills/**/SKILL.md` files are the runtime protocol. `.codex/agents/` is not required; Codex should manually read the relevant skill if it is not auto-listed.
|
|
218
219
|
|
|
219
220
|
---
|
|
220
221
|
|
|
@@ -19,6 +19,18 @@ Internal routing uses agent/skill wiring only.
|
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
+
## 1.1 Codex Runtime Adapter
|
|
23
|
+
|
|
24
|
+
Codex does not need `.codex/agents/` to run this harness. The installed Codex contract is:
|
|
25
|
+
|
|
26
|
+
- Owner entrypoints are `.codex/commands/goal.md`, `.codex/commands/submission.md`, and `.codex/commands/hot-fix.md`.
|
|
27
|
+
- Harness role protocols live in `.codex/skills/harness-{ceo,coo,cdo,cto,cqo,ops,hiring,resource-manager,brick-office}/SKILL.md`.
|
|
28
|
+
- If Codex does not auto-list these as available skills, manually read the relevant `SKILL.md` file and follow it. Do not report that the harness is unavailable just because `.codex/agents/` is absent.
|
|
29
|
+
- When a command asks for a "fresh session context", Codex must create a role-scoped context by reading only the role skill, the active mission files, and required conventions/gotchas before writing that role's `{cxx}.md`. If Codex sub-agent tooling is explicitly available and requested, it may be used; otherwise execute the role protocol sequentially with clear role boundaries.
|
|
30
|
+
- Codex must not treat `.codex/skills` as passive documentation. These files are the installed runtime protocol for Codex.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
22
34
|
## 2. Think Before Acting
|
|
23
35
|
|
|
24
36
|
Don't assume. Don't hide confusion.
|
package/bin/init.js
CHANGED
|
@@ -168,6 +168,33 @@ function mergeClaudePermissionAllow(settings, entries) {
|
|
|
168
168
|
return changed;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
function shellQuote(value) {
|
|
172
|
+
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function harnessScriptCommand(scriptName) {
|
|
176
|
+
return `bash ${shellQuote(path.join(PROJECT_ROOT, 'scripts', scriptName))}`;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function replaceHarnessHookCommand(entries, marker, command) {
|
|
180
|
+
let changed = false;
|
|
181
|
+
for (const entry of entries) {
|
|
182
|
+
if (!entry || typeof entry !== 'object') continue;
|
|
183
|
+
if (Array.isArray(entry.hooks)) {
|
|
184
|
+
for (const hook of entry.hooks) {
|
|
185
|
+
if (hook && hook.command && hook.command.includes(marker) && hook.command !== command) {
|
|
186
|
+
hook.command = command;
|
|
187
|
+
changed = true;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
} else if (entry.type === 'command' && entry.command && entry.command.includes(marker) && entry.command !== command) {
|
|
191
|
+
entry.command = command;
|
|
192
|
+
changed = true;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return changed;
|
|
196
|
+
}
|
|
197
|
+
|
|
171
198
|
const V7_REMOVED_CONVENTION_FILES = [
|
|
172
199
|
'conductor.md',
|
|
173
200
|
'coo-developer.md',
|
|
@@ -820,7 +847,7 @@ function installSessionHook() {
|
|
|
820
847
|
|
|
821
848
|
// Migrate any legacy flat entries (created by older walwal-harness versions)
|
|
822
849
|
// into the correct matcher + hooks-array shape that Claude Code expects.
|
|
823
|
-
const hookCmd = '
|
|
850
|
+
const hookCmd = harnessScriptCommand('harness-session-start.sh');
|
|
824
851
|
let migrated = false;
|
|
825
852
|
settings.hooks.SessionStart = settings.hooks.SessionStart
|
|
826
853
|
.map((entry) => {
|
|
@@ -845,6 +872,8 @@ function installSessionHook() {
|
|
|
845
872
|
)
|
|
846
873
|
);
|
|
847
874
|
|
|
875
|
+
const hookUpdated = replaceHarnessHookCommand(settings.hooks.SessionStart, 'harness-session-start', hookCmd);
|
|
876
|
+
|
|
848
877
|
if (!alreadyInstalled) {
|
|
849
878
|
settings.hooks.SessionStart.push({
|
|
850
879
|
matcher: '',
|
|
@@ -852,9 +881,9 @@ function installSessionHook() {
|
|
|
852
881
|
});
|
|
853
882
|
writeClaudeSettings(settings);
|
|
854
883
|
log('SessionStart hook installed in .claude/settings.json');
|
|
855
|
-
} else if (migrated) {
|
|
884
|
+
} else if (migrated || hookUpdated) {
|
|
856
885
|
writeClaudeSettings(settings);
|
|
857
|
-
log('SessionStart hook migrated
|
|
886
|
+
log('SessionStart hook migrated in .claude/settings.json');
|
|
858
887
|
} else {
|
|
859
888
|
log('SessionStart hook already installed');
|
|
860
889
|
}
|
|
@@ -872,16 +901,9 @@ function installStatusline() {
|
|
|
872
901
|
|
|
873
902
|
let settings = readClaudeSettings();
|
|
874
903
|
|
|
875
|
-
// Check if statusLine is already configured
|
|
876
|
-
if (settings.statusLine && settings.statusLine.command &&
|
|
877
|
-
settings.statusLine.command.includes('harness-statusline')) {
|
|
878
|
-
log('Statusline already installed');
|
|
879
|
-
return;
|
|
880
|
-
}
|
|
881
|
-
|
|
882
904
|
settings.statusLine = {
|
|
883
905
|
type: 'command',
|
|
884
|
-
command: '
|
|
906
|
+
command: harnessScriptCommand('harness-statusline.sh'),
|
|
885
907
|
refreshInterval: 3
|
|
886
908
|
};
|
|
887
909
|
|
|
@@ -904,7 +926,7 @@ function installUserPromptSubmitHook() {
|
|
|
904
926
|
if (!settings.hooks) settings.hooks = {};
|
|
905
927
|
if (!settings.hooks.UserPromptSubmit) settings.hooks.UserPromptSubmit = [];
|
|
906
928
|
|
|
907
|
-
const hookCmd = '
|
|
929
|
+
const hookCmd = harnessScriptCommand('harness-user-prompt-submit.sh');
|
|
908
930
|
|
|
909
931
|
// Detect existing harness UserPromptSubmit hook (any shape)
|
|
910
932
|
const alreadyInstalled = settings.hooks.UserPromptSubmit.some((entry) => {
|
|
@@ -920,6 +942,8 @@ function installUserPromptSubmitHook() {
|
|
|
920
942
|
return false;
|
|
921
943
|
});
|
|
922
944
|
|
|
945
|
+
const hookUpdated = replaceHarnessHookCommand(settings.hooks.UserPromptSubmit, 'harness-user-prompt-submit', hookCmd);
|
|
946
|
+
|
|
923
947
|
if (!alreadyInstalled) {
|
|
924
948
|
settings.hooks.UserPromptSubmit.push({
|
|
925
949
|
matcher: '',
|
|
@@ -930,6 +954,9 @@ function installUserPromptSubmitHook() {
|
|
|
930
954
|
log(' → /goal, /submission, and /hot-fix are guided through harness-ceo and CXX workflow');
|
|
931
955
|
log(' → Opt-out per message: say "harness skip" or "without harness"');
|
|
932
956
|
log(' → Disable globally: set .harness/config.json behavior.auto_route_ceo = false');
|
|
957
|
+
} else if (hookUpdated) {
|
|
958
|
+
writeClaudeSettings(settings);
|
|
959
|
+
log('UserPromptSubmit hook migrated in .claude/settings.json');
|
|
933
960
|
} else {
|
|
934
961
|
log('UserPromptSubmit hook already installed');
|
|
935
962
|
}
|
|
@@ -950,7 +977,7 @@ function installStopHook() {
|
|
|
950
977
|
if (!settings.hooks) settings.hooks = {};
|
|
951
978
|
if (!settings.hooks.Stop) settings.hooks.Stop = [];
|
|
952
979
|
|
|
953
|
-
const hookCmd = '
|
|
980
|
+
const hookCmd = harnessScriptCommand('harness-stop.sh');
|
|
954
981
|
|
|
955
982
|
const alreadyInstalled = settings.hooks.Stop.some((entry) => {
|
|
956
983
|
if (!entry || typeof entry !== 'object') return false;
|
|
@@ -965,6 +992,8 @@ function installStopHook() {
|
|
|
965
992
|
return false;
|
|
966
993
|
});
|
|
967
994
|
|
|
995
|
+
const hookUpdated = replaceHarnessHookCommand(settings.hooks.Stop, 'harness-stop', hookCmd);
|
|
996
|
+
|
|
968
997
|
if (!alreadyInstalled) {
|
|
969
998
|
settings.hooks.Stop.push({
|
|
970
999
|
matcher: '',
|
|
@@ -975,6 +1004,9 @@ function installStopHook() {
|
|
|
975
1004
|
log(' → Conductor 가 running 인 동안 turn 종료 시 자동으로 다음 tick 으로 연쇄');
|
|
976
1005
|
log(' → 비활성: .harness/config.json behavior.auto_chain_on_stop = false');
|
|
977
1006
|
log(' → 상한: behavior.auto_chain_max_per_sprint (기본 200)');
|
|
1007
|
+
} else if (hookUpdated) {
|
|
1008
|
+
writeClaudeSettings(settings);
|
|
1009
|
+
log('Stop hook migrated in .claude/settings.json');
|
|
978
1010
|
} else {
|
|
979
1011
|
log('Stop hook already installed');
|
|
980
1012
|
}
|
|
@@ -1227,6 +1259,7 @@ function detectMigrationNeeded() {
|
|
|
1227
1259
|
hrResourcePoolStale: false,
|
|
1228
1260
|
harnessMdStale: false,
|
|
1229
1261
|
agentsMissingOpsVerificationRules: false,
|
|
1262
|
+
agentsMissingCodexAdapterRules: false,
|
|
1230
1263
|
rosterCodexPathsMissing: false,
|
|
1231
1264
|
resourceIndexCodexWordingMissing: false,
|
|
1232
1265
|
memoryMissingSystemEntries: [],
|
|
@@ -1347,6 +1380,12 @@ function detectMigrationNeeded() {
|
|
|
1347
1380
|
) {
|
|
1348
1381
|
flags.agentsMissingOpsVerificationRules = true;
|
|
1349
1382
|
}
|
|
1383
|
+
if (
|
|
1384
|
+
!agentsBody.includes('Codex Runtime Adapter') &&
|
|
1385
|
+
!agentsBody.includes('.codex/skills/harness-ceo/SKILL.md')
|
|
1386
|
+
) {
|
|
1387
|
+
flags.agentsMissingCodexAdapterRules = true;
|
|
1388
|
+
}
|
|
1350
1389
|
} catch {}
|
|
1351
1390
|
}
|
|
1352
1391
|
if (fs.existsSync(rosterPath)) {
|
|
@@ -1852,6 +1891,32 @@ function runMigrate(opts = {}) {
|
|
|
1852
1891
|
}
|
|
1853
1892
|
}
|
|
1854
1893
|
|
|
1894
|
+
|
|
1895
|
+
if (flags.agentsMissingCodexAdapterRules) {
|
|
1896
|
+
const agentsPath = path.join(PROJECT_ROOT, 'AGENTS.md');
|
|
1897
|
+
if (fs.existsSync(agentsPath)) {
|
|
1898
|
+
const original = fs.readFileSync(agentsPath, 'utf8');
|
|
1899
|
+
const block = [
|
|
1900
|
+
'',
|
|
1901
|
+
'---',
|
|
1902
|
+
'',
|
|
1903
|
+
'## walwal-harness Codex Runtime Adapter',
|
|
1904
|
+
'',
|
|
1905
|
+
'- Codex does not require .codex/agents/; repo-local .codex/skills/**/SKILL.md files are the Codex runtime protocol.',
|
|
1906
|
+
'- For /goal, /submission, and /hot-fix, read .codex/commands/{goal,submission,hot-fix}.md and .codex/skills/harness-ceo/SKILL.md if Codex does not auto-load them.',
|
|
1907
|
+
'- Do not report walwal-harness as unavailable just because skills are not listed in the global Available Skills panel.',
|
|
1908
|
+
'- Emulate fresh CXX context by reading the role skill, active mission files, and required conventions/gotchas before writing that role\'s {cxx}.md.',
|
|
1909
|
+
''
|
|
1910
|
+
].join('\n');
|
|
1911
|
+
log(' AGENTS.md: Codex runtime adapter rules append');
|
|
1912
|
+
if (!dryRun) {
|
|
1913
|
+
fs.writeFileSync(path.join(backupDir, 'AGENTS.codex-adapter.md'), original);
|
|
1914
|
+
const sep = original.endsWith('\n') ? '' : '\n';
|
|
1915
|
+
fs.writeFileSync(agentsPath, original + sep + block);
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1855
1920
|
// 7. Bundle version stamp — record which package version was last applied.
|
|
1856
1921
|
if (flags.bundleVersionStale) {
|
|
1857
1922
|
const { current, installed } = flags.bundleVersionStale;
|
package/commands/goal.md
CHANGED
|
@@ -7,6 +7,11 @@ argument-hint: "<goal request>"
|
|
|
7
7
|
|
|
8
8
|
Route the Owner request to the installed `harness-ceo` agent/skill.
|
|
9
9
|
|
|
10
|
+
Codex adapter:
|
|
11
|
+
- If Codex does not auto-load `harness-ceo`, manually read `.codex/skills/harness-ceo/SKILL.md` and follow it.
|
|
12
|
+
- Absence of `.codex/agents/` is not a failure. `.codex/skills/**/SKILL.md` is the Codex runtime protocol.
|
|
13
|
+
- For CXX "fresh session context", use role-scoped context: read the CXX skill, active mission files, and required conventions/gotchas before writing that role's `{cxx}.md`.
|
|
14
|
+
|
|
10
15
|
Required flow:
|
|
11
16
|
1. Create or update a goal under `.harness/documents/goal-{goal_index}-{goal_name}/`.
|
|
12
17
|
2. Record CEO decisions in `.harness/documents/goal-{goal_index}-{goal_name}/ceo.md`.
|
package/commands/hot-fix.md
CHANGED
|
@@ -7,6 +7,11 @@ argument-hint: "<incident or fix request>"
|
|
|
7
7
|
|
|
8
8
|
Route the Owner request to the installed `harness-ceo` agent/skill as an emergency mission under the active goal.
|
|
9
9
|
|
|
10
|
+
Codex adapter:
|
|
11
|
+
- If Codex does not auto-load `harness-ceo`, manually read `.codex/skills/harness-ceo/SKILL.md` and follow it.
|
|
12
|
+
- Absence of `.codex/agents/` is not a failure. `.codex/skills/**/SKILL.md` is the Codex runtime protocol.
|
|
13
|
+
- For CXX "fresh session context", use role-scoped context: read the CXX skill, active mission files, and required conventions/gotchas before writing that role's `{cxx}.md`.
|
|
14
|
+
|
|
10
15
|
Required flow:
|
|
11
16
|
1. Locate the active goal document root under `.harness/documents/{goal_name}/`. If no active goal exists, CEO must create/select one before proceeding.
|
|
12
17
|
2. Create `.harness/documents/{goal_name}/hotfix-{hotfix_index}-{hotfix_name}/ceo.md`.
|
package/commands/submission.md
CHANGED
|
@@ -7,6 +7,11 @@ argument-hint: "<additional requirement>"
|
|
|
7
7
|
|
|
8
8
|
Route the Owner request to the installed `harness-ceo` agent/skill as an additional requirement under the active goal.
|
|
9
9
|
|
|
10
|
+
Codex adapter:
|
|
11
|
+
- If Codex does not auto-load `harness-ceo`, manually read `.codex/skills/harness-ceo/SKILL.md` and follow it.
|
|
12
|
+
- Absence of `.codex/agents/` is not a failure. `.codex/skills/**/SKILL.md` is the Codex runtime protocol.
|
|
13
|
+
- For CXX "fresh session context", use role-scoped context: read the CXX skill, active mission files, and required conventions/gotchas before writing that role's `{cxx}.md`.
|
|
14
|
+
|
|
10
15
|
Required flow:
|
|
11
16
|
1. Locate the active goal document root under `.harness/documents/{goal_name}/`. If no active goal exists, CEO must ask the Owner to create or select one with `/goal` before proceeding.
|
|
12
17
|
2. Create a submission record under `.harness/documents/{goal_name}/submission-{submission_index}-{submission_name}/`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walwal-harness/cli",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.25",
|
|
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"
|