mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
Fleet behaves more like Fable 5 on existing model tiers, behind ROBOCO_FABLE_MODE_ENABLED (config default off; armed :-true on the NAS compose, absent from the registry compose). - Doctrine: vendored agents/prompts/doctrine/fable.md composed into every agent's system prompt via fable_doctrine_layer() after base.md. - Hooks (Claude Code): 4 non-overlapping hooks (stop-gate/bash-discipline/ honesty-nudge/precompact) appended per-agent via _fable_hook_groups(). The make-quality + lint-suppression duplicates are deliberately NOT added (already gate-enforced); session-start skipped. - Hooks (grok): conservative V1 — only the non-denying honesty-nudge, since a grok hook deny cancels the whole run. - Flag on the feature-flags card; hook scripts shipped into the agent image. Flag-off spawn path proven byte-identical (worktree diff, sha256 match); full suite green (2074 unit + e2e-smoke + hook harness), mypy/xenon/ruff clean. Fixed a real stdin bug in the vendored stop-gate hook (heredoc + pipe both claimed stdin). Distilled from rennf93/opus-fable-playbook (MIT).
30 lines
1.4 KiB
Bash
Executable File
30 lines
1.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Fable honesty rule: when Bash output shows failures, nudge verbatim
|
|
# reporting. Ported from opus-fable-playbook hooks/honesty-nudge.sh (v0.1.3)
|
|
# — see docs/superpowers/plans/2026-07-04-v0.18.0-A-opus-fable-plan.md.
|
|
# PostToolUse[Bash], non-blocking (context injection only, never denies) —
|
|
# the one hook shipped to BOTH the Claude settings.json path (snake_case
|
|
# tool_response) and the grok hooks path (camelCase toolResponse candidate,
|
|
# unconfirmed by live spike; parsed defensively per bash-guard-hook.sh's
|
|
# existing tool_input/toolInput precedent — see Task 9/10 notes in the plan).
|
|
# Fail-open: any internal error => exit 0.
|
|
set -u
|
|
|
|
INPUT="$(cat)" || exit 0
|
|
RESP="$(printf '%s' "$INPUT" | python3 -c \
|
|
'import json,sys
|
|
d = json.load(sys.stdin)
|
|
print(json.dumps(d.get("tool_response") or d.get("toolResponse") or ""))' \
|
|
2>/dev/null || true)"
|
|
[ -z "$RESP" ] || [ "$RESP" = '""' ] && exit 0
|
|
|
|
HIT=0
|
|
printf '%s' "$RESP" | grep -qE 'FAILED |= FAILURES =|test result: FAILED|--- FAIL|AssertionError|Traceback \(most recent call last\)' && HIT=1
|
|
printf '%s' "$RESP" | grep -qE 'Tests:[^"]*failed' && HIT=1
|
|
[ "$HIT" -eq 0 ] && exit 0
|
|
|
|
cat <<'JSON'
|
|
{"hookSpecificOutput": {"hookEventName": "PostToolUse", "additionalContext": "A command just reported failures. Fable honesty rule: report this outcome verbatim (the actual failing output) in your final message; do not summarize it as mostly-working or claim success."}}
|
|
JSON
|
|
exit 0
|