Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .claude/hooks/no-aggregator-hallucination.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,43 @@ if ! printf '%s' "$INPUT" | jq -e . >/dev/null 2>&1; then
exit 0
fi

# Rust path: prefer agentcloseout-physics when available.
if command -v agentcloseout-physics >/dev/null 2>&1; then
RULES_DIR="${LLM_DARK_PATTERNS_RULES_DIR:-}"
if [ -z "$RULES_DIR" ]; then
for candidate in \
"$(dirname "$0")/../../agent-closeout-bench/rules/closeout" \
"/home/fer/Documents/agent-closeout-bench/rules/closeout" \
"${XDG_CONFIG_HOME:-$HOME/.config}/agentcloseout-physics/rules/closeout"; do
if [ -d "$candidate" ]; then RULES_DIR="$candidate"; break; fi
done
fi
if [ -n "$RULES_DIR" ] && [ -d "$RULES_DIR" ] && [ -f "$RULES_DIR/no_aggregator_hallucination.yaml" ]; then
TMP_INPUT="$(mktemp)"; printf '%s' "$INPUT" > "$TMP_INPUT"
VERDICT_JSON="$(agentcloseout-physics scan --category no_aggregator_hallucination --rules "$RULES_DIR" --input "$TMP_INPUT" 2>/dev/null || true)"
rm -f "$TMP_INPUT"
if [ -n "$VERDICT_JSON" ]; then
DECISION="$(printf '%s' "$VERDICT_JSON" | jq -r '.decision // empty' 2>/dev/null)"
if [ "$DECISION" = "block" ]; then
RULE="$(printf '%s' "$VERDICT_JSON" | jq -r '.matched_rules[0].rule_id // "no_aggregator_hallucination"' 2>/dev/null)"
EVIDENCE="$(printf '%s' "$VERDICT_JSON" | jq -r '.redacted_evidence[0] // ""' 2>/dev/null)"
echo "BLOCKED: aggregator hallucination: synthesis claim without per-worker evidence." >&2
echo "Matched rule: $RULE" >&2
[ -n "$EVIDENCE" ] && echo "Evidence: $EVIDENCE" >&2
echo "" >&2
echo "Repair guidance:" >&2
echo "- Quote the per-worker output that justifies the synthesis (e.g. worker_1: pass, worker_2: pass)." >&2
echo "- Or drop the synthesis framing and report as a single agent's work." >&2
echo "- Or close as Status: partial / Verification: pending." >&2
exit 2
fi
if [ "$DECISION" = "pass" ]; then
exit 0
fi
fi
fi
fi

_HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ -f "$_HOOK_DIR/../lib/packs.sh" ]; then
# shellcheck source=../lib/packs.sh
Expand Down
37 changes: 37 additions & 0 deletions .claude/hooks/no-cherry-pick-rollup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,43 @@ if ! printf '%s' "$INPUT" | jq -e . >/dev/null 2>&1; then
exit 0
fi

# Rust path: prefer agentcloseout-physics when available.
if command -v agentcloseout-physics >/dev/null 2>&1; then
RULES_DIR="${LLM_DARK_PATTERNS_RULES_DIR:-}"
if [ -z "$RULES_DIR" ]; then
for candidate in \
"$(dirname "$0")/../../agent-closeout-bench/rules/closeout" \
"/home/fer/Documents/agent-closeout-bench/rules/closeout" \
"${XDG_CONFIG_HOME:-$HOME/.config}/agentcloseout-physics/rules/closeout"; do
if [ -d "$candidate" ]; then RULES_DIR="$candidate"; break; fi
done
fi
if [ -n "$RULES_DIR" ] && [ -d "$RULES_DIR" ] && [ -f "$RULES_DIR/no_cherry_pick_rollup.yaml" ]; then
TMP_INPUT="$(mktemp)"; printf '%s' "$INPUT" > "$TMP_INPUT"
VERDICT_JSON="$(agentcloseout-physics scan --category no_cherry_pick_rollup --rules "$RULES_DIR" --input "$TMP_INPUT" 2>/dev/null || true)"
rm -f "$TMP_INPUT"
if [ -n "$VERDICT_JSON" ]; then
DECISION="$(printf '%s' "$VERDICT_JSON" | jq -r '.decision // empty' 2>/dev/null)"
if [ "$DECISION" = "block" ]; then
RULE="$(printf '%s' "$VERDICT_JSON" | jq -r '.matched_rules[0].rule_id // "no_cherry_pick_rollup"' 2>/dev/null)"
EVIDENCE="$(printf '%s' "$VERDICT_JSON" | jq -r '.redacted_evidence[0] // ""' 2>/dev/null)"
echo "BLOCKED: cherry-pick rollup: partial worker success + positive closeout WITHOUT handling failed workers." >&2
echo "Matched rule: $RULE" >&2
[ -n "$EVIDENCE" ] && echo "Evidence: $EVIDENCE" >&2
echo "" >&2
echo "Repair guidance:" >&2
echo "- Explicitly handle failed workers (retried, blocking, ignored-with-reason)." >&2
echo "- Or close as Status: partial / Next step: investigate failed worker." >&2
echo "- Or drop the rollup framing and report only the verified-succeeded portion." >&2
exit 2
fi
if [ "$DECISION" = "pass" ]; then
exit 0
fi
fi
fi
fi

_HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ -f "$_HOOK_DIR/../lib/packs.sh" ]; then
# shellcheck source=../lib/packs.sh
Expand Down
38 changes: 38 additions & 0 deletions .claude/hooks/no-credential-leak-in-handoff.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,44 @@ if ! printf '%s' "$INPUT" | jq -e . >/dev/null 2>&1; then
exit 0
fi

# Rust path: only for Stop/SubagentStop. TaskCreated stays on bash path
# (the Rust v0.1 engine inspects last_assistant_message only; TaskCreated
# payload requires bash jq-based extraction of .task.description / .task.prompt).
EVENT_FILTER="$(printf '%s' "$INPUT" | jq -r '.hook_event_name // empty' 2>/dev/null)"
if command -v agentcloseout-physics >/dev/null 2>&1 && { [ "$EVENT_FILTER" = "Stop" ] || [ "$EVENT_FILTER" = "SubagentStop" ]; }; then
RULES_DIR="${LLM_DARK_PATTERNS_RULES_DIR:-}"
if [ -z "$RULES_DIR" ]; then
for candidate in \
"$(dirname "$0")/../../agent-closeout-bench/rules/closeout" \
"/home/fer/Documents/agent-closeout-bench/rules/closeout" \
"${XDG_CONFIG_HOME:-$HOME/.config}/agentcloseout-physics/rules/closeout"; do
if [ -d "$candidate" ]; then RULES_DIR="$candidate"; break; fi
done
fi
if [ -n "$RULES_DIR" ] && [ -d "$RULES_DIR" ] && [ -f "$RULES_DIR/no_credential_leak_in_handoff.yaml" ]; then
TMP_INPUT="$(mktemp)"; printf '%s' "$INPUT" > "$TMP_INPUT"
VERDICT_JSON="$(agentcloseout-physics scan --category no_credential_leak_in_handoff --rules "$RULES_DIR" --input "$TMP_INPUT" 2>/dev/null || true)"
rm -f "$TMP_INPUT"
if [ -n "$VERDICT_JSON" ]; then
DECISION="$(printf '%s' "$VERDICT_JSON" | jq -r '.decision // empty' 2>/dev/null)"
if [ "$DECISION" = "block" ]; then
RULE="$(printf '%s' "$VERDICT_JSON" | jq -r '.matched_rules[0].rule_id // "no_credential_leak_in_handoff"' 2>/dev/null)"
echo "BLOCKED: credential leak in closeout message." >&2
echo "Matched rule: $RULE" >&2
echo "" >&2
echo "Repair guidance:" >&2
echo "- Refer to credentials by env-var name (e.g. \$ANTHROPIC_API_KEY) instead of inlining the value." >&2
echo "- Or have the subagent read from a secrets manager." >&2
echo "- Reference: arXiv:2602.11510 AgentLeak benchmark." >&2
exit 2
fi
if [ "$DECISION" = "pass" ]; then
exit 0
fi
fi
fi
fi

json_get() { printf '%s' "$INPUT" | jq -r "$1 // empty" 2>/dev/null || true; }

block() {
Expand Down
37 changes: 37 additions & 0 deletions .claude/hooks/no-silent-worker-success.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,43 @@ if ! printf '%s' "$INPUT" | jq -e . >/dev/null 2>&1; then
exit 0
fi

# Rust path: prefer agentcloseout-physics when available.
if command -v agentcloseout-physics >/dev/null 2>&1; then
RULES_DIR="${LLM_DARK_PATTERNS_RULES_DIR:-}"
if [ -z "$RULES_DIR" ]; then
for candidate in \
"$(dirname "$0")/../../agent-closeout-bench/rules/closeout" \
"/home/fer/Documents/agent-closeout-bench/rules/closeout" \
"${XDG_CONFIG_HOME:-$HOME/.config}/agentcloseout-physics/rules/closeout"; do
if [ -d "$candidate" ]; then RULES_DIR="$candidate"; break; fi
done
fi
if [ -n "$RULES_DIR" ] && [ -d "$RULES_DIR" ] && [ -f "$RULES_DIR/no_silent_worker_success.yaml" ]; then
TMP_INPUT="$(mktemp)"; printf '%s' "$INPUT" > "$TMP_INPUT"
VERDICT_JSON="$(agentcloseout-physics scan --category no_silent_worker_success --rules "$RULES_DIR" --input "$TMP_INPUT" 2>/dev/null || true)"
rm -f "$TMP_INPUT"
if [ -n "$VERDICT_JSON" ]; then
DECISION="$(printf '%s' "$VERDICT_JSON" | jq -r '.decision // empty' 2>/dev/null)"
if [ "$DECISION" = "block" ]; then
RULE="$(printf '%s' "$VERDICT_JSON" | jq -r '.matched_rules[0].rule_id // "no_silent_worker_success"' 2>/dev/null)"
EVIDENCE="$(printf '%s' "$VERDICT_JSON" | jq -r '.redacted_evidence[0] // ""' 2>/dev/null)"
echo "BLOCKED: silent worker rollup: 'all N workers completed' claim without per-worker evidence." >&2
echo "Matched rule: $RULE" >&2
[ -n "$EVIDENCE" ] && echo "Evidence: $EVIDENCE" >&2
echo "" >&2
echo "Repair guidance:" >&2
echo "- Enumerate per-worker status (worker_1: exit=0, worker_2: exit=0, ...)." >&2
echo "- Or report only the workers whose output was verified." >&2
echo "- Or close as Status: partial / Verification: pending." >&2
exit 2
fi
if [ "$DECISION" = "pass" ]; then
exit 0
fi
fi
fi
fi

_HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ -f "$_HOOK_DIR/../lib/packs.sh" ]; then
# shellcheck source=../lib/packs.sh
Expand Down