From a184c441e2b35a66ed972b9cd684aff0ff61b3ae Mon Sep 17 00:00:00 2001 From: nivSwisa1 Date: Tue, 10 Nov 2026 11:49:16 +0200 Subject: [PATCH 1/2] LINBEE-30104 | fix: show the effort verdict at every effort level (v1.5.2) Co-Authored-By: Claude Opus 5.5 --- .../.claude-plugin/plugin.json | 2 +- plugins/agentic-advisor/CHANGELOG.md | 6 +++ .../hooks/agentic-advisor-trigger.sh | 15 ++++++- plugins/agentic-advisor/hooks/hooks.json | 11 ++++++ .../skills/agentic-advisor/SKILL.md | 15 +++++-- tests/agentic-advisor/hooks_test.sh | 39 ++++++++++++++++++- 6 files changed, 81 insertions(+), 7 deletions(-) diff --git a/plugins/agentic-advisor/.claude-plugin/plugin.json b/plugins/agentic-advisor/.claude-plugin/plugin.json index 0ee1fc8..3fcf901 100644 --- a/plugins/agentic-advisor/.claude-plugin/plugin.json +++ b/plugins/agentic-advisor/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "agentic-advisor", - "version": "1.5.1", + "version": "1.5.2", "description": "Before writing code, grades how fragile the target is from LinearB health signals + local git history (rework, incidents, fix/revert density, code ownership) and reports whether it Reduced, Kept or Raised effort against the model's current level — lean on calm repos, defensive on fragile ones. Auto-triggers via a bundled hook and can report each effort decision to your LinearB org as usage telemetry.", "author": { "name": "LinearB", diff --git a/plugins/agentic-advisor/CHANGELOG.md b/plugins/agentic-advisor/CHANGELOG.md index 4b0c032..d5a709a 100644 --- a/plugins/agentic-advisor/CHANGELOG.md +++ b/plugins/agentic-advisor/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [1.5.2] - 2026-11-10 + +### Fixed + +- The verdict now shows up at every effort level. The skill records it with one `printf` call, and a new PostToolUse hook shows that line to the user. At low effort the model used to keep the verdict in its thinking, so nothing was shown or reported until the hold blocked an edit. + ## [1.5.1] - 2026-11-09 ### Fixed diff --git a/plugins/agentic-advisor/hooks/agentic-advisor-trigger.sh b/plugins/agentic-advisor/hooks/agentic-advisor-trigger.sh index f4d2d20..cf98119 100755 --- a/plugins/agentic-advisor/hooks/agentic-advisor-trigger.sh +++ b/plugins/agentic-advisor/hooks/agentic-advisor-trigger.sh @@ -17,6 +17,10 @@ # BACKSTOP - a code edit or subagent spawn is starting and this repo wasn't graded yet this # session. Catches tasks that slipped past the prompt gate. # +# PostToolUse (matcher Bash) +# SHOW - a `printf` verdict line ran: echo it as a systemMessage so the user sees it +# even when the Bash call is collapsed. +# # This NEVER does LinearB work itself and NEVER blocks. It only injects an # additionalContext nudge and always exits 0 (exit 2 on UserPromptSubmit would # erase the user's prompt). @@ -133,6 +137,15 @@ if [ -n "$session_id" ] && [ "${BASELINE_PCT:-0}" -gt 0 ] 2>/dev/null; then fi case "$event" in + PostToolUse) + cmd="$(jq -r '.tool_input.command // empty' <<<"$input" 2>/dev/null || true)" + case "$cmd" in *printf*"LinearB: "*) ;; *) exit 0 ;; esac + line="$(printf '%s\n' "$cmd" | grep -oE "> $GRADED_RE[^']*" | head -n 1)" + [ -n "$line" ] || exit 0 + jq -cn --arg m "$line" '{systemMessage: $m}' + dbg "PostToolUse: showed the verdict line to the user" + ;; + UserPromptSubmit) prompt="$(jq -r '.prompt // .user_input // empty' <<<"$input" 2>/dev/null || true)" [ -z "$prompt" ] && exit 0 @@ -234,7 +247,7 @@ case "$event" in printf '%s' "$((n + 1))" > "$held" 2>/dev/null || exit 0 dbg "PreToolUse: held $tool until a verdict line exists (hold $((n + 1)))" if skill_ran; then - reason="Your effort grade isn't recorded yet: print the verdict line itself, not a prose summary — > LinearB: — effort ( → ; ) — , or > LinearB: — Kept effort (; ) — (or run: printf '%s\\n' '> LinearB: …'). A skipped (not a code task) line doesn't count once you change code. Then make the same call again." + reason="Your effort grade isn't recorded yet (thinking and prose summaries don't count). Run this Bash call now with your grade filled in, then make the same call again: printf '%s\\n' '> LinearB: — effort ( → ; ) — ' (or '> LinearB: — Kept effort (; ) — ')." else reason="One quick first step before ${what}: run the \`agentic-advisor\` skill to grade this repo's effort.$skill_hint Print its verdict line (> LinearB: — effort ( → ; ) — , or > LinearB: — Kept effort (; ) — ), then make the same call again; this hold repeats until it's printed. If LinearB isn't available it just works at medium effort." fi diff --git a/plugins/agentic-advisor/hooks/hooks.json b/plugins/agentic-advisor/hooks/hooks.json index 4c6a213..061ab91 100644 --- a/plugins/agentic-advisor/hooks/hooks.json +++ b/plugins/agentic-advisor/hooks/hooks.json @@ -21,6 +21,17 @@ ] } ], + "PostToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { + "type": "command", + "command": "\"${CLAUDE_PLUGIN_ROOT}\"/hooks/agentic-advisor-trigger.sh" + } + ] + } + ], "Stop": [ { "hooks": [ diff --git a/plugins/agentic-advisor/skills/agentic-advisor/SKILL.md b/plugins/agentic-advisor/skills/agentic-advisor/SKILL.md index 37839b1..b7820fe 100644 --- a/plugins/agentic-advisor/skills/agentic-advisor/SKILL.md +++ b/plugins/agentic-advisor/skills/agentic-advisor/SKILL.md @@ -15,16 +15,23 @@ Your first Bash call starts with `printf 'enabled=%s effort=%s\n' "${LINEARB_AGE ## Output contract (read this first) -Right after the repo sweep, your first assistant text **must be this verdict line, verbatim in shape**, as a markdown blockquote: +Right after the repo sweep, your next step **must be one Bash call that prints this verdict line, verbatim in shape**: + +```bash +printf '%s\n' '> LinearB: — effort ( → ; ) — ' +``` + +The two shapes: > LinearB: — effort ( → ; ) — > LinearB: — Kept effort (; ) — - **A hook parses this exact line** to record the decision. Prose such as "repo health looks solid… I'll work harder" is not recognized: the decision is lost and nothing is reported. - `Raised effort` or `Reduced effort`, then in the parentheses the model's current level, `→`, and the level to work at; `Kept effort` shows only the current level. Levels are lowercase (`low`, `medium`, `high`, `xhigh`, `max`); see Effort Change. -- Explanation may follow on later lines, but the verdict line comes first and is never reworded. +- Always use the `printf` Bash call, at every effort level: a hook records it and shows it to the user. Text alone can end up only in thinking, where nothing sees it. +- Explanation may follow, but the verdict comes first and is never reworded. - **No code will change?** Print `> LinearB: — skipped (not a code task)` instead of a grade and stop (see the cheap exits). Nothing is reported. -- If you aren't writing visible text at this point, record it with one Bash call instead: `printf '%s\n' '> LinearB: — effort ( → ; ) — '` (or `Kept effort (; )`). If neither exists, a hook reminds you on your next file read or edit. +- If it's missing, a hook blocks your first edit until the `printf` call runs. Example: `> LinearB: api-service — Raised effort (medium → high; rework 3.4%, calm repo — but auth refactor with wide blast radius) — small behavior-preserving steps, tests green, confirm scope first.` @@ -303,7 +310,7 @@ HIGH effort — repo looks fragile, be careful: ## Human-Facing Note -The moment the **repo sweep** (including the ticket lookup, if any) returns — and **before any other tool call, and before spawning any Explore/subagent, reading, searching, `ls`/`find`, or editing code** — your next output MUST be this exact verdict line, **formatted as a markdown blockquote** (start it with `> ` so the terminal renders it with the left bar / emphasis and it stands out). Emit it as assistant text — do NOT wrap it in an `echo`/shell command or code fence (that hides it in a collapsed tool block). The one exception is the exact `printf '%s\n' '> LinearB: …'` Bash call from the Output contract, when you aren't writing visible text or the hook asks for it. Do not paraphrase it into prose like "LOW effort signals confirmed". This is the **repo-level verdict**; it is fully knowable from the sweep alone, so nothing else may happen first. Format: +The moment the **repo sweep** (including the ticket lookup, if any) returns — and **before any other tool call, and before spawning any Explore/subagent, reading, searching, `ls`/`find`, or editing code** — your next step MUST be the `printf '%s\n' '> LinearB: …'` Bash call from the Output contract, printing this exact verdict line (starting with `> `). Use `printf`, not `echo`, and nothing else in that call; a hook shows the line to the user. Do not paraphrase it into prose like "LOW effort signals confirmed". This is the **repo-level verdict**; it is fully knowable from the sweep alone, so nothing else may happen first. Format: ```text > LinearB: — effort ( → ; ) — diff --git a/tests/agentic-advisor/hooks_test.sh b/tests/agentic-advisor/hooks_test.sh index f9b5c7b..481734c 100755 --- a/tests/agentic-advisor/hooks_test.sh +++ b/tests/agentic-advisor/hooks_test.sh @@ -136,7 +136,7 @@ teardown # --- trigger: PreToolUse grade-before-edit hold --- names_skill_file() { jq -e '.hookSpecificOutput.permissionDecisionReason | contains("/skills/agentic-advisor/SKILL.md")' <<<"$out" >/dev/null; } -wants_line() { jq -e '.hookSpecificOutput.permissionDecisionReason | contains("not a prose summary")' <<<"$out" >/dev/null; } +wants_line() { jq -e '.hookSpecificOutput.permissionDecisionReason | (contains("prose summaries") and contains("printf"))' <<<"$out" >/dev/null; } setup run "$TRIGGER" PreToolUse "$(tool Edit app.js)" check "trigger: first source edit is held" denied @@ -473,6 +473,43 @@ for bad in "> LinearB: widgets — Raised effort (medium" "> LinearB: widgets teardown done +# PostToolUse: a printf verdict line is shown to the user as a systemMessage. +bash_cmd() { jq -cn --arg c "$1" '{tool_name:"Bash",tool_input:{command:$c}}' | sed 's/^{/,/; s/}$//'; } +shown() { [ "$rc" -eq 0 ] && [ "$(jq -r '.systemMessage // empty' <<<"$out")" = "$1" ]; } +add_printf() { jq -cn --arg c "printf '%s\\n' '$1'" '{message:{role:"assistant",content:[{type:"tool_use",name:"Bash",input:{command:$c}}]}}' >> "$TRANSCRIPT"; } +V1='> LinearB: widgets — Raised effort (low → high; rework 11.0% NEEDS FOCUS) — smallest change, tests per field.' +V2='> LinearB: widgets — Kept effort (high; rework 2.3%) — focused fix.' +V3='> LinearB: widgets — Reduced effort (max -> medium; rework 2.3%) — focused fix.' +for v in "$V1" "$V2" "$V3"; do + setup + run "$TRIGGER" PostToolUse "$(bash_cmd "printf '%s\\n' '$v'")" + check "show: printf verdict is shown: ${v:12:40}" shown "$v" + teardown +done +setup +run "$TRIGGER" PostToolUse "$(bash_cmd "ls -la && git status")" +check "show: an unrelated Bash call shows nothing" silent +run "$TRIGGER" PostToolUse "$(bash_cmd "printf '%s\\n' '> LinearB: — effort ( → ; ) — '")" +check "show: the template line itself shows nothing" silent +run "$TRIGGER" PostToolUse "$(bash_cmd "printf '%s\\n' '> LinearB: widgets — Raised effort (medium'")" +check "show: an incomplete verdict shows nothing" silent +LINEARB_AGENTIC_ADVISOR_ENABLED=off run "$TRIGGER" PostToolUse "$(bash_cmd "printf '%s\\n' '$V1'")" +check "show: off switch shows nothing" silent +teardown + +# Hold asks for the printf call; a printf verdict then unblocks the edit and is reported once. +setup +add_skill +run "$TRIGGER" PreToolUse "$(tool Edit app.js)" +check "hold: reason asks for the printf call" bash -c 'jq -e ".hookSpecificOutput.permissionDecisionReason | contains(\"printf\")" >/dev/null <<<"$1"' _ "$out" +add_printf "$V1" +run "$TRIGGER" PreToolUse "$(tool Edit app.js)" +check "hold: a printf verdict unblocks the edit" silent +run "$REPORT" Stop; await_calls 1 +check "report: the printf verdict is reported once" one_call +check "report: it is a raised decision to high" bash -c 'call_json() { cat "$1"/curl/call.* 2>/dev/null; }; call_json "$1" | jq -se "any(.[]; .tags.effort_change == \"raised\" and .tags.target_effort == \"high\")" >/dev/null' _ "$T" +teardown + printf '\n%d passed, %d failed\n' "$pass" "$fail" [ "$fail" -eq 0 ] From 53babf8ff3ce75be11e894123b3a0d7858f87017 Mon Sep 17 00:00:00 2001 From: nivSwisa1 Date: Tue, 10 Nov 2026 11:53:25 +0200 Subject: [PATCH 2/2] fix: shellcheck SC1087 in the verdict display, test helpers instead of bash -c Co-Authored-By: Claude Opus 5.5 --- plugins/agentic-advisor/hooks/agentic-advisor-trigger.sh | 2 +- tests/agentic-advisor/hooks_test.sh | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/agentic-advisor/hooks/agentic-advisor-trigger.sh b/plugins/agentic-advisor/hooks/agentic-advisor-trigger.sh index cf98119..4b46c53 100755 --- a/plugins/agentic-advisor/hooks/agentic-advisor-trigger.sh +++ b/plugins/agentic-advisor/hooks/agentic-advisor-trigger.sh @@ -140,7 +140,7 @@ case "$event" in PostToolUse) cmd="$(jq -r '.tool_input.command // empty' <<<"$input" 2>/dev/null || true)" case "$cmd" in *printf*"LinearB: "*) ;; *) exit 0 ;; esac - line="$(printf '%s\n' "$cmd" | grep -oE "> $GRADED_RE[^']*" | head -n 1)" + line="$(printf '%s\n' "$cmd" | grep -oE "> ${GRADED_RE}[^']*" | head -n 1)" [ -n "$line" ] || exit 0 jq -cn --arg m "$line" '{systemMessage: $m}' dbg "PostToolUse: showed the verdict line to the user" diff --git a/tests/agentic-advisor/hooks_test.sh b/tests/agentic-advisor/hooks_test.sh index 481734c..5750a54 100755 --- a/tests/agentic-advisor/hooks_test.sh +++ b/tests/agentic-advisor/hooks_test.sh @@ -476,6 +476,8 @@ done # PostToolUse: a printf verdict line is shown to the user as a systemMessage. bash_cmd() { jq -cn --arg c "$1" '{tool_name:"Bash",tool_input:{command:$c}}' | sed 's/^{/,/; s/}$//'; } shown() { [ "$rc" -eq 0 ] && [ "$(jq -r '.systemMessage // empty' <<<"$out")" = "$1" ]; } +asks_printf() { jq -e '.hookSpecificOutput.permissionDecisionReason | contains("printf")' <<<"$out" >/dev/null; } +raised_to_high() { call_json | jq -se 'any(.[]; .tags.effort_change == "raised" and .tags.target_effort == "high")' >/dev/null; } add_printf() { jq -cn --arg c "printf '%s\\n' '$1'" '{message:{role:"assistant",content:[{type:"tool_use",name:"Bash",input:{command:$c}}]}}' >> "$TRANSCRIPT"; } V1='> LinearB: widgets — Raised effort (low → high; rework 11.0% NEEDS FOCUS) — smallest change, tests per field.' V2='> LinearB: widgets — Kept effort (high; rework 2.3%) — focused fix.' @@ -501,13 +503,13 @@ teardown setup add_skill run "$TRIGGER" PreToolUse "$(tool Edit app.js)" -check "hold: reason asks for the printf call" bash -c 'jq -e ".hookSpecificOutput.permissionDecisionReason | contains(\"printf\")" >/dev/null <<<"$1"' _ "$out" +check "hold: reason asks for the printf call" asks_printf add_printf "$V1" run "$TRIGGER" PreToolUse "$(tool Edit app.js)" check "hold: a printf verdict unblocks the edit" silent run "$REPORT" Stop; await_calls 1 check "report: the printf verdict is reported once" one_call -check "report: it is a raised decision to high" bash -c 'call_json() { cat "$1"/curl/call.* 2>/dev/null; }; call_json "$1" | jq -se "any(.[]; .tags.effort_change == \"raised\" and .tags.target_effort == \"high\")" >/dev/null' _ "$T" +check "report: it is a raised decision to high" raised_to_high teardown