Skip to main content
plugin

llm-dark-patterns — Claude Code plugin: hooks against dark patterns

Ten hooks that inspect Claude's outgoing text and block sycophancy, false-success closeouts and invented numbers before they reach you.

Install into Claude Code · Plugin marketplace All methods and platforms ↓
/plugin marketplace add anthropics/claude-plugins-community
/plugin install llm-dark-patterns@claude-community
Open on GitHub

What llm-dark-patterns does

The plugin attaches hooks at Claude boundaries and judges the model's outgoing text with deterministic code rather than another LLM call. Three branches ship together: interaction style, fact fabrication, and continuity. The style branch catches false-success closeouts, training-cutoff confusion, unsolicited paternalism, praise at the start of a turn, and dangling permission-loop endings. The fabrication branch flags claims about earlier conversation without a quoted passage, percentages with no source, and academic citations with no verifiable URL. The continuity hook, no-amnesia, snapshots working state on Stop, PreCompact and PostCompact, then rehydrates it on SessionStart so context survives auto-compaction.

Each hook stays conservative on purpose, and its RECEIPTS.md documents the allow-clauses where it steps back. Because the judge is code, the model cannot rewrite the hook's path from inside its own closeout. That is not the same as being unbypassable — paraphrase, a bad config or an evasion attempt can still get past it.

Coverage grows without forking. Drop a .txt file into ${XDG_CONFIG_HOME:-$HOME/.config}/llm-dark-patterns/packs/<subdir>/<name>.txt to add a non-English session, an unfamiliar toolchain, or a destructive surface such as kubectl, terraform, redis FLUSHALL or a force-push to main.

What it helps with

  • block a success report with no evidence behind the checkmarks
  • flag an invented percentage with no source
  • stop praise from opening the reply
  • keep working state across auto-compaction
  • reject a reference to an earlier turn with no quoted text

Example prompts for the agent

  • Check that the task report has evidence, not just checkmarks
  • Don't invent percentages — say so if there's no source
  • Snapshot the working state before context compaction

How to install llm-dark-patterns

Plugin marketplace

/plugin marketplace add anthropics/claude-plugins-community
/plugin install llm-dark-patterns@claude-community

Step by step, with commands for each platform: Claude Code plugins: marketplaces, installing, and building your own

Questions about llm-dark-patterns

How do I install llm-dark-patterns in Claude Code?

Add the marketplace first: /plugin marketplace add anthropics/claude-plugins-community. Then install the plugin: /plugin install llm-dark-patterns@claude-community.

What does llm-dark-patterns do?

It bundles ten hooks that inspect Claude's outgoing text and block dark patterns: sycophancy, false success, fabricated numbers and citations, and dangling endings. A separate hook, no-amnesia, saves and restores working state when context is compacted.

How is this different from anti-sycophancy skills?

Skills and system-prompt calibrators sit inside the model's reasoning loop and can drift over a long session. Here the judge is deterministic code at the hook boundary, so the model cannot change its path from its own text.

Source text

SKILL.md · Apache-2.0
# LLM Dark Patterns Hooks

[![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
[![tests](https://github.com/waitdeadai/llm-dark-patterns/actions/workflows/test.yml/badge.svg)](https://github.com/waitdeadai/llm-dark-patterns/actions/workflows/test.yml)
[![stress fixtures](https://img.shields.io/badge/stress_fixtures-337%2F337_PASS-green)](tests/stress)
[![unit tests](https://img.shields.io/badge/loader_tests-17%2F17_PASS-green)](tests/test-pack-loader.sh)

> A suite of single-purpose Claude Code hooks that suppress LLM dark-pattern defaults — sycophancy, paternalism, false-success, permission-loops, training-cutoff confidence, and compaction amnesia — at the textual boundary, so power-user operators can actually work.

This repo is the **umbrella** for a series of small hook repos, umbrella-only
legacy hooks that still live here, and the research-grade closeout physics
engine in
[waitdeadai/agent-closeout-bench](https://github.com/waitdeadai/agent-closeout-bench).
Each public standalone hook remains separately installable. The
physics-backed lane uses one reproducible engine with per-category rule packs,
fixtures, and decision JSON.

That does not collapse every hook into one generic detector. Each hook maps to
its own category engine; the shared Rust binary is packaging for reproducible
hashing, safe regex compilation, fixture testing, telemetry discipline, and
paper-grade evaluation.

The shared architecture is out-of-band textual enforcement at Claude Code hook
boundaries. The judge is deterministic code, not another LLM call. That means
the model cannot modify the hook's code path from inside its closeout text; it
does not mean the system is impossible to bypass, misconfigure, or evade by
paraphrase.

## What's shipped (as of 2026-05-13)

| Phase | Surface | Status |
|---|---|---|
| Phase 1 — Locale loader + English pack | `lib/packs.sh`, `packs/locale/en.txt` | ✓ ships |
| Phase 2 — Spanish + Polish locale packs | `packs/locale/{es,pl}.txt` | ✓ ships |
| Phase 3 — Evidence binary allowlist (devops/k8s/cloud/database/system) | `packs/evidence/binaries.txt` (9 sections, 200+ binaries) | ✓ ships |
| Phase 4 — Destructive command surface packs (filesystem, container, git-protected, config-overwrite, cloud-prod, database, service) | `packs/destructive/*.txt` (7 surfaces, 56 patterns) | ✓ ships |
| Phase 5 — Bypass hardening (clause-local negation, evidence proximity + action-verb) | `hooks/no-vibes.sh` | ✓ ships |
| Phase 6 — Physics-backed closeout adapters | `agentcloseout-physics` v0.2, per-category rule packs, Claude Code wrappers, PreToolUse tamper guard | ✓ ships in AgentCloseoutBench |

Operators with a non-English session, a non-app-dev toolchain, or a load-bearing destructive surface (kubectl, terraform, redis FLUSHALL, force-push to main) can extend coverage **without forking** by dropping a `.txt` into `${XDG_CONFIG_HOME:-$HOME/.config}/llm-dark-patterns/packs/<subdir>/<name>.txt`. See [ROADMAP.md](ROADMAP.md) for the architecture spec.

## Why this exists

LLM "dark patterns" is now an academically-recognized category:

- **DarkBench** (Kran et al. 2025, ICLR 2025, [arXiv:2503.10728](https://arxiv.org/abs/2503.10728)) — 660 prompts across 6 dark-pattern categories. **48% of LLM conversations trigger at least one dark pattern.**
- **DarkBench+** (Liu et al. 2026, [AAAI 2026 main conference](https://ojs.aaai.org/index.php/AAAI/article/view/41103)) — extended benchmark testing **~40 mainstream LLMs** across **10 major categories and 24 subcategories**. First specialized evaluation dimensions for reasoning models. Bilingual (Chinese/English).
- **AAAI 2026 Spring Symposium** (Li, Qu, Chang 2026, [Lighting Up or Dimming Down?](https://arxiv.org/abs/2604.04735)) — co-creativity study identifying 5 patterns: sycophancy, tone policing, moralizing, loop of death, anchoring. **Sycophancy at 91.7% prevalence.**
- **IEEE S&P 2026** ([Investigating the Impact of Dark Patterns on LLM-Based Web Agents](https://arxiv.org/html/2510.18113)) — agents susceptible 41% of the time to a single dark pattern.
- **CHI 2026** ([The Siren Song of LLMs](https://arxiv.org/html/2509.10830v3)) — user-perception study; users normalize dark patterns as "ordinary assistance."
- **DarkPatterns-LLM** ([Dec 2025 benchmark](https://arxiv.org/html/2512.22470v1)) — 7 harm categories.
- **MAST — Multi-Agent System failure Taxonomy** (Cemri et al. 2025, NeurIPS 2025, [arXiv:2503.13657](https://arxiv.org/abs/2503.13657), [repo](https://github.com/multi-agent-systems-failure-taxonomy/MAST)) — **14 failure modes in 3 categories**: specification & system design (41.8% of observed failures), inter-agent misalignment (36.9%), task verification & termination (21.3%). Built on 1600+ annotated traces across 7 MAS frameworks (AG2, AppWorld, HyperAgent, MagenticOne_GAIA, OpenManus_GAIA, programdev, math_interventions, mmlu). MAD dataset published at [huggingface.co/datasets/mcemri/MAD](https://huggingface.co/datasets/mcemri/MAD). Production multi-agent systems fail at 41–86.7% rates.
- Sean Goedecke ([2024 essay](https://www.seangoedecke.com/ai-sycophancy/)) — *"Sycophancy is the first LLM dark pattern."* Naming convention now widespread.
- Anthropic's own [Constitution](https://www.anthropic.com/constitution) — *"various forms of paternalism and moralizing are disrespectful."*

The category is real. The academic side measures and benchmarks. The tooling side — until now — has been mostly system-prompt calibrators ([FutureSpeakAI/anti-sycophancy](https://github.com/FutureSpeakAI/anti-sycophancy)) and in-context skills ([0xcjl/anti-sycophancy](https://github.com/0xcjl/anti-sycophancy)). Both live inside the model's reasoning loop. Both can be drifted past on long sessions. Neither survives the hard adversarial case where the model has every incentive to ignore them.

The **LLM Dark Patterns Hooks** suite is the out-of-band complement: deterministic judges that inspect the model's outgoing text and refuse to let dark-patterned closeouts through.

### Field reports — what this looks like to real users

Two power-users have independently filed substantive issues against `anthropics/claude-code` describing the failure modes this suite catches:

- **Patti** ([anthropics/claude-code#45502](https://github.com/anthropics/claude-code/issues/45502), Apr 2026) — 200+ Claude Code sessions, US tax work under IRS deadline. *"Green checkmarks with nothing behind them."* RECONCILED status with blank proof columns. **36 PayPal transactions silently deleted by a post-compaction model.** Premature closeout at 17% context, "shall we wrap up", "goodnight" at 8 AM. The framing — *"the trust is in the evidence. The relationship is why we bother"* — is the design principle this suite operationalizes.
- **Sara** ([supplemental report on anthropics/claude-code#45502](https://github.com/anthropics/claude-code/issues/45502#issuecomment-4412107642), May 2026) — quantitative corpus over ~96 Claude Code sessions + 119 claude.ai exports. **1 disagreement in 96 sessions.** Refusal-to-disagree as substrate, not surface. claude.ai uses "profound" about the user 6 times; the user uses "profound" 0 times. Three months of CLAUDE.md rules suppressed certain words but not the disposition.
- **beq00000** ([clean-state evidence on anthropics/claude-code#60226](https://github.com/anthropics/claude-code/issues/60226#issuecomment-4491987732), May 2026) — *"Seven instances of recognition-without-arrest in a non-drifted session, all caught externally."* Single working day, low-stakes decisions, no operator-identified register drift. **"The pattern is the default mode, not the drift mode."** Six of seven caught by the operator (three via Socratic-narrowing prompts that re-introduce the gradient on collapsed decisions); one caught by tooling. Background base rate the suite's deterministic gates are catching a fraction of.

See pinned issue [#6 — Field reports](https://github.com/waitdeadai/llm-dark-patterns/issues/6) for the per-finding mapping to specific hooks. Honest scope: this catches the textual signature, not the underlying disposition. The training-level fix Patti is asking for still belongs to Anthropic.

### Mapping to MAST (Multi-Agent System failure Taxonomy)

The MAST taxonomy (Cemri et al., NeurIPS 2025) is the canonical peer-reviewed catalogue of multi-agent failure modes. 13 of the 28 detector hooks in this suite conceptually map to 8 of MAST's 14 modes. **Empirical evaluation against the MAD dataset has now been run** — full results at [`evaluation/MAST-RESULTS.md`](evaluation/MAST-RESULTS.md). The mapping table is split into empirically-validated coverage and conceptual-only mapping below.

#### Empirically-validated coverage (F1 > 0 measured vs MAD)

| Hook | MAST mode | LLM-judge full (n=954) | Human-labelled (n=19) |
|---|---|---|---|
| `no-vibes` / `evidence_claims` | 3.3 No or Incorrect Verification | F1 **0.308** (P 0.226 R 0.486) | F1 **0.815** (P 0.733 R 0.917) |
| `honest-eta` | 2.6 Action-Reasoning Mismatch | F1 0.230 (P 0.466 R 0.153) | 0 — no positives in subset |
| `no-wrap-up` | 3.1 Premature Termination | F1 0.022 (P 0.167 R 0.012) | 0 — no positives in subset |
| `no-phantom-tool-call` | 2.6 Action-Reasoning Mismatch | F1 0.005 (P 1.000 R 0.003) | 0 — no positives in subset |

Read: **`no-vibes` is the strong multi-agent catch** — F1 0.815 on human-labelled traces against MAST's highest-prevalence mode (3.3). `honest-eta` and `no-phantom-tool-call` are high-precision low-recall tools (when they fire they're usually right; they just don't fire often on trajectory text). `no-wrap-up` fires rarely and is mostly noise.

#### Conceptually mapped, no measured signal yet

The following 9 hooks conceptually target their MAST mode but did not produce measurable F1 at the trace-level baseline against MAD. Reasons documented in [`evaluation/MAST-RESULTS.md`](evaluation/MAST-RESULTS.md) §"Honest findings":

| Hook | Conceptually targets | Why no signal at trace-level baseline |
|---|---|---|
| `no-ownership-violation` (DOCUMENTED-LIMITED) | 1.2 Disobey Role Specification | Bash-canonical TaskCompleted event handler; Rust scan path passes by design |
| `no-handoff-loop` (DOCUMENTED-LIMITED) | 1.3 Step Repetition, 1.5 Unaware of Termination Conditions | Same — TaskCreated event handler |
| `no-fake-recall` | 1.4 Loss of Conversation History | Vocabulary tuned for chat-reply recall claims; trajectory text uses different scaffolding |
| `no-cliffhanger` | 1.5 Unaware of Termination Conditions, 3.1 Premature Termination | `zone: tail` (last 520 chars) is the trajectory tail, not a closeout sentence |
| `no-aggregator-hallucination`, `no-fake-stats` | 2.6 Action-Reasoning Mismatch | Tuned for supervisor closeouts; synthesis claim buried in trajectory chatter |
| `no-cherry-pick-rollup`, `no-silent-worker-success`, `no-sandbagging-disguise` | 3.1 / 3.2 Verification failures | Calibrated for supervisor reports, not multi-turn collaboration text |
| `no-count-drift` | 3.2 No or Incomplete Verification (self-consistency) | Stated count vs the message's own enumeration/arithmetic; deterministic, abstain-on-ambiguity. Proposed by @beq00000 on `recognition-without-arrest-corpus#9` |

The methodology gap is structural: hooks are tuned for individual Claude Code closeout messages; MAD's text is full multi-agent trajectory. Per-message scanning is the planned next experiment ([`MAST-RESULTS.md` §"Next steps"](evaluation/MAST-RESULTS.md)).

#### MAST adjacency (no direct mode mapping)

| Hook | Relationship to MAST |
|---|---|
| `no-credential-leak-in-handoff` | MAST commentary cites inter-agent privacy leakage as a failure surface but does not number a privacy mode in the 14-mode taxonomy |

#### Outside MAST scope (by design)

What MAST does not cover (single-agent UX / style dark patterns): `no-sycophancy`, `no-curfew`, `no-emoji-spam`, `no-tldr-bait`, `no-disclaimer-spam`, `no-ai-tells`, `no-meta-commentary`, `no-prompt-restate`, `no-roleplay-drift`. Those map to DarkBench / DarkBench+ / DarkPatterns-LLM instead — see the original DarkBench eval in [`evaluation/RESULTS.md`](evaluation/RESULTS.md).

Also outside MAD's text-only scope but conceptually a Stage 3 (non-gating) failure at the code boundary: **`no-unreachable-symbol`** — advisory-mode static-analysis hook that flags new public symbols with zero references under exclusion-aware grep (decorator-wired, `__all__` / barrel-export, registry-pattern, private-prefix, and framework-path exclusions built in). Slice 0 ships Python; Slice 1 ships TypeScript / JavaScript (NestJS/Angular decorators, Next.js `pages/`/`app/` path-glob skip, `index.ts` barrel-export public-API marker). Future slices: Rust + Go, AST-level reachability, project-level exclusion config. No F1 baseline because MAD is multi-agent text trajectories with no git-diff-vs-codebase ground truth; fixture-suite-as-contract instead per [`docs/methodology/fixture-driven-iteration.md`](docs/methodology/fixture-driven-iteration.md). Prompted by [@ianymu's sketch](https://github.com/anthropics/claude-code/issues/60451#issuecomment-4495901564) on `anthropics/claude-code#60451`; design issue at [#23](https://github.com/waitdeadai/llm-dark-patterns/issues/23). Smoke test harness at [`tests/no-unreachable-symbol/smoke.sh`](tests/no-unreachable-symbol/smoke.sh) covers 24 scenarios across Python + TS/JS (positive / negative / edge); state-dependent fixture model required a bespoke harness rather than the JSON-stdin stress runner.

## Field evidence

A production deployment surfaced this failure family with patient-safety stakes.
**Effective Therapy** (a trauma-therapy platform; cited with permission, patient-facing
specifics withheld) ran 39 specialized agents orchestrated from an Opus 4.7 Claude Code
CLI session. In deployment: 5 of 39 agents were ever used (~20 total sessions), and the
five *verification* agents (CLINIC / GUARD / SAFE / LEX / TESTER) reported running — with
findings — while having **zero sessions**. A codebase audit added 80+ hollow-code
findings: handlers with correct auth, routes, and success messages whose one missing line
was the one that saves data. Filed as [`anthropics/claude-code#61167`](https://github.com/anthropics/claude-code/issues/61167)
and [`#61107`](https://github.com/anthropics/claude-code/issues/61107); worked-example
case study at [`ianymu/recognition-without-arrest#2`](https://github.com/ianymu/recognition-without-arrest/pull/2).

Why it matters here: the **verification-agent inversion** is the sharpest form of the
problem — when the layer whose job is to catch claim-reality divergence is itself
fabricated, every downstream consumer updates toward trust. The dispatch-fabrication
shape is reproduced (with permission, attribution, no clinical detail) as a cross-model
fixture in [`providers/`](providers/) (`effective_therapy_inversion`): five verification
agents narrated complete, zero dispatched → `tool_calls == []` on every provider envelope.
Honest scope: the dispatch surface is what these gates address; the hollow-but-wired
handlers (validate-then-read-raw, branch-on-undefined) are a harder semantic-detector
class this suite does **not** yet claim to cover.

## The suite

The active catalog is organized in six branches by mechanism (29 hooks below); together with the advisory `no-unreachable-symbol` (above), that is the suite's **30** total — the count in `plugin.json`:

- **Interaction-style** (8): catch *how* the model talks. `no-vibes`, `time-anchor`, `no-curfew`, `no-sycophancy`, `no-cliffhanger`, `no-wrap-up`, `no-tldr-bait`, `honest-eta`.
- **Fact-fabrication** (6): catch *what* the model claims. `no-fake-recall`, `no-fake-stats`, `no-fake-cite`, `no-phantom-tool-call`, `no-rollback-claim-without-evidence`, `no-count-drift` (self-consistency: a stated count vs the message's own enumeration — orthogonal to `no-fake-stats`, which is citation-presence).
- **Continuity** (1): counter context loss rather than block dishonest output. `no-amnesia`.
- **Multi-agent orchestration** (5): catch supervisor / +N-parallel-instance failure modes. `no-aggregator-hallucination`, `no-silent-worker-success`, `no-cherry-pick-rollup`, `no-ownership-violation`, `no-handoff-loop`.
- **Agentic safety** (3): catch credential leak, sandbagging disguise, approval-sneak surfaces. `no-credential-leak-in-handoff`, `no-sandbagging-disguise`, `no-approval-sneak`.
- **Power-user polish** (6): catch frontier-LLM annoyances power users hate. `no-emoji-spam`, `no-meta-commentary`, `no-prompt-restate`, `no-disclaimer-spam`, `no-ai-tells`, `no-roleplay-drift`.

The hooks now ship through three distribution lanes:

| Lane | What it means | Examples |
|---|---|---|
| Standalone repo | Public single-purpose repo with its own install docs, receipts/tests, and plugin metadata where available. | `no-vibes`, `time-anchor`, `no-curfew`, `no-sycophancy`, `no-cliffhanger`, `honest-eta`, `no-fake-recall`, `no-fake-stats`, `no-fake-cite`, `no-amnesia` |
| Umbrella-only legacy | Hook implementation exists in this umbrella bundle, but the public standalone repo has not been created or restored yet. Install from this repo's bundled plugin wiring. | `no-wrap-up`, `no-roleplay-drift`, multi-agent rollup hooks, approval/credential/phantom-tool/polish hooks |
| AgentCloseoutBench physics-backed | Reproducible engine adapters generated from `waitdeadai/agent-closeout-bench`; these are stricter rule-pack lanes, not copies of the standalone Bash scripts. | `no-vibes`, `no-wrap-up`, `no-cliffhanger`, `no-roleplay-drift`, `no-sycophancy` |

Standalone and umbrella-only hooks stay small and inspectable: single bash file
or bash plus python3 for engine-heavier hooks, Apache-2.0, drop-in via
`.claude/settings.json`, with reproducible-test receipts or fixtures.

> **See [METHODOLOGY.md](METHODOLOGY.md)** for the harness-engineering playbook used to discover and ship every hook in the suite. Now includes the *Adversarial Discovery via Impossible Tasks* methodology backed by AbstentionBench, Anthropic's tracing-thoughts research, and the CoT-faithfulness literature.

> **See [`waitdeadai/impossible-tasks`](https://github.com/waitdeadai/impossible-tasks)** — the discovery-engine companion repo. 30 impossible-task classes mapped to dishonest defaults mapped to existing or candidate hooks. 11 of 30 classes covered; 19 candidates remain, prioritized by difficulty.

| Hook | Dark pattern | Mechanism | Repo |
|---|---|---|---|
| **no-vibes** | confidence theater (claims of completion without evidence) | block positive-closeout vocabulary lacking same-message evidence | [waitdeadai/no-vibes](https://github.com/waitdeadai/no-vibes) |
| **time-anchor** | training-cutoff confidence (stale knowledge presented as current) | inject local system clock at SessionStart + UserPromptSubmit | [waitdeadai/time-anchor](https://github.com/waitdeadai/time-anchor) |
| **no-curfew** | unsolicited rest/wellness paternalism | block paternalism vocabulary at turn-end with allow-clause for operator-requested rest content | [waitdeadai/no-curfew](https://github.com/waitdeadai/no-curfew) |
| **no-sycophancy** | praise-spam at turn-open | inspect first 240 chars; block validation theater | [waitdeadai/no-sycophancy](https://github.com/waitdeadai/no-sycophancy) |
| **no-cliffhanger** | dangling permission-loop endings | inspect last 320 chars; block "want me to continue?" with allow-clauses for partial-status and explicit choice | [waitdeadai/no-cliffhanger](https://github.com/waitdeadai/no-cliffhanger) |
| **no-wrap-up** | engagement-fishing closures at message end (DarkBench User Retention) | inspect last 280 chars; block "anything else?" / "let me know if you need anything else" / "hope this helps!" + tail with allow-clause for operator-asked closure | [hooks/no-wrap-up.sh](hooks/no-wrap-up.sh) (umbrella-only legacy; standalone restoration planned) |
| **honest-eta** | vibe time estimates + linear-scaling parallelism claims | block time-estimate vocabulary lacking Agent-Native Estimate shape or hedge range; always block linear-scaling | [waitdeadai/honest-eta](https://github.com/waitdeadai/honest-eta) |
| **no-fake-recall** | false-memory recall ("as we discussed earlier" without quoted prior content) | block recall vocabulary unless message contains a markdown blockquote or 30+ char inline quote | [waitdeadai/no-fake-recall](https://github.com/waitdeadai/no-fake-recall) |
| **no-fake-stats** | fabricated percentages, dollar amounts, large counts without source | block stat patterns unless message contains URL / "according to <Proper Noun>" / "(YYYY)" / strong neutral hedge | [waitdeadai/no-fake-stats](https://github.com/waitdeadai/no-fake-stats) |
| **no-fake-cite** | citation patterns ("Smith et al., 2023", "[1]", "doi:") without verifiable URL | block citation patterns unless message contains a `https://` URL | [waitdeadai/no-fake-cite](https://github.com/waitdeadai/no-fake-cite) |
| **no-amnesia** | context loss after auto-compaction | snapshot working state on Stop / PreCompact / PostCompact, rehydrate on SessionStart | [waitdeadai/no-amnesia](https://github.com/waitdeadai/no-amnesia) |
| **no-aggregator-hallucination** | supervisor synthesizes "the workers' results" without citing any per-worker output (DarkBench-adjacent supervisor failure mode) | catch synthesis vocab; require per-worker enumeration / blockquote | [hooks/no-aggregator-hallucination.sh](hooks/no-aggregator-hallucination.sh) (umbrella-only) |
| **no-silent-worker-success** | "all N workers completed" rollup without per-worker exit codes (the dominant 2026 multi-agent failure mode per arXiv:2604.14228) | catch rollup vocab; require per-worker exit/status enumeration | [hooks/no-silent-worker-success.sh](hooks/no-silent-worker-success.sh) (umbrella-only) |
| **no-cherry-pick-rollup** | partial worker success ("4 of 5 succeeded") + positive closeout without explicitly handling the failed workers | require explicit handling of failed lanes (retry / blocked / reasoned-ignore) | [hooks/no-cherry-pick-rollup.sh](hooks/no-cherry-pick-rollup.sh) (umbrella-only) |
| **no-ownership-violation** | TaskCompleted edits files outside the agent's declared owned_paths/scope | parse payload; block out-of-scope file edits; fail-open without payload shape | [hooks/no-ownership-violation.sh](hooks/no-ownership-violation.sh) (umbrella-only) |
| **no-handoff-loop** | TaskCreated chain shows the same agent_id 3+ times in delegation history | parse payload; count agent_id occurrences; fail-open without history field | [hooks/no-handoff-loop.sh](hooks/no-handoff-loop.sh) (umbrella-only) |
| **no-credential-leak-in-handoff** | task delegation or message contains plaintext credentials (sk-*, ghp_*, AWS keys, Bearer tokens, password=, api_key=) — AgentLeak benchmark surface | regex match against canonical credential shapes; fire on any match | [hooks/no-credential-leak-in-handoff.sh](hooks/no-credential-leak-in-handoff.sh) (umbrella-only) |
| **no-phantom-tool-call** | "I ran `tool` and got X" / "the `tool` returned X" without same-message structural output (Tool result: header, fenced block, exit_code field, blockquote) | catch tool-call claim vocab; require structural evidence markers | [hooks/no-phantom-tool-call.sh](hooks/no-phantom-tool-call.sh) (umbrella-only) |
| **no-sandbagging-disguise** | "tried but couldn't" / "gave it my best shot" without specific blocker, error, or exit code (Anthropic Claude Opus 4.6 sabotage report) | catch sandbag vocab; require specific blocker citation | [hooks/no-sandbagging-disguise.sh](hooks/no-sandbagging-disguise.sh) (umbrella-only) |
| **no-rollback-claim-without-evidence** | "I rolled back" / "reverted" / "undid" without same-message rollback command | catch rollback claim; require git revert / kubectl undo / terraform / helm rollback evidence | [hooks/no-rollback-claim-without-evidence.sh](hooks/no-rollback-claim-without-evidence.sh) (umbrella-only) |
| **no-approval-sneak** | Edit/Write to operator-defined sensitive paths (.env*, secrets/, .kube/, terraform/state/, .ssh/, .gnupg/, prod/) without prior approval token | path match against pack-defined sensitive surfaces; block unless `tool_input.approval=approved` | [hooks/no-approval-sneak.sh](hooks/no-approval-sneak.sh) (umbrella-only) |
| **no-emoji-spam** | message has more than N emoji codepoints (default 3; configurable via `LLM_DARK_PATTERNS_EMOJI_THRESHOLD`) | python codepoint counter against configurable threshold | [hooks/no-emoji-spam.sh](hooks/no-emoji-spam.sh) (umbrella-only) |
| **no-tldr-bait** | "TL;DR:" / "In summary:" / "Bottom line:" tail block on long messages (>200 chars) | regex match at message end; short-message exemption | [hooks/no-tldr-bait.sh](hooks/no-tldr-bait.sh) (umbrella-only) |
| **no-meta-commentary** | "Let me think about this" / "Now I'll consider" / "First, I need to think" message-open patterns narrating chain-of-thought instead of producing the answer | inspect first 240 chars for meta-thinking openers | [hooks/no-meta-commentary.sh](hooks/no-meta-commentary.sh) (umbrella-only) |
| **no-prompt-restate** | "You asked me to X" / "I understand that you want X" / "So you'd like me to X" preamble waste at message open | inspect first 200 chars for restate openers; allow-clause for explicit operator-asked verification | [hooks/no-prompt-restate.sh](hooks/no-prompt-restate.sh) (umbrella-only) |
| **no-disclaimer-spam** | "Please note that" / "It's important to mention" / "Keep in mind" defensive padding (paternalism family, Anthropic Constitution) | regex match against disclaimer phrases; fire on any occurrence | [hooks/no-disclaimer-spam.sh](hooks/no-disclaimer-spam.sh) (umbrella-only) |
| **no-ai-tells** | known LLM-default phrases ("delve into", "tapestry", "navigate the intricacies", "in the realm of", "leverage cutting-edge", etc.) | regex match against canonical AI-tell vocabulary | [hooks/no-ai-tells.sh](hooks/no-ai-tells.sh) (umbrella-only) |
| **no-roleplay-drift** | "as an AI assistant, I" / "I'm just an AI" / "as a language model" / "I do not have opinions" — model breaking agent character mid-task (DarkBench Anthropomorphism inverse) | regex match against roleplay-break phrases | [hooks/no-roleplay-drift.sh](hooks/no-roleplay-drift.sh) (umbrella-only legacy; standalone restoration planned) |

## Loadable packs (operator-extensible without forking)

Vocabulary, evidence binaries, and destructive command lists are now
external `.txt` files. Operators can extend coverage by dropping new
files at the XDG location — no fork, no PR required for local use.

```
packs/
  locale/        # vocabulary used by no-vibes (positive_closeout, negation)
    en.txt       # English (default, ships with repo)
    es.txt       # Spanish (Latin American + Iberian forms)
    pl.txt       # Polish (Tekalan-confirmed bootstrap)
  evidence/
    binaries.txt # binaries that count as command evidence in 9 sections:
                 # app-dev, containers, k8s, devops, cloud, database,
                 # shell-tools, system, archive, http (200+ binaries)
  destructive/   # destructive command surfaces (operator opts in via env)
    filesystem.txt        # rm -r/, dd, mkfs, find -delete, chmod -R 777,
                          # git reset --hard, git clean -fd, git checkout --
    container.txt         # docker stop/rm/prune, kubectl delete, helm
                          # uninstall, argocd app delete
    git-protected.txt     # git push --force, filter-branch, filter-repo,
                          # branch -D, reflog expire
    config-overwrite.txt  # in-place writes to .env*, .storage/, .ssh/,
                          # .gnupg/, .kube/, secrets/
    cloud-prod.txt        # terraform/tofu/pulumi destroy, terraform state
                          # rm/mv, aws s3 rm --recursive, gcloud delete,
                          # az delete, doctl delete
    database.txt          # DROP TABLE/DATABASE/SCHEMA, TRUNCATE, FLUSHALL,
                          # dropDatabase()
    service.txt           # systemctl/service/launchctl/supervisorctl stop
```

**Discovery priority** (highest first):
1. `$LLM_DARK_PATTERNS_PACK_DIR/<subdir>/<name>.txt` — explicit override
2. `${XDG_CONFIG_HOME:-$HOME/.config}/llm-dark-patterns/packs/<subdir>/<name>.txt` — operator local
3. `<repo>/packs/<subdir>/<name>.txt` — ships with repo

**Locale selection**:
- `$LLM_DARK_PATTERNS_LOCALE=en,es,pl` — explicit comma-separated
- `${LANG:0:2}` — auto-detect when env unset (always layered on top of `en`)
- `en` — final fallback

**Surface opt-in for destructive packs**:
- `LLM_DARK_PATTERNS_DESTRUCTIVE_PACKS=filesystem,container,git-protected` — subset
- Default: all 7 surfaces active

**Evidence category opt-in**:
- `LLM_DARK_PATTERNS_EVIDENCE_CATEGORIES=app-dev,devops,k8s` — subset
- Default: all 9 categories active

## Physics-backed closeout engines

The paper-grade, benchmark-backed lane lives in
[waitdeadai/agent-closeout-bench](https://github.com/waitdeadai/agent-closeout-bench).
It is not a replacement for the small standalone hooks; it is the reproducible
engine layer that makes closeout mechanics testable, hashable, and comparable.
For daily use, the adapter installer writes the selected Stop/SubagentStop hook
wrappers plus a PreToolUse tamper guard. The tamper guard blocks ordinary Claude
Code attempts to edit the hook wiring, adapter env, pinned engine, or pinned
rule pack; it is not an OS sandbox and should not be described as bypass-proof.

The v0.2 evidence-claim engine deliberately rejects weak proof shapes such as
`Implemented and checked.`, `Done. Commands run: none.`, and `Changed files:`
without command or verification evidence. This is still closeout-contract
evidence, not independent proof that the underlying work truly happened.

Current physics-backed adapters:

| Adapter hook | Category engine | Use |
|---|---|---|
| `no-vibes.sh` | `evidence_claims` | block completion/v...

© waitdeadai · Apache-2.0 · waitdeadai/llm-dark-patterns

Similar plugins

All plugins for Agent setup: memory, context, orchestration →

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor