@walwal-harness/cli 7.1.23 → 7.1.24

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 CHANGED
@@ -31,6 +31,15 @@ docmeta:
31
31
 
32
32
  ## Unreleased
33
33
 
34
+ ## 7.1.24 — Hourly CEO wake loop + migrate script refresh (2026-05-22)
35
+
36
+ ### Changed
37
+ - Hourly wake prompting now explicitly wakes CEO to convene CXX + OPS, collect current progress and decisions, dispatch one NOW action, and continue through CQO/OPS verification without asking Owner for next steps.
38
+ - Hourly wake prompts now include external executive-function scaffolding: body-doubling status checks, context-transition summaries, time-guardian hidden-task detection, and NOW/NEXT/PARKED open-loop triage.
39
+ - Hourly wake now supports `HARNESS_WAKE_MODEL` / `company_mode.hourly_wake_model` for Claude model pinning.
40
+ - `migrate` now refreshes package-owned runtime scripts, including `scripts/harness-wake.sh`, while archiving the previous target scripts directory.
41
+ - Dashboard Org Tree now uses a left-to-right depth layout while keeping zoom, ctrl/meta-wheel zoom, and drag panning.
42
+
34
43
  ## 7.1.23 — Dashboard CDO preview + radial org tree (2026-05-21)
35
44
 
36
45
  ### Added
package/README.md CHANGED
@@ -209,6 +209,13 @@ Features:
209
209
  - **Document tab** — per-CXX markdown doc viewer
210
210
  - **Owner Acceptance Gate** — Owner is final acceptance only; CEO/CXX must complete worker-backed verification before asking for Owner review
211
211
 
212
+ Hourly autonomous wake:
213
+
214
+ - `HARNESS_WAKE_EXECUTOR=claude|codex` selects `claude -p` or `codex exec`.
215
+ - `HARNESS_WAKE_MODEL=<model>` optionally pins the Claude model for wake ticks.
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
+ - `npx @walwal-harness/cli migrate` refreshes package-owned runtime scripts, so existing projects receive wake prompt updates without a full re-init.
218
+
212
219
  ---
213
220
 
214
221
  ## Harness Runtime Paths
@@ -243,29 +243,23 @@ export function OrgTree({ snapshot, activeNodeId, onNodeClick }: OrgTreeProps) {
243
243
  dragRef.current = null;
244
244
  }, []);
245
245
 
246
- const canvas = { width: 1160, height: 600 };
247
- const center = { x: 500, y: 240 };
246
+ const canvas = { width: 1280, height: 500 };
247
+ const ownerPos = { x: 70, y: 196 };
248
+ const ceoPos = { x: 320, y: 196 };
249
+ const cxxX = 610;
250
+ const workerX = 890;
248
251
 
249
252
  const layout = useMemo(() => {
250
- const cxxAngles = [-150, -78, 0, 78, 150];
251
- const cxxRadius = 280;
252
- const workerRadius = 150;
253
+ const startY = 50;
254
+ const rowGap = 86;
253
255
 
254
256
  return cxxNodes.map((node, index) => {
255
- const angle = (cxxAngles[index] * Math.PI) / 180;
256
- const x = center.x + Math.cos(angle) * cxxRadius;
257
- const y = center.y + Math.sin(angle) * cxxRadius * 0.58;
258
- const outwardX = Math.cos(angle) * workerRadius;
259
- const outwardY = Math.sin(angle) * workerRadius * 0.48;
260
- return {
261
- node,
262
- x,
263
- y,
264
- workerX: x + outwardX,
265
- workerY: y + outwardY,
266
- };
257
+ const nodeWorkers = workers.filter((w) => w.owner === node.role);
258
+ const y = startY + index * rowGap;
259
+ const workerHeight = Math.max(58, nodeWorkers.length * 54 + Math.max(0, nodeWorkers.length - 1) * 6);
260
+ return { node, x: cxxX, y, workerX, workerY: y - workerHeight / 2 + 30, nodeWorkers };
267
261
  });
268
- }, [cxxNodes]);
262
+ }, [cxxNodes, workers]);
269
263
 
270
264
  return (
271
265
  <div className="select-none">
@@ -329,48 +323,51 @@ export function OrgTree({ snapshot, activeNodeId, onNodeClick }: OrgTreeProps) {
329
323
  transform: `scale(${zoom})`,
330
324
  }}
331
325
  >
332
- <svg
333
- className="pointer-events-none absolute inset-0"
334
- width={canvas.width}
335
- height={canvas.height}
336
- >
337
- <line x1={center.x} y1={center.y - 26} x2={center.x} y2={center.y + 26} stroke="#374151" strokeWidth="1.5" />
338
- {layout.map(({ node, x, y }) => (
339
- <line
340
- key={node.id}
341
- x1={center.x}
342
- y1={center.y}
343
- x2={x}
344
- y2={y}
345
- stroke="#374151"
346
- strokeDasharray="4 5"
347
- strokeWidth="1.5"
348
- />
349
- ))}
350
- {layout.map(({ node, x, y, workerX, workerY }) => {
351
- const nodeWorkers = workers.filter((w) => w.owner === node.role);
352
- if (nodeWorkers.length === 0) return null;
353
- return (
354
- <line
355
- key={`${node.id}-workers`}
356
- x1={x}
357
- y1={y}
358
- x2={workerX}
359
- y2={workerY}
326
+ <svg className="pointer-events-none absolute inset-0" width={canvas.width} height={canvas.height}>
327
+ <path
328
+ d={`M ${ownerPos.x + 235} ${ownerPos.y + 56} H ${ceoPos.x}`}
329
+ stroke="#374151"
330
+ strokeWidth="1.5"
331
+ fill="none"
332
+ />
333
+ <path
334
+ d={`M ${ceoPos.x + 235} ${ceoPos.y + 56} H ${cxxX - 54}`}
335
+ stroke="#374151"
336
+ strokeWidth="1.5"
337
+ fill="none"
338
+ />
339
+ <path
340
+ d={`M ${cxxX - 54} ${layout[0]?.y ?? 80} V ${layout[layout.length - 1]?.y ?? 420}`}
341
+ stroke="#374151"
342
+ strokeWidth="1.5"
343
+ fill="none"
344
+ />
345
+ {layout.map(({ node, x, y, nodeWorkers }) => (
346
+ <g key={node.id}>
347
+ <path
348
+ d={`M ${x - 54} ${y} H ${x - 10}`}
360
349
  stroke="#374151"
350
+ strokeDasharray="4 5"
361
351
  strokeWidth="1.5"
352
+ fill="none"
362
353
  />
363
- );
364
- })}
354
+ {nodeWorkers.length > 0 && (
355
+ <path
356
+ d={`M ${x + 166} ${y} H ${workerX - 16}`}
357
+ stroke="#374151"
358
+ strokeWidth="1.5"
359
+ fill="none"
360
+ />
361
+ )}
362
+ </g>
363
+ ))}
365
364
  </svg>
366
365
 
367
- <div className="absolute left-[390px] top-[170px] grid w-[220px] gap-2">
368
- <OrgCard
369
- node={ownerNode}
370
- size="lg"
371
- active={activeNodeId === "owner"}
372
- onClick={onNodeClick}
373
- />
366
+ <div className="absolute" style={{ left: ownerPos.x, top: ownerPos.y }}>
367
+ <OrgCard node={ownerNode} size="lg" active={activeNodeId === "owner"} onClick={onNodeClick} />
368
+ </div>
369
+
370
+ <div className="absolute" style={{ left: ceoPos.x, top: ceoPos.y }}>
374
371
  <OrgCard
375
372
  node={ceoNode}
376
373
  size="lg"
@@ -379,8 +376,7 @@ export function OrgTree({ snapshot, activeNodeId, onNodeClick }: OrgTreeProps) {
379
376
  />
380
377
  </div>
381
378
 
382
- {layout.map(({ node, x, y, workerX, workerY }) => {
383
- const nodeWorkers = workers.filter((w) => w.owner === node.role);
379
+ {layout.map(({ node, x, y, workerX, workerY, nodeWorkers }) => {
384
380
  const hasActiveWorker = nodeWorkers.some((w) => w.active);
385
381
  const displayNode = hasActiveWorker
386
382
  ? { ...node, status: "typing" as const, activity: "Worker active" }
@@ -390,7 +386,7 @@ export function OrgTree({ snapshot, activeNodeId, onNodeClick }: OrgTreeProps) {
390
386
  <div
391
387
  key={node.id}
392
388
  className="absolute"
393
- style={{ left: x - 82, top: y - 38 }}
389
+ style={{ left: x, top: y - 38 }}
394
390
  >
395
391
  <OrgCard
396
392
  node={displayNode}
@@ -186,6 +186,8 @@
186
186
  "worker_spawn_description": "claude 이면 idle worker 배정 시 `claude -p` 백그라운드 프로세스를 띄운다. record 로 두면 prompt/log만 생성한다.",
187
187
  "hourly_wake_executor": "claude",
188
188
  "hourly_wake_executor_description": "claude 이면 `claude -p`, codex 이면 `codex exec` 로 매시간 autonomous tick 을 실행한다.",
189
+ "hourly_wake_model": "",
190
+ "hourly_wake_model_description": "Claude executor 에서 특정 모델을 강제하려면 HARNESS_WAKE_MODEL 또는 이 값을 사용한다. 비워두면 CLI 기본 모델을 사용한다.",
189
191
  "hourly_wake_mode": "headless",
190
192
  "hourly_wake_mode_description": "headless 는 백그라운드 실행, tmux 는 매시간 별도 tmux 세션, record 는 prompt/log만 생성한다.",
191
193
  "autonomous": true,
package/bin/init.js CHANGED
@@ -99,6 +99,19 @@ function copyDir(src, dest) {
99
99
  }
100
100
  }
101
101
 
102
+ function chmodShellScripts(dir) {
103
+ if (!fs.existsSync(dir)) return;
104
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
105
+ for (const entry of entries) {
106
+ const full = path.join(dir, entry.name);
107
+ if (entry.isDirectory()) {
108
+ chmodShellScripts(full);
109
+ } else if (entry.name.endsWith('.sh')) {
110
+ try { fs.chmodSync(full, '755'); } catch (e) {}
111
+ }
112
+ }
113
+ }
114
+
102
115
  function fileExists(p) {
103
116
  return fs.existsSync(p);
104
117
  }
@@ -728,25 +741,29 @@ function installScripts() {
728
741
 
729
742
  if (fs.existsSync(scriptsSrc)) {
730
743
  copyDir(scriptsSrc, scriptsDest);
731
-
732
- // chmod +x for all .sh files (recursive)
733
- function chmodRecursive(dir) {
734
- const entries = fs.readdirSync(dir, { withFileTypes: true });
735
- for (const entry of entries) {
736
- const full = path.join(dir, entry.name);
737
- if (entry.isDirectory()) {
738
- chmodRecursive(full);
739
- } else if (entry.name.endsWith('.sh')) {
740
- try { fs.chmodSync(full, '755'); } catch (e) {}
741
- }
742
- }
743
- }
744
- chmodRecursive(scriptsDest);
744
+ chmodShellScripts(scriptsDest);
745
745
  }
746
746
 
747
747
  log('Scripts installation complete');
748
748
  }
749
749
 
750
+ function refreshScriptsForMigrate({ dryRun = false, backupDir = null } = {}) {
751
+ const scriptsSrc = path.join(PKG_ROOT, 'scripts');
752
+ const scriptsDest = path.join(PROJECT_ROOT, 'scripts');
753
+ if (!fs.existsSync(scriptsSrc)) return;
754
+
755
+ log(' scripts/: package runtime scripts refresh');
756
+ if (dryRun) return;
757
+
758
+ if (backupDir && fs.existsSync(scriptsDest)) {
759
+ const scriptsBackup = path.join(backupDir, 'scripts');
760
+ copyDir(scriptsDest, scriptsBackup);
761
+ }
762
+
763
+ copyDir(scriptsSrc, scriptsDest);
764
+ chmodShellScripts(scriptsDest);
765
+ }
766
+
750
767
  // ─────────────────────────────────────────
751
768
  // 3a. Commands → .claude/commands/
752
769
  // ─────────────────────────────────────────
@@ -1205,6 +1222,7 @@ function detectMigrationNeeded() {
1205
1222
  configMissingCompanyMode: false,
1206
1223
  configLegacyRouting: false,
1207
1224
  configRuntimeVerificationMissing: false,
1225
+ configWakeModelMissing: false,
1208
1226
  coreSkillsStale: false,
1209
1227
  hrResourcePoolStale: false,
1210
1228
  harnessMdStale: false,
@@ -1307,6 +1325,9 @@ function detectMigrationNeeded() {
1307
1325
  if (!c.runtime?.verification?.watch_during_cqo || !c.runtime?.verification?.require_ops_evidence_for_pass) {
1308
1326
  flags.configRuntimeVerificationMissing = true;
1309
1327
  }
1328
+ if (c.company_mode && c.company_mode.hourly_wake_model === undefined) {
1329
+ flags.configWakeModelMissing = true;
1330
+ }
1310
1331
  if (
1311
1332
  c.behavior?.auto_route_dispatcher !== undefined ||
1312
1333
  c.behavior?.auto_route_dispatcher_description ||
@@ -1439,6 +1460,10 @@ function showMigrationProposal(flags) {
1439
1460
  console.log(' • config.json: runtime.verification 섹션 추가 가능');
1440
1461
  console.log(' CQO 검수 중 OPS runtime watch 와 PASS 차단 조건을 설정합니다.');
1441
1462
  }
1463
+ if (flags.configWakeModelMissing) {
1464
+ console.log(' • config.json: company_mode.hourly_wake_model 추가 가능');
1465
+ console.log(' Claude wake tick 에서 --model 을 환경변수/설정으로 지정할 수 있습니다.');
1466
+ }
1442
1467
  if (flags.configLegacyRouting) {
1443
1468
  console.log(' • config.json: legacy dispatcher/conductor wording → v7 CEO/CXX wording');
1444
1469
  }
@@ -1499,11 +1524,13 @@ function runMigrate(opts = {}) {
1499
1524
  // Always refresh owner-facing commands (full replacement regardless of current state).
1500
1525
  if (dryRun) {
1501
1526
  log(' (dry-run) commands: /goal, /submission, /hot-fix 교체 예정');
1527
+ log(' (dry-run) scripts/: package runtime scripts refresh 예정');
1502
1528
  } else {
1503
1529
  installCommands();
1504
1530
  }
1505
1531
 
1506
1532
  const flags = detectMigrationNeeded();
1533
+ const runtimeScriptsAlwaysRefresh = true;
1507
1534
  const gotchaMissingTotal = Object.values(flags.gotchaMissingEntries || {}).reduce((n, a) => n + a.length, 0);
1508
1535
  const conventionMissingTotal = Object.values(flags.conventionMissingEntries || {}).reduce((n, a) => n + a.length, 0);
1509
1536
  if (
@@ -1512,6 +1539,7 @@ function runMigrate(opts = {}) {
1512
1539
  !flags.configMissingCompanyMode &&
1513
1540
  !flags.configLegacyRouting &&
1514
1541
  !flags.configRuntimeVerificationMissing &&
1542
+ !flags.configWakeModelMissing &&
1515
1543
  !flags.coreSkillsStale &&
1516
1544
  !flags.hrResourcePoolStale &&
1517
1545
  !flags.harnessMdStale &&
@@ -1521,7 +1549,8 @@ function runMigrate(opts = {}) {
1521
1549
  (!flags.memoryMissingSystemEntries || flags.memoryMissingSystemEntries.length === 0) &&
1522
1550
  gotchaMissingTotal === 0 &&
1523
1551
  conventionMissingTotal === 0 &&
1524
- !flags.bundleVersionStale
1552
+ !flags.bundleVersionStale &&
1553
+ !runtimeScriptsAlwaysRefresh
1525
1554
  ) {
1526
1555
  console.log('');
1527
1556
  let pkgVer = 'unknown';
@@ -1537,6 +1566,10 @@ function runMigrate(opts = {}) {
1537
1566
  const backupDir = path.join(HARNESS_DIR, 'archive', `migration-${ts}`);
1538
1567
  if (!dryRun) ensureDir(backupDir);
1539
1568
 
1569
+ // Runtime scripts are package-owned. Migrate must refresh them so existing
1570
+ // projects receive wake/meeting/OPS fixes without requiring a full init.
1571
+ refreshScriptsForMigrate({ dryRun, backupDir });
1572
+
1540
1573
  // 1. progress.json
1541
1574
  const progressPath = path.join(HARNESS_DIR, 'progress.json');
1542
1575
  if ((flags.progressV3toV4 || flags.progressLegacyRouting) && fs.existsSync(progressPath)) {
@@ -1568,10 +1601,11 @@ function runMigrate(opts = {}) {
1568
1601
  // 2. config.json — inject company_mode/runtime verification from template if missing
1569
1602
  const configPath = path.join(HARNESS_DIR, 'config.json');
1570
1603
  const tplPath = path.join(PKG_ROOT, 'assets', 'templates', 'config.json');
1571
- if ((flags.configMissingCompanyMode || flags.configLegacyRouting || flags.configRuntimeVerificationMissing) && fs.existsSync(configPath) && fs.existsSync(tplPath)) {
1604
+ if ((flags.configMissingCompanyMode || flags.configLegacyRouting || flags.configRuntimeVerificationMissing || flags.configWakeModelMissing) && fs.existsSync(configPath) && fs.existsSync(tplPath)) {
1572
1605
  const original = fs.readFileSync(configPath, 'utf8');
1573
1606
  const c = JSON.parse(original);
1574
1607
  const tpl = JSON.parse(fs.readFileSync(tplPath, 'utf8'));
1608
+ let configChanged = false;
1575
1609
  if (tpl.company_mode) {
1576
1610
  if (flags.configMissingCompanyMode || flags.configLegacyRouting) {
1577
1611
  c.company_mode = {
@@ -1588,14 +1622,23 @@ function runMigrate(opts = {}) {
1588
1622
  delete c.behavior.auto_route_dispatcher;
1589
1623
  delete c.behavior.auto_route_dispatcher_description;
1590
1624
  delete c.mode_selection;
1625
+ configChanged = true;
1591
1626
  log(' config.json: v7 CEO/CXX routing 섹션 동기화');
1592
1627
  }
1628
+ if (flags.configWakeModelMissing) {
1629
+ c.company_mode = c.company_mode || {};
1630
+ c.company_mode.hourly_wake_model = tpl.company_mode.hourly_wake_model ?? '';
1631
+ c.company_mode.hourly_wake_model_description = tpl.company_mode.hourly_wake_model_description;
1632
+ configChanged = true;
1633
+ log(' config.json: hourly_wake_model 섹션 동기화');
1634
+ }
1593
1635
  if (flags.configRuntimeVerificationMissing && tpl.runtime?.verification) {
1594
1636
  c.runtime = c.runtime || {};
1595
1637
  c.runtime.verification = deepMerge(tpl.runtime.verification, c.runtime.verification || {});
1638
+ configChanged = true;
1596
1639
  log(' config.json: runtime.verification 섹션 동기화');
1597
1640
  }
1598
- if (!dryRun) {
1641
+ if (!dryRun && configChanged) {
1599
1642
  fs.writeFileSync(path.join(backupDir, 'config.json'), original);
1600
1643
  fs.writeFileSync(configPath, JSON.stringify(c, null, 2) + '\n');
1601
1644
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@walwal-harness/cli",
3
- "version": "7.1.23",
3
+ "version": "7.1.24",
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"
@@ -130,10 +130,17 @@ start_headless_tick() {
130
130
  local idle="$2"
131
131
  local force="$3"
132
132
  local review_path="$4"
133
- local mode executor agent_bin stamp wake_dir ops_dir prompt_rel log_rel prompt_path log_path pid_file old_pid pid status tmux_session session_name session_safe
133
+ local mode executor wake_model agent_bin stamp wake_dir ops_dir prompt_rel log_rel prompt_path log_path pid_file old_pid pid status tmux_session session_name session_safe
134
134
 
135
- mode="${HARNESS_WAKE_MODE:-headless}"
136
- executor="${HARNESS_WAKE_EXECUTOR:-claude}"
135
+ if command -v jq >/dev/null 2>&1 && [ -f "$project_root/.harness/config.json" ]; then
136
+ mode="${HARNESS_WAKE_MODE:-$(jq -r '.company_mode.hourly_wake_mode // "headless"' "$project_root/.harness/config.json" 2>/dev/null || echo headless)}"
137
+ executor="${HARNESS_WAKE_EXECUTOR:-$(jq -r '.company_mode.hourly_wake_executor // "claude"' "$project_root/.harness/config.json" 2>/dev/null || echo claude)}"
138
+ wake_model="${HARNESS_WAKE_MODEL:-$(jq -r '.company_mode.hourly_wake_model // ""' "$project_root/.harness/config.json" 2>/dev/null || true)}"
139
+ else
140
+ mode="${HARNESS_WAKE_MODE:-headless}"
141
+ executor="${HARNESS_WAKE_EXECUTOR:-claude}"
142
+ wake_model="${HARNESS_WAKE_MODEL:-}"
143
+ fi
137
144
  stamp="$(date -u "+%Y%m%dT%H%M%SZ")"
138
145
  wake_dir="$project_root/.harness/actions/wake"
139
146
  ops_dir="$project_root/.harness/ops/wake"
@@ -154,28 +161,58 @@ start_headless_tick() {
154
161
  fi
155
162
 
156
163
  cat > "$prompt_path" <<EOF
157
- You are the walwal-harness autonomous hourly wake tick.
164
+ You are harness-ceo waking for the walwal-harness hourly executive loop.
158
165
 
159
166
  Project root: $project_root
160
167
  Wake reason: idle=${idle}s force=${force}
161
168
  Hourly review: ${review_path:-"(not available)"}
162
169
 
170
+ One-line command:
171
+ Convene CXX + OPS, collect current progress and decisions, decide the next action as CEO with the active goal in mind, drive all teams without asking Owner, and use CQO verification until the goal demonstrably works.
172
+
163
173
  Policy:
164
- - Owner input after the initial GOAL is an interrupt or additional request, never a reason to wait.
174
+ - Owner already provided the GOAL. Owner input after the initial GOAL is an interrupt or additional request, never a reason to wait.
175
+ - Do not ask Owner what to do next. Convert uncertainty into CXX/OPS tasks, CQO checks, or a bounded assumption written to artifacts.
165
176
  - Never set conductor.state to waiting_owner. Normalize any waiting_owner state to waiting_meeting and continue.
166
- - meeting-manager is the default synchronization loop. Incidents, service warnings, goal drift, and escalations go to meeting-manager first.
177
+ - meeting-manager is the synchronization loop, not the stopping point. Incidents, service warnings, goal drift, and escalations go to meeting-manager first, then route execution.
167
178
  - Keep this to one bounded autonomous tick. Do not run an endless loop.
168
179
  - Do not write future timestamps to .harness/progress.log or artifacts.
169
180
  - Keep terminal output concise; write evidence to project files.
181
+ - Treat paperwork-only output as insufficient. A meeting that does not create or advance executable next actions is incomplete.
182
+
183
+ ADHD/autonomy support pattern:
184
+ - Act as an external executive-function scaffold: break blocked work into tiny executable next steps, name the first action, and start it.
185
+ - Use body-doubling behavior: check the active work state, ask each role for a concise status through artifacts, and keep the loop moving.
186
+ - Use context-transition support: summarize what just finished, what starts next, and the handoff artifact path.
187
+ - Use time-guardian behavior: identify hidden sub-tasks that make the work longer than expected, set a realistic next checkpoint, and avoid vague "later" states.
188
+ - Use open-loop triage: classify discovered work as NOW / NEXT / PARKED. Execute or dispatch NOW items only.
170
189
 
171
190
  Tasks:
172
191
  1. Read CONVENTIONS.md if present, .harness/conventions/shared.md, relevant .harness/conventions/<role>.md, .harness/gotchas/<role>.md, .harness/memory.md, .harness/progress.json, and the hourly review above.
173
- 2. If service_ops.requested_mode is monitor, run or trigger one service-ops monitor pass and record last_check. stream_active may be true only during the pass and must be false when finished.
174
- 3. Treat the hourly review as Executive Meeting Minutes. Verify it contains CEO/COO/CTO/CQO/Service-Ops role positions, discussion, decision JSON, and action items.
175
- 4. Check conductor state against the current GOAL and route the next department without waiting for Owner.
176
- 5. If there is an active incident or operational warning, make sure meeting-manager has shared context and an action decision that names CTO/CQO/Service-Ops responsibilities.
177
- 6. Split meaningful progress from paperwork-only artifacts in your summary.
178
- 7. Append a short factual summary to .harness/progress.log and any normal harness artifacts used by this project.
192
+ 2. Determine the active GOAL/submission/hot-fix from progress.json and .harness/documents. Restate it in one sentence for yourself.
193
+ 3. Convene the executive loop through artifacts: CEO + COO + CDO + CTO + CQO + OPS. Collect only concise status, blocker, decision-needed, and evidence-path information.
194
+ 4. If service_ops.requested_mode is monitor, run or trigger one service-ops monitor pass and record last_check. stream_active may be true only during the pass and must be false when finished.
195
+ 5. Treat the hourly review as Executive Meeting Minutes. Verify it contains role positions, discussion, decision JSON, action items, and CQO/OPS evidence requirements.
196
+ 6. As CEO, decide exactly one NOW action package:
197
+ - owner CXX/role,
198
+ - action_type,
199
+ - deliverable_path,
200
+ - success_condition,
201
+ - verifier, preferably CQO when goal behavior must be proven.
202
+ 7. Route all teams needed for that NOW action. Do not stop after hiring, planning, status reporting, or meeting note creation.
203
+ 8. Use CQO to verify whether the goal is actually satisfied. If verification fails or is missing, route implementation/fix work again.
204
+ 9. If there is an active incident or operational warning, make sure meeting-manager has shared context and an action decision that names CTO/CQO/OPS responsibilities.
205
+ 10. Split meaningful progress from paperwork-only artifacts in your summary.
206
+ 11. Append a short factual summary to .harness/progress.log and update normal harness artifacts used by this project.
207
+
208
+ Required final shape for this tick:
209
+ - GOAL:
210
+ - CXX/OPS status collected:
211
+ - CEO decision:
212
+ - NOW action dispatched:
213
+ - CQO/OPS verification required:
214
+ - NEXT checkpoint:
215
+ - Evidence paths:
179
216
  EOF
180
217
 
181
218
  case "$mode" in
@@ -189,7 +226,11 @@ EOF
189
226
  if [ "$executor" = "codex" ]; then
190
227
  "$agent_bin" exec -C "$project_root" "$(cat "$prompt_path")" > "$log_path" 2>&1
191
228
  else
192
- "$agent_bin" -p "$(cat "$prompt_path")" > "$log_path" 2>&1
229
+ if [ -n "$wake_model" ]; then
230
+ "$agent_bin" -p "$(cat "$prompt_path")" --model "$wake_model" > "$log_path" 2>&1
231
+ else
232
+ "$agent_bin" -p "$(cat "$prompt_path")" > "$log_path" 2>&1
233
+ fi
193
234
  fi
194
235
  ) &
195
236
  pid=$!
@@ -208,7 +249,11 @@ EOF
208
249
  if [ "$executor" = "codex" ]; then
209
250
  tmux new-session -d -s "$session_name" "cd '$project_root' && '$agent_bin' exec -C '$project_root' - < '$prompt_path' 2>&1 | tee '$log_path'"
210
251
  else
211
- tmux new-session -d -s "$session_name" "cd '$project_root' && '$agent_bin' -p \"\$(cat '$prompt_path')\" 2>&1 | tee '$log_path'"
252
+ if [ -n "$wake_model" ]; then
253
+ tmux new-session -d -s "$session_name" "cd '$project_root' && '$agent_bin' -p \"\$(cat '$prompt_path')\" --model '$wake_model' 2>&1 | tee '$log_path'"
254
+ else
255
+ tmux new-session -d -s "$session_name" "cd '$project_root' && '$agent_bin' -p \"\$(cat '$prompt_path')\" 2>&1 | tee '$log_path'"
256
+ fi
212
257
  fi
213
258
  status="spawned-tmux executor=$executor session=$session_name"
214
259
  else