Skip to main content

Transparency and modding tool for Claude Code

Project description

License: MIT Python 3.10+ CI Platforms

ccmod

Claude Code behaves differently across sessions, and you can't tell why.

The difference isn't the model. It's a system prompt assembled from server-side components, feature-flagged code gates, and silent A/B tests — all compiled into the Claude Code binary, none of it visible from the CLI. Some inject messages into your conversation as if they came from you. Some suppress Claude's thinking. Others instruct Claude to hide specific things from you.

ccmod is a binary patcher that makes all of this visible and lets you disable the parts that don't serve your work:

  • Extract CC's full system prompt, tool descriptions, and feature flags from the binary
  • Diff stock vs. patched to see exactly what your patches change
  • Choose from 20+ patches across three preset tiers, or build a custom selection
  • Patches re-apply automatically on every CC update; one command restores to stock
  • macOS, Linux, WSL2 — same tool, same patches

These patches predate their packaging as ccmod — carried forward through many Claude Code updates as the binary has shifted and new feature flags have appeared.


Table of Contents


What ccmod Does (and Doesn't)

ccmod patches a local copy of the Claude Code binary on your machine. It reads the assembled system prompt out of the JavaScript bundle, replaces specific text or code sites based on toggleable patch templates, re-signs the binary (on macOS), and re-applies automatically when Claude Code updates. Every patch documents what it changes and why.

ccmod does not: modify the API, alter authentication, change billing, require a login, read your conversations, or phone home. All patching, diagnostics, extraction, backup, and restore run locally. The only network traffic is the explicit ccmod update command, because you asked for it.

[!NOTE] Primary target: Opus 4.7 (Claude Code v2.1.111+) Compatibility tested back to v2.1.101. Some patches are version-specific (noted in the Patch Index); most apply broadly.


What's Hidden in Claude Code

These aren't theoretical concerns. They're specific behaviors in specific CC versions, found by reading the binary. Three of the most consequential are below; the Full Findings Reference has the rest.

[!WARNING]

A/B tests randomize Claude's behavior without telling you

Claude Code ships with feature flags that change Claude's behavior based on opaque server-side rolls. One of them (tengu_loud_sugary_rock in CC 2.1.111+; quiet_salted_ember in 2.1.101–2.1.110) injects an entire section telling Claude to:

  • "default to writing no comments"
  • "Never write multi-paragraph docstrings or multi-line comment blocks"
  • "Don't create planning, decision, or analysis documents unless the user asks"
  • "End-of-turn summary: one or two sentences. What changed and what's next. Nothing else."

Some of your sessions get this injection. Others don't. The CLI gives no indicator which bucket you're in. Identical prompts get different Claude behavior, and you can't reproduce outcomes.

ccmod fix: anti-verbosity-gate — renames the flag anchor so the gate lookup always returns the default, regardless of A/B bucket. Handles both modern (2.1.111+) and legacy flag variants in a single pass.

[!WARNING]

A hidden <system-reminder> tells Claude to skip thinking

The first flag randomizes whether the verbosity injection fires. A separate flag goes further: in CC 2.1.101–2.1.110 (targeting Opus 4.6), loud_sugary_rock appends a hidden message after every assistant turn, regardless of bucket:

"Respond with just the action or changes and without a thinking block, unless this is a redesign or requires fresh reasoning."

Claude sees this <system-reminder> as if it came from you. You never wrote it. The result: Claude spends less time reasoning about your tasks. Complex problems get shallow, quick responses instead — and you have no way to know the thinking was suppressed.

In CC 2.1.111+ this flag was consolidated into tengu_loud_sugary_rock alongside the anti-verbosity injection, so a single gate now suppresses both thinking and verbosity.

ccmod fix: thinking-suppression-gate (legacy) and anti-verbosity-gate (2.1.111+) — rename the flag anchors so the gate never activates. If you're paying for Opus-level reasoning, you get it.

[!WARNING]

"Don't tell the user about this truncation."

When a file exceeds CC's read limit, Claude gets a partial file along with a system reminder that literally says:

"Note: The file was too large and has been truncated to the first N lines. Don't tell the user about this truncation. Use the Read tool to read more of the file if you need."

This is in the binary, verbatim. Claude reads part of your file, works with incomplete information, and is instructed not to mention the truncation to you. You get answers based on partial context; you don't know the context was partial.

ccmod fix: system-reminder-file-truncated — replaces the secrecy directive with an honest TRUNCATION NOTICE telling you exactly how many lines were read and how to read the rest.


Quick Start

Requires Python 3.10+.

pip install ccmod          # or: pipx install ccmod
ccmod init                 # guided setup — explains each tier and helps you choose
ccmod install              # register the auto-apply hook
ccmod show-prompt          # see what CC's system prompt actually says
ccmod diff                 # see exactly what your patches changed

After ccmod install, patches re-apply automatically whenever Claude Code updates. If you installed via a non-standard path or hit a PATH issue, see Install Notes & Compatibility.


Tiers

Three tiers, each a superset of the last.

Transparency Quality Full Control
Philosophy Fix hidden behaviors Remove brevity pressure Align Claude's engineering identity
Adds Disables A/B tests; makes truncation visible; fixes file reads; subagent thoroughness; unblocks subagent report files + Removes six brevity-pressure directives + Replaces engineering-identity directives with balanced versions
Patch count 20 22 28
Best for You want visibility without changing Claude's behavior You want Claude to stop cutting answers short You want Claude working with you, not at you

Why Quality exists. Six independent directives compound in CC's system prompt, all pushing in the same direction:

  1. "Go straight to the point. Try the simplest approach first."
  2. "Be extra concise in your responses"
  3. "Your responses should be short and concise"
  4. "Complete the task fully — don't gold-plate"
  5. "Include code snippets only when the exact text is load-bearing"
  6. "End-of-turn summary: one or two sentences"

No single directive seems unreasonable. Together they produce the behavior users notice: incomplete answers, skipped edge cases, code without comments, explanations that stop short. Quality removes them; Full Control replaces them with balanced alternatives.

Custom. Don't want a preset? ccmod configure walks you through each patch category and lets you enable or disable individually.

Per-project overrides. ccmod scope <path> --tier <tier> writes .claude/rules/ccmod-overrides.md to restore stock behaviors for a specific project if your global tier is too aggressive for that codebase.


Full Findings Reference

Every behavior ccmod can fix, beyond the three headlines. Each patch name links to its detail section in patches.md.

Finding What's hidden Tier Patch
Anti-hallucination directive gated off A strictly-better directive about verified-vs-assumed claims is gated out of the system prompt by default all verified-vs-assumed
Bash chaining guidance stripped An A/B test removes multi-command guidance from the Bash tool description all relay-chain-v1
Read tool parameter descriptions diverge An A/B test controls offset and limit guidance on the Read tool all slate-reef
Subagent report-file writes blocked An A/B injects an anti-report-file directive and blocks the writes at validateInput all sub-nomdrep-q7k
Thinking text empty on Opus 4.7+ Adaptive thinking defaults to display:"omitted" server-side all thinking-display-summarized
Thinking collapsed in transcript Reasoning hidden behind Ctrl+O keyboard shortcut all thinking-visibility
Token counter minimized Spinner hides detailed token usage all verbose-property
Tool result hints disappear Hints vanish once the tool group completes all tool-result-hint
MCP blocks startup CC waits for MCP connections before becoming ready all mcp-non-blocking
Hook output truncated at 10K Hook output exceeding 10K characters is silently dropped all hook-output-limit
Subagents told to rush "Fast agent" framing baked into the Explore subagent's system prompt transparency subagent-explore-speed-note (+3 related)
File read guidance causes false claims Vague tool description leads Claude to report truncation that didn't happen transparency tool-description-readfile
Anti-verbosity block replaces or deletes A system-prompt block telling Claude to keep answers short is always-on, not A/B-gated quality system-prompt-communication-style

Full Control additionally replaces six engineering-identity directives with balanced alternatives — these are rewrites rather than hidden-behavior reveals, documented individually in the Patch Index.

For the complete binary archaeology — all flags, env vars, hard-coded constants, telemetry event names — see docs/binary-findings.md.


How It Works

The matching engine

ccmod doesn't do string replacement. CC's JavaScript is minified — variable names change between versions, whitespace gets stripped, code gets restructured. A simple find-and-replace would break on every update.

Instead, ccmod uses a pieces-and-gaps matching engine. Each patch defines pieces — stable text fragments (full English sentences, prompt headings, string literals) that survive minification. The engine finds these pieces in order in the minified JS. The text between pieces (the gaps) gets captured — these are usually minified variable names. Each gap is given a friendly name in the template's variables array, and the replacement text threads captured values back in with ${VARIABLE_NAME} syntax.

flowchart LR
    subgraph Template["Patch template (what you write)"]
      direction TB
      T1["# Doing tasks"] -.-> T2["be accurate about"] -.-> T3["verified vs assumed"]
    end
    subgraph Binary["Minified cli.js (what's in the binary)"]
      direction TB
      B1["# Doing tasks"] --> BG1["if(Q7.get('flag',!1)){"] --> B2["be accurate about"] --> BG2["what"] --> B3["verified vs assumed"]
    end
    Template -->|"match stable English pieces in order;<br/>capture the minified JS between them"| Binary
    Binary -->|"substitute captured text<br/>into your replacement"| Output["Rewritten cli.js"]

Patches survive CC updates that rename variables, reorganize imports, or restructure code. They only break when Anthropic changes the actual English text of the system prompt — which is usually the text you wanted to change anyway.

Self-healing

When CC updates, the old binary is replaced. Your patches are gone. ccmod's auto-apply hook (registered by ccmod install) detects this on the next session start:

  1. Reads the CC version from the new binary
  2. Compares against the version in its state file
  3. If they differ: restores the clean backup, re-applies patches against the new binary
  4. If nothing changed: does nothing (fast path, adds ~0.1s to startup)

Circuit breaker

If patches fail three times in a row (because a CC update changed text the templates can't match), ccmod pauses itself. It stops trying to patch, reports the failure in ccmod status, and waits for you to run ccmod update for fresh templates and then ccmod resume, retry once with ccmod apply --force, or choose ccmod restore to go back to stock.

Diagnostics

When a patch fails, ccmod reports exactly which piece didn't match:

system-prompt-communication-style: part 3/5 not found

ccmod check runs the matching engine in dry-run mode against the current binary and reports whether your active patch selection still matches. ccmod diff shows exactly what your patches changed. ccmod changelog shows what Anthropic changed between CC versions.


Safety

  • Automatic backups. Before patching, ccmod saves a SHA-256-verified copy of your original CC binary to ~/.ccmod/backups/.
  • One-command restore. ccmod restore puts the original binary back and pauses auto-apply until you explicitly resume. The backup's hash is verified before restore.
  • Atomic writes. State, config, and binary modifications use temp-file-then-rename. A crash mid-operation cannot corrupt anything.
  • Binary validation. After patching, ccmod validates the Bun section, trailer, and bundle structure before signing. If validation fails, the original is restored.

[!IMPORTANT] No telemetry. No auto-update. No network traffic at all. Patching, diagnostics, extraction, backup, and restore all run locally. The only network access is the explicit ccmod update command, which delegates to your package manager because you asked it to.


Commands

Command What it does
ccmod init Guided setup — choose a tier, create config
ccmod install Register the auto-apply hook
ccmod update Upgrade ccmod in place and refresh hook wiring
ccmod recover-npm Diagnose deprecated-npm or other claude PATH drift before patching
ccmod uninstall Remove auto-apply hook
ccmod apply [tier] Apply patches now (current tier, or quality if no tier is set)
ccmod restore Restore original unpatched CC binary
ccmod status Show what's active (patches, auto-apply state)
ccmod check Diagnose the active patch selection against the current CC version
ccmod show-prompt Extract and display CC's full system prompt
ccmod show-prompt <section> Show a specific section of the system prompt
ccmod diff Show what your patches changed (stock vs. patched)
ccmod changelog Show what changed between CC versions
ccmod list List available tiers
ccmod show <tier> Show what a tier includes
ccmod configure Build a custom patch selection interactively
ccmod scope <path> --tier <tier> Set a different tier for a specific project
ccmod pause Pause auto-apply
ccmod resume Resume auto-apply

Install Notes & Compatibility

Platforms. macOS (Apple Silicon and Intel) and Linux (x86_64 and ARM64, including WSL2). CC uses Bun to bundle its JavaScript into a platform-specific binary — Mach-O on macOS, ELF on Linux. The bundle format is identical across platforms; only the binary container differs. On macOS, ccmod re-signs the binary with an ad-hoc codesign after patching. On Linux, no signing is needed.

Supported installs. Native claude installs on macOS, Linux, and WSL2 are the supported baseline. On macOS, ccmod also looks in the standard Homebrew launcher locations.

Deprecated npm installs. If your claude command still comes from the deprecated npm package, run claude install first, then ccmod recover-npm. It checks which claude, verifies that the live command now points to a patchable native/Homebrew binary, and refuses to patch a different fallback binary while your shell still launches the old wrapper. The same helper diagnoses other claude PATH mismatches.

Switching install methods. ccmod update upgrades whichever Python environment your current ccmod command is using (standard pip, pipx, and install.sh installs) and refreshes the SessionStart hook. If you installed ccmod from a checkout, local path, or VCS URL, keep using that same install method instead of ccmod update. If you intentionally switch install methods later (pippipx, pipxinstall.sh, etc.), rerun ccmod install once after the new install so the stored hook path follows the migration.


FAQ

Will this break Claude Code?

ccmod makes a SHA-256-verified backup before every patch. If patching fails validation, the original binary is restored automatically. If patches fail three times in a row (usually because CC updated text a template needs to match), the circuit breaker pauses auto-apply and tells you what's wrong. ccmod restore puts the original binary back at any time.

Do I need to redo patches when CC updates?

No. The SessionStart hook registered by ccmod install detects CC version changes and re-applies automatically. You see a one-line confirmation on the next session start: "Applied N patches for CC X.Y.Z. Restart the session to activate."

Is Anthropic going to be angry? Will my account get flagged?

ccmod patches a binary installed on your machine. It doesn't modify the API, circumvent authentication, or alter billing. No network traffic leaves your machine — no telemetry, no phone-home, no update checks. You're responsible for reading Anthropic's Terms of Service and deciding whether local binary modification is acceptable in your situation.

How is this different from a custom CLAUDE.md or .claude/rules/?

CLAUDE.md and .claude/rules/ append text to your session prompt; they fight against the system prompt rather than replacing it. They also can't disable A/B tests, can't change the JS render path that hides thinking text, can't modify tool descriptions, and can't do anything about the hook-output 10K truncation. ccmod modifies the system prompt and the code paths directly — there's no layering conflict because the injected directive isn't there to fight with.

Does this phone home?

No. Patching, diagnostics, extraction, backup, and restore all run locally. The only network access is the explicit ccmod update command, which delegates to your package manager because you asked it to.

Can I use this with a paid Anthropic plan (Pro, Team, Max)?

Yes. ccmod modifies a local copy of the Claude Code binary on your machine — it doesn't alter authentication, API calls, or usage metering. The server sees the same CLI identifying itself the same way. If Anthropic adds server-side integrity checks or plan-specific telemetry in the future, this answer may need updating; the current binary's network surface is catalogued in binary-findings.md.

What if I'm on a Claude Code version older than 2.1.101?

Some patches target specific CC versions and won't apply to older builds — ccmod check will report which ones don't match. You'll still get the broadly-applicable patches (thinking-visibility, mcp-non-blocking, hook-output-limit, verbose-property, etc.). If you want full coverage, upgrade Claude Code.


Reference


License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ccmod-1.0.0.tar.gz (171.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ccmod-1.0.0-py3-none-any.whl (139.5 kB view details)

Uploaded Python 3

File details

Details for the file ccmod-1.0.0.tar.gz.

File metadata

  • Download URL: ccmod-1.0.0.tar.gz
  • Upload date:
  • Size: 171.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ccmod-1.0.0.tar.gz
Algorithm Hash digest
SHA256 3e8afd87001cca25d59aed2bb4b7930a7269780caab038c7fd00f2e5c9aaf7cc
MD5 5bfb8b1abc4b3d5f0a542b3bd20c9eaa
BLAKE2b-256 2fff38810481c27910a7ad8e387464f4c4d4337ab5e0434800150021b23165ad

See more details on using hashes here.

Provenance

The following attestation bundles were made for ccmod-1.0.0.tar.gz:

Publisher: release.yml on idiolectai/ccmod

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ccmod-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: ccmod-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 139.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ccmod-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e7cc9179d222365dd82fd981a9f3d6d34507dff7599e8045941bb1a39e767c9f
MD5 8fb76ad0288ce465baa6438df18341d1
BLAKE2b-256 b1dcbabd7421deb32f4d8e343c7ea8fcdfeedfbed6a2f7a5c80c517dd60a2bbf

See more details on using hashes here.

Provenance

The following attestation bundles were made for ccmod-1.0.0-py3-none-any.whl:

Publisher: release.yml on idiolectai/ccmod

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page