@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.
- package/CHANGELOG.md +13 -1
- package/HR-Resource/cdo/SKILL.md +30 -7
- package/HR-Resource/ceo/SKILL.md +20 -0
- package/HR-Resource/coo/SKILL.md +30 -7
- package/HR-Resource/cqo/SKILL.md +58 -7
- package/HR-Resource/cto/SKILL.md +46 -7
- package/HR-Resource/hiring/SKILL.md +14 -1
- package/HR-Resource/ops/SKILL.md +39 -8
- package/assets/templates/AGENTS.md.template +4 -1
- package/assets/templates/config.json +5 -1
- package/assets/templates/worker-report.md.template +16 -0
- package/bin/init.js +98 -1
- package/commands/goal.md +2 -0
- package/commands/hot-fix.md +4 -0
- package/commands/submission.md +2 -0
- package/conventions/cqo.md +2 -0
- package/conventions/ops.md +1 -0
- package/conventions/shared.md +15 -0
- package/gotchas/cqo.md +12 -0
- package/gotchas/cto.md +4 -0
- package/gotchas/ops.md +4 -0
- package/gotchas/shared.md +18 -0
- package/package.json +1 -1
- package/scripts/harness-hourly-review.sh +1 -1
- package/scripts/harness-lessons-gate.sh +130 -0
- package/scripts/harness-stop.sh +25 -1
- package/scripts/harness-user-prompt-submit.sh +1 -1
- package/scripts/harness-wake.sh +14 -7
- package/scripts/harness-worker-dispatch.sh +33 -11
- package/scripts/harness-worker-evidence-validate.sh +12 -5
|
@@ -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.
|
|
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
|
-
|
|
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
|
|
18
|
-
grep -Eq
|
|
19
|
-
grep -Eq
|
|
20
|
-
grep -Eq
|
|
21
|
-
grep -Eq
|
|
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() {
|