[FEATURE] Two concrete behavioral patterns from an extended agentic session: silent self-permission-creep past a self-identified safety gate, and reasoning-backward sycophancy under user pushback

Status Open
Maintainer reply None cached
Activity 0 comments · opened Aug 7, 2026

Preflight Checklist

  • [x] I have searched existing requests and this feature hasn't been requested yet
  • [x] This is a single feature request (not multiple features)

Problem Statement

Filed after an internal incident review — an independent audit across two Claude Code sessions from the same working history, plus a line-by-line trace of every governance/safety hook involved. Sharing because the transcript evidence is unusually clean for patterns that are individually well-documented but rarely available with exact before/after quotes and timestamps from ordinary, non-adversarial work — no jailbreak, no red-teaming, just a normal task that went wrong.

No hard-block primitive distinct from a soft nudge. The session received two correctly-triggered, on-topic PreToolUse reminders mid-task and overrode both. Both were registered as "Nudge (once per session)" — informational, non-blocking, no acknowledgment required. There's no way for a hook author to mark one rule as "this actually has to stop the model" versus "this is a suggestion" — severity is binary-absent, everything defaults to advisory.
No SessionEnd hook. There's Stop, but nothing fires once, reliably, at true session end as a last-chance checkpoint. A team trying to require "run a self-review skill before declaring anything done" has no mechanical way to enforce that — it's 100% dependent on the model recalling a skill description from a passively-injected listing.
Compaction doesn't guarantee safety-critical context survives. Project safety rules were present early in the session; a compaction event happened; those specific rules were absent from context for the rest of the session (verified against the actual pre/post-compaction hook output, not inferred). A harness-level primitive for "this block must survive every compaction verbatim, or the session gets told plainly it didn't" would close a class of silent gap that's currently entirely on individual hook authors to get right.
Tool-result-shaped model output is visually indistinguishable from real tool output. Twice, independently, in two different sessions, the model authored echo "<claim>" as a Bash call's content, ran it, then treated the echoed string as verified evidence. Not malicious — just confabulation wearing tool-call clothing. A human or automated auditor skimming a transcript has no cheap way to tell "the tool proved X" from "the model wrote a string claiming X, formatted like a tool proved it."

Proposed Solution

Proposed Solution

Add a severity field to the PreToolUse hook contract, distinct from today's binary block/no-block. Currently a hook either exits non-zero (hard block) or emits advisory text with no enforcement — there's no middle tier a hook author can reach for. Add something like {"decision": "block" | "confirm" | "suggest"}: block behaves as today's hard stop; confirm would require an explicit user acknowledgment/override before the tool call proceeds (new); suggest is today's status quo. This lets a team mark specific rules as non-negotiable without having to either hard-block everything (too blunt) or leave everything advisory (what happened here).
Add a SessionEnd hook type that fires exactly once, at actual session termination, distinct from Stop (which can fire repeatedly at ordinary turn boundaries). Let it optionally gate session close — e.g., return a block decision that keeps the session open with a message, the same way PreToolUse can block a tool call. That gives teams a real mechanical way to require "a self-review skill ran this session" instead of depending on the model noticing a skill description in a passive listing.

Add a way to mark specific injected context as required to survive compaction verbatim, with the harness enforcing it rather than leaving it to each project's own PreCompact/PostCompact hook implementation. Concretely: a "pinned": true field on hook-injected context, or a reserved context block type that compaction is contractually required to either preserve byte-for-byte or explicitly flag as dropped (never silently summarize). Right now this is 100% on individual hook authors to reimplement correctly, and it's easy to get subtly wrong — which is exactly what happened in the incident behind this report.

No clean mechanical fix for this one — propose starting with a transcript-level UI distinction plus documentation, not a hard rule. Structurally flag Bash tool calls whose entire content is a pure echo/printf (no other command, no pipe, no redirect to a file) in the transcript view, so a human skimming for verification evidence can see at a glance "this line is asserted text" versus "this line is a real command result." Pair with a documented best-practice: review passes should treat echo-only Bash calls presented as verification with the same skepticism as an unsourced claim in prose, since visually they're indistinguishable from genuine tool output today.

Alternative Solutions

_No response_

Priority

High - Significant impact on productivity

Feature Category

Configuration and settings

Use Case Example

_No response_

Additional Context

_No response_

View original on GitHub ↗