@walwal-harness/cli 7.1.53 → 7.1.55

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.
@@ -62,12 +62,28 @@ acquire_dispatch_lock() {
62
62
  acquire_dispatch_lock
63
63
 
64
64
  spawn_mode="$(jq -r '.company_mode.worker_spawn // "claude"' "$CONFIG" 2>/dev/null || echo claude)"
65
+
66
+ # AGENTS.md Hard Rule 21 — every worker spawn declares its model explicitly.
67
+ # Never inherit the CLI default: a worker terminated by a usage limit looks
68
+ # exactly like a worker that finished, and without a declared model there is
69
+ # nothing to check the limit against. Falls back to the phase model from
70
+ # flow.team, then to opus.
71
+ resolve_worker_model() {
72
+ local phase="$1" model
73
+ model="$(jq -r --arg p "$phase" '
74
+ .company_mode.worker_model
75
+ // (if $p == "eval" then .flow.team.eval_model else .flow.team.gen_model end)
76
+ // empty' "$CONFIG" 2>/dev/null || true)"
77
+ [ -n "$model" ] && [ "$model" != "null" ] || model="opus"
78
+ printf '%s' "$model"
79
+ }
80
+
65
81
  pipeline="$(jq -r '.pipeline // "FULLSTACK"' "$PROGRESS" 2>/dev/null || echo FULLSTACK)"
66
82
  ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
67
83
  stamp="$(date -u +%Y%m%dT%H%M%SZ)"
68
84
 
69
85
  build_prompt() {
70
- local team="$1" fid="$2" agent="$3" prompt_path="$4" log_path="$5"
86
+ local team="$1" fid="$2" agent="$3" prompt_path="$4" log_path="$5" model="${6:-}"
71
87
  cat > "$prompt_path" <<EOF
72
88
  You are running as walwal-harness company worker.
73
89
 
@@ -75,9 +91,10 @@ Agent: harness-${agent}
75
91
  Worker slot: ${team}
76
92
  Feature ID: ${fid}
77
93
  Project root: ${PROJECT_ROOT}
94
+ Declared model: ${model:-unspecified}
78
95
 
79
96
  Follow these rules exactly:
80
- 1. Read AGENTS.md, CONVENTIONS.md if present, .harness/conventions/shared.md, .harness/conventions/${agent}.md if present, .harness/gotchas/${agent}.md if present, .harness/memory.md, .harness/progress.json, .harness/actions/feature-list.json, .harness/actions/api-contract.json, and the relevant harness skill for ${agent}.
97
+ 1. Lessons before plan. FIRST — before any source edit and before any measurement — read AGENTS.md, CONVENTIONS.md if present, .harness/conventions/shared.md, .harness/conventions/${agent}.md if present, .harness/gotchas/shared.md, .harness/gotchas/${agent}.md if present, .harness/memory.md, .harness/progress.json, .harness/actions/feature-list.json, .harness/actions/api-contract.json, and the relevant harness skill for ${agent}. Then write down which convention/gotcha items apply to FEATURE_ID=${fid} and why, and only then start work.
81
98
  2. Work only on FEATURE_ID=${fid}. Do not broaden scope.
82
99
  3. Respect IA ownership and do not edit files outside your department.
83
100
  4. Write a report to .harness/actions/gen-report-${fid}.md if you are a generator, or .harness/actions/evaluation-${fid}.md if you are an evaluator.
@@ -85,6 +102,8 @@ Follow these rules exactly:
85
102
  6. On failure, write the reason and run: bash scripts/harness-queue-manager.sh fail ${fid} "<short reason>"
86
103
  7. Use partial progress updates only via scripts/harness-progress-set.sh.
87
104
  8. Append real timestamped progress to .harness/progress.log. Never write future timestamps.
105
+ 9. End the report with a one-line tally naming which of the convention/gotcha items from step 1 actually fired. \`0 fired\` is a valid tally and must be stated, not omitted.
106
+ 10. Write the report incrementally as the work happens — create the file with its sections present up front and fill them in. If this session is killed mid-round, the report must still be a valid partial report, never a stub.
88
107
 
89
108
  This worker log is: ${log_path#$PROJECT_ROOT/}
90
109
  EOF
@@ -138,7 +157,8 @@ while [ "$i" -lt "$count" ]; do
138
157
  continue
139
158
  fi
140
159
 
141
- build_prompt "$team" "$fid" "$agent" "$prompt_path" "$log_path"
160
+ worker_model="$(resolve_worker_model "$phase")"
161
+ build_prompt "$team" "$fid" "$agent" "$prompt_path" "$log_path" "$worker_model"
142
162
 
143
163
  pid="null"
144
164
  tmux_session="null"
@@ -146,7 +166,7 @@ while [ "$i" -lt "$count" ]; do
146
166
  if [ "$spawn_mode" = "tmux" ] && command -v tmux >/dev/null 2>&1 && command -v claude >/dev/null 2>&1; then
147
167
  session_safe="$(basename "$PROJECT_ROOT" | tr -c '[:alnum:]_' '_')"
148
168
  session_name="walwal_${session_safe}_w${team}_${stamp}"
149
- if tmux new-session -d -s "$session_name" "cd '$PROJECT_ROOT' && claude -p \"\$(cat '$prompt_path')\" > '$log_path' 2>&1"; then
169
+ if tmux new-session -d -s "$session_name" "cd '$PROJECT_ROOT' && claude --dangerously-skip-permissions --model '$worker_model' -p \"\$(cat '$prompt_path')\" > '$log_path' 2>&1"; then
150
170
  pane_pid="$(tmux list-panes -t "$session_name" -F '#{pane_pid}' 2>/dev/null | head -n1)"
151
171
  if [ -n "$pane_pid" ]; then
152
172
  pid="$pane_pid"
@@ -160,22 +180,23 @@ while [ "$i" -lt "$count" ]; do
160
180
  # tmux requested but unavailable: fall back to background claude spawn
161
181
  (
162
182
  cd "$PROJECT_ROOT" || exit 1
163
- claude -p "$(cat "$prompt_path")" > "$log_path" 2>&1
183
+ claude --dangerously-skip-permissions --model "$worker_model" -p "$(cat "$prompt_path")" > "$log_path" 2>&1
164
184
  ) &
165
185
  pid="$!"
166
186
  status="spawned tmux-fallback-claude"
167
187
  elif [ "$spawn_mode" = "claude" ] && command -v claude >/dev/null 2>&1; then
168
188
  (
169
189
  cd "$PROJECT_ROOT" || exit 1
170
- claude -p "$(cat "$prompt_path")" > "$log_path" 2>&1
190
+ claude --dangerously-skip-permissions --model "$worker_model" -p "$(cat "$prompt_path")" > "$log_path" 2>&1
171
191
  ) &
172
192
  pid="$!"
173
193
  status="spawned"
174
194
  fi
175
195
 
176
196
  tmpq="${QUEUE}.tmp.$$.$i"
177
- jq --arg tid "$team" --arg agent "$agent" --arg phase "$phase" --arg prompt "$prompt_rel" --arg log "$log_rel" --arg status "$status" --argjson pid "$pid" --argjson tmux_session "$tmux_session" --arg ts "$ts" '
197
+ jq --arg tid "$team" --arg agent "$agent" --arg phase "$phase" --arg prompt "$prompt_rel" --arg log "$log_rel" --arg status "$status" --argjson pid "$pid" --argjson tmux_session "$tmux_session" --arg ts "$ts" --arg model "$worker_model" '
178
198
  .teams[$tid].pid = $pid |
199
+ .teams[$tid].model = $model |
179
200
  .teams[$tid].tmux_session = $tmux_session |
180
201
  .teams[$tid].agent = $agent |
181
202
  .teams[$tid].phase = $phase |
@@ -184,6 +205,7 @@ while [ "$i" -lt "$count" ]; do
184
205
  .teams[$tid].spawn_status = $status |
185
206
  .teams[$tid].started_at = $ts |
186
207
  .queue.in_progress[.teams[$tid].feature].agent = $agent |
208
+ .queue.in_progress[.teams[$tid].feature].model = $model |
187
209
  .queue.in_progress[.teams[$tid].feature].phase = $phase |
188
210
  .queue.in_progress[.teams[$tid].feature].prompt = $prompt |
189
211
  .queue.in_progress[.teams[$tid].feature].log = $log |
@@ -191,15 +213,15 @@ while [ "$i" -lt "$count" ]; do
191
213
  .queue.in_progress[.teams[$tid].feature].tmux_session = $tmux_session
192
214
  ' "$QUEUE" > "$tmpq" && mv "$tmpq" "$QUEUE"
193
215
 
194
- jq -n --argjson team "$team" --arg feature "$fid" --arg agent "$agent" --arg phase "$phase" --arg prompt "$prompt_rel" --arg log "$log_rel" --arg status "$status" --argjson pid "$pid" --argjson tmux_session "$tmux_session" \
195
- '{team:$team, feature:$feature, agent:$agent, phase:$phase, prompt:$prompt, log:$log, status:$status, pid:$pid, tmux_session:$tmux_session}' >> "$dispatches_file"
196
- echo "$ts | conductor | worker-dispatch | $status | T${team}/${fid} | $agent phase=$phase pid=$pid" >> "$PROJECT_ROOT/.harness/progress.log"
216
+ jq -n --argjson team "$team" --arg feature "$fid" --arg agent "$agent" --arg phase "$phase" --arg prompt "$prompt_rel" --arg log "$log_rel" --arg status "$status" --argjson pid "$pid" --argjson tmux_session "$tmux_session" --arg model "$worker_model" \
217
+ '{team:$team, feature:$feature, agent:$agent, phase:$phase, model:$model, prompt:$prompt, log:$log, status:$status, pid:$pid, tmux_session:$tmux_session}' >> "$dispatches_file"
218
+ echo "$ts | conductor | worker-dispatch | $status | T${team}/${fid} | $agent phase=$phase model=$worker_model pid=$pid" >> "$PROJECT_ROOT/.harness/progress.log"
197
219
  i=$((i + 1))
198
220
  done
199
221
 
200
222
  dispatches="$(jq -s '.' "$dispatches_file")"
201
223
  rm -f "$dispatches_file"
202
- active_workers="$(jq '[.teams | to_entries[] | select(.value.status == "busy") | {team:(.key|tonumber), feature:.value.feature, agent:.value.agent, pid:.value.pid, tmux_session:.value.tmux_session, phase:(.value.phase // "gen"), prompt:.value.prompt, log:.value.log, spawn_status:.value.spawn_status}]' "$QUEUE")"
224
+ active_workers="$(jq '[.teams | to_entries[] | select(.value.status == "busy") | {team:(.key|tonumber), feature:.value.feature, agent:.value.agent, model:.value.model, pid:.value.pid, tmux_session:.value.tmux_session, phase:(.value.phase // "gen"), prompt:.value.prompt, log:.value.log, spawn_status:.value.spawn_status}]' "$QUEUE")"
203
225
 
204
226
  jq --arg ts "$ts" --argjson dispatches "$dispatches" --argjson workers "$active_workers" '
205
227
  .company_state.active_workers = ($workers | length) |
@@ -11,14 +11,21 @@ mode="${2:-text}"
11
11
  scope="${3:-all}"
12
12
  violations=()
13
13
 
14
+ # Section-scoped reading (conventions/shared.md): match `^>?\s*#{1,6}` and take
15
+ # every hit — blockquoted or plain, at any depth, with no content filter. A
16
+ # heading anchored on `^#` alone misses the same heading quoted one level in,
17
+ # which is how in-place retractions and continuation lines get written.
18
+ HEADING2='^[[:space:]]*>?[[:space:]]*##[[:space:]]+'
19
+ HEADING3='^[[:space:]]*>?[[:space:]]*###[[:space:]]+'
20
+
14
21
  has_implementation_notes() {
15
22
  local file="$1"
16
23
  [ -s "$file" ] || return 1
17
- grep -Eq '^##[[:space:]]+Implementation Notes[[:space:]]*$' "$file" &&
18
- grep -Eq '^###[[:space:]]+Design Decisions[[:space:]]*$' "$file" &&
19
- grep -Eq '^###[[:space:]]+Deviations[[:space:]]*$' "$file" &&
20
- grep -Eq '^###[[:space:]]+Tradeoffs[[:space:]]*$' "$file" &&
21
- grep -Eq '^###[[:space:]]+Open Questions[[:space:]]*$' "$file"
24
+ grep -Eq "${HEADING2}Implementation Notes[[:space:]]*$" "$file" &&
25
+ grep -Eq "${HEADING3}Design Decisions[[:space:]]*$" "$file" &&
26
+ grep -Eq "${HEADING3}Deviations[[:space:]]*$" "$file" &&
27
+ grep -Eq "${HEADING3}Tradeoffs[[:space:]]*$" "$file" &&
28
+ grep -Eq "${HEADING3}Open Questions[[:space:]]*$" "$file"
22
29
  }
23
30
 
24
31
  has_worker_report() {