patch-creation
Create and register new patches for tweakcc. Use when adding new customizations to Claude Code.
git clone https://github.com/Piebald-AI/tweakcc
T=$(mktemp -d) && git clone --depth=1 https://github.com/Piebald-AI/tweakcc "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills/patch-creation" ~/.claude/skills/piebald-ai-tweakcc-patch-creation && rm -rf "$T"
.claude/skills/patch-creation/SKILL.mdPatch Creation & Registration
Overview
Patches are code modifications applied to Claude Code's
cli.js (or native binary). Each patch finds specific patterns in the minified code and replaces/injects new behavior.
Creating a New Patch
1. Create the patch file
Create
src/patches/myPatch.ts:
// Please see the note about writing patches in ./index import { showDiff } from './index'; /** * Description of what this patch does. * * CC X.Y.Z: * ```diff * // Show before/after of the code change * -oldCode * +newCode * ``` */ export const writeMyPatch = ( file: string, configValue: string // Add parameters as needed ): string | null => { // Pattern to find in minified code // IMPORTANT: Use [$\w]+ for identifiers (not \w+) because $ is valid in JS identifiers // IMPORTANT: Start patterns with a boundary char (,;}{) for HIGH performance (e.g. 1.5s -> 30ms) const pattern = /,somePattern([$\w]+)/; const match = file.match(pattern); if (!match || match.index === undefined) { console.error('patch: myPatch: failed to find pattern'); return null; } const replacement = `,newCode${match[1]}`; const startIndex = match.index; const endIndex = startIndex + match[0].length; const newFile = file.slice(0, startIndex) + replacement + file.slice(endIndex); showDiff(file, newFile, replacement, startIndex, endIndex); return newFile; };
2. Add config type (if patch is configurable)
Edit
src/types.ts - add to MiscConfig or create a new interface:
export interface MiscConfig { // ... existing fields ... myNewSetting: string | null; // null = disabled }
3. Add default value
Edit
src/defaultSettings.ts:
misc: { // ... existing fields ... myNewSetting: null, // or a sensible default },
4. Register in index.ts
Edit
src/patches/index.ts:
4a. Add import:
import { writeMyPatch } from './myPatch';
4b. Add patch definition (in
array):PATCH_DEFINITIONS
{ id: 'my-patch', name: 'My patch', group: PatchGroup.FEATURES, // or ALWAYS_APPLIED, MISC_CONFIGURABLE description: 'What this patch does for the user', },
4c. Add patch implementation (in
object):patchImplementations
'my-patch': { fn: c => writeMyPatch(c, config.settings.misc!.myNewSetting!), condition: !!config.settings.misc?.myNewSetting, },
5. Add UI (optional)
Edit
src/ui/components/MiscView.tsx to add a toggle or input for the setting.
Key Files
| File | Purpose |
|---|---|
| Individual patch implementations |
| Patch registry, definitions, and application logic |
| Config type definitions (, etc.) |
| Default values for all settings |
| UI for misc settings |
Registration Checklist
When adding a new patch, update these locations:
-
- Create the patch file with exported functionsrc/patches/myPatch.ts -
- Add config type (if configurable)src/types.ts -
- Add default value (if configurable)src/defaultSettings.ts -
:src/patches/index.ts- Import the patch function
- Add to
array (id, name, group, description)PATCH_DEFINITIONS - Add to
object (fn, condition)patchImplementations
-
- Add UI controls (optional)src/ui/components/MiscView.tsx
Patch Groups
- Core patches that are always appliedPatchGroup.ALWAYS_APPLIED
- User-configurable misc settingsPatchGroup.MISC_CONFIGURABLE
- Feature patches that can be enabled/disabledPatchGroup.FEATURES
Pattern Writing Tips
-
Use
for identifiers - Not[$\w]+
, because\w+
is valid in JS identifiers and common in minified code$ -
Start patterns with boundary characters - Use
,,
,;
,{
at the start to dramatically speed up matching (can reduce 1.5s to 30ms)} -
Don't use
for word boundaries - It doesn't treat\b
as a word character, so$
won't match\b[$\w]+,$= -
Extract function bodies carefully - Count braces to find matching
when you need the full function} -
Use
for debugging - Always call it to log what the patch is changingshowDiff() -
Return
on failure - Let the patch system know the patch couldn't be appliednull -
Handle multiple CC versions - Code patterns may change between versions; try multiple patterns if needed
Example: Simple Toggle Patch
// Bypass a feature flag check const pattern = /function [$\w]+\(\)\{return [$\w]+\("my_feature_flag"/; const match = file.match(pattern); if (!match || match.index === undefined) { console.error('patch: myPatch: failed to find feature flag'); return null; } const insertIndex = match.index + match[0].indexOf('{') + 1; const insertion = 'return true;'; const newFile = file.slice(0, insertIndex) + insertion + file.slice(insertIndex); showDiff(file, newFile, insertion, insertIndex, insertIndex); return newFile;
Example: Replace a Value
// Replace a hardcoded value const pattern = /(someConfig=)\d+(;)/; const match = file.match(pattern); if (!match || match.index === undefined) { console.error('patch: myPatch: failed to find config value'); return null; } const replacement = match[1] + newValue + match[2]; const startIndex = match.index; const endIndex = startIndex + match[0].length; const newFile = file.slice(0, startIndex) + replacement + file.slice(endIndex); showDiff(file, newFile, replacement, startIndex, endIndex); return newFile;
Testing
- Run
to compilenpm run build - Run
to apply patchesnpx tweakcc --apply - Check console output for patch success/failure
- Run Claude Code to verify behavior