Skip to content

Instantly share code, notes, and snippets.

@AojdevStudio
Created February 21, 2026 00:14
Show Gist options
  • Select an option

  • Save AojdevStudio/6eb7c31cdc9d564f282ceb9205b287cb to your computer and use it in GitHub Desktop.

Select an option

Save AojdevStudio/6eb7c31cdc9d564f282ceb9205b287cb to your computer and use it in GitHub Desktop.
compile-claude — Semantic CLAUDE.md compiler. Compress LLM instruction files by 36%+ while preserving 100% meaning.

compile-claude

Semantic CLAUDE.md compiler. Compresses your human-readable CLAUDE.md into a dense, LLM-optimized version using Claude as the compression engine.

You edit the readable source. Your AI gets the dense version. 36%+ token savings, 100% meaning preserved.

Works for any LLM instruction file: CLAUDE.md, Cursor rules, Copilot instructions, system prompts, agent configs.

Requirements

Setup

# Download both files to the same directory
mkdir -p ~/.local/bin/compile-claude
# Place compile-claude.ts and prompt.txt in that directory
chmod +x compile-claude.ts

# Optional: add alias
echo 'alias compile-claude="bun run ~/.local/bin/compile-claude/compile-claude.ts"' >> ~/.zshrc

Usage

# First run in a project with CLAUDE.md — creates CLAUDE.src.md from existing
compile-claude

# Edit CLAUDE.src.md (your human-readable source), then compile
compile-claude

# Preview without writing
compile-claude --print

# Use a faster model
compile-claude --model haiku

How it works

  1. Reads CLAUDE.src.md (your human-readable source)
  2. Sends it through Claude with a semantic compression prompt
  3. Outputs CLAUDE.md (dense, LLM-optimized version)

The compression preserves all semantic meaning while removing formatting that only humans need: markdown decoration, verbose prose, blank lines, bullet lists (converted to inline), tables (converted to pipe-delimited).

Marker blocks (<!-- START --> to <!-- END -->), XML tags, code blocks, file paths, and URLs are preserved byte-for-byte.

Options

Flag Default Description
--print - Preview output + stats without writing
--model sonnet Claude model (sonnet, haiku, opus)
--source ./CLAUDE.src.md Source file path
--output ./CLAUDE.md Output file path
--timeout 120000 Inference timeout in ms

Results

Typical compression on real-world CLAUDE.md files:

  • 16KB source -> ~10KB compiled (36% reduction)
  • 300 lines -> ~117 lines
  • 100% semantic meaning preserved
#!/usr/bin/env bun
/**
* compile-claude — Semantic CLAUDE.md compiler
*
* Compresses CLAUDE.src.md into CLAUDE.md using LLM semantic compression.
* Source+Compiled pattern: you edit .src.md, this tool produces .md
*
* Requirements:
* - bun (https://bun.sh)
* - claude CLI (https://docs.anthropic.com/en/docs/claude-code)
*
* Usage:
* compile-claude [options]
*
* Options:
* --print Preview compressed output + stats (don't write)
* --model <name> Claude model to use [default: sonnet]
* --source <file> Source file path [default: ./CLAUDE.src.md]
* --output <file> Output file path [default: ./CLAUDE.md]
* --timeout <ms> Inference timeout in ms [default: 120000]
* -h, --help Show help
*/
import { existsSync, readFileSync, writeFileSync, copyFileSync } from "fs";
import { resolve, dirname } from "path";
import { fileURLToPath } from "url";
import * as readline from "readline";
// Types
interface CompileOptions {
source: string;
output: string;
model: string;
timeout: number;
printOnly: boolean;
}
// Constants
const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
const PROMPT_FILE = resolve(SCRIPT_DIR, "prompt.txt");
// Colors (ANSI)
const c = {
red: "\x1b[0;31m",
green: "\x1b[0;32m",
yellow: "\x1b[0;33m",
blue: "\x1b[0;34m",
dim: "\x1b[0;90m",
bold: "\x1b[1m",
reset: "\x1b[0m",
};
function log(msg: string): void {
console.log(msg);
}
function logError(msg: string): void {
console.error(`${c.red}${msg}${c.reset}`);
}
async function promptYesNo(question: string): Promise<boolean> {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
return new Promise((resolve) => {
rl.question(question, (answer) => {
rl.close();
const normalized = (answer || "Y").toLowerCase();
resolve(normalized.startsWith("y"));
});
});
}
// Parse CLI arguments
function parseArgs(): CompileOptions {
const args = process.argv.slice(2);
const options: CompileOptions = {
source: "./CLAUDE.src.md",
output: "./CLAUDE.md",
model: "sonnet",
timeout: 120000,
printOnly: false,
};
for (let i = 0; i < args.length; i++) {
const arg = args[i];
switch (arg) {
case "--print":
options.printOnly = true;
break;
case "--model":
options.model = args[++i] || options.model;
break;
case "--source":
options.source = args[++i] || options.source;
break;
case "--output":
options.output = args[++i] || options.output;
break;
case "--timeout":
options.timeout = parseInt(args[++i] || "120000", 10);
break;
case "-h":
case "--help":
showHelp();
process.exit(0);
default:
logError(`Unknown option: ${arg}`);
process.exit(1);
}
}
return options;
}
function showHelp(): void {
const help = `
${c.bold}compile-claude${c.reset} ${c.dim}— semantic CLAUDE.md compiler${c.reset}
Compresses CLAUDE.src.md into CLAUDE.md using LLM semantic compression.
Source+Compiled pattern: you edit .src.md, this tool produces .md
${c.bold}Usage:${c.reset}
compile-claude [options]
${c.bold}Options:${c.reset}
--print Preview compressed output + stats (don't write)
--model <name> Claude model to use [default: sonnet]
--source <file> Source file path [default: ./CLAUDE.src.md]
--output <file> Output file path [default: ./CLAUDE.md]
--timeout <ms> Inference timeout in ms [default: 120000]
-h, --help Show help
${c.bold}Examples:${c.reset}
compile-claude # Compress ./CLAUDE.src.md -> ./CLAUDE.md
compile-claude --print # Preview without writing
compile-claude --model haiku # Use Haiku for faster compression
compile-claude --source custom.md # Use different source file
`;
console.log(help);
}
/**
* Run inference via Claude CLI.
* Uses `claude --print` which works with both API keys and subscription auth.
*/
async function runInference(
systemPrompt: string,
userPrompt: string,
model: string,
timeout: number
): Promise<{ success: boolean; output: string; error?: string; latencyMs: number }> {
const start = Date.now();
try {
const proc = Bun.spawn(
["claude", "--print", "--model", model, "--output-format", "text", "-p", userPrompt],
{
stdin: "ignore",
stdout: "pipe",
stderr: "pipe",
env: {
...process.env,
CLAUDE_CODE_SYSTEM_PROMPT: systemPrompt,
},
}
);
const timeoutId = setTimeout(() => proc.kill(), timeout);
const [stdout, stderr] = await Promise.all([
new Response(proc.stdout).text(),
new Response(proc.stderr).text(),
]);
clearTimeout(timeoutId);
const exitCode = await proc.exited;
const latencyMs = Date.now() - start;
if (exitCode !== 0) {
return { success: false, output: "", error: stderr || `Exit code ${exitCode}`, latencyMs };
}
return { success: true, output: stdout.trim(), latencyMs };
} catch (err: unknown) {
const latencyMs = Date.now() - start;
const message = err instanceof Error ? err.message : String(err);
return { success: false, output: "", error: message, latencyMs };
}
}
async function main(): Promise<void> {
const options = parseArgs();
const startTime = Date.now();
// Validate prompt file exists
if (!existsSync(PROMPT_FILE)) {
logError(`Error: Prompt file not found: ${PROMPT_FILE}`);
logError(`Place prompt.txt in the same directory as this script.`);
process.exit(1);
}
// Validate claude CLI is available
const which = Bun.spawnSync(["which", "claude"]);
if (which.exitCode !== 0) {
logError(`Error: 'claude' CLI not found in PATH.`);
logError(`Install: https://docs.anthropic.com/en/docs/claude-code`);
process.exit(1);
}
// First-run: offer to create CLAUDE.src.md from CLAUDE.md
if (!existsSync(options.source)) {
if (existsSync(options.output)) {
log(`${c.yellow}No source file found: ${options.source}${c.reset}`);
log(`${c.blue}Found existing: ${options.output}${c.reset}`);
log("");
const confirmed = await promptYesNo(
`Copy ${options.output} -> ${options.source} as initial source? [Y/n] `
);
if (confirmed) {
copyFileSync(options.output, options.source);
log(`${c.green}Created ${options.source} from ${options.output}${c.reset}`);
log(`${c.dim}Edit ${options.source}, then run compile-claude again.${c.reset}`);
process.exit(0);
} else {
logError(`Aborted. Create ${options.source} manually.`);
process.exit(1);
}
} else {
logError(`Error: Source file not found: ${options.source}`);
log(`${c.dim}Create CLAUDE.src.md or specify --source <path>${c.reset}`);
process.exit(1);
}
}
// Read inputs
const systemPrompt = readFileSync(PROMPT_FILE, "utf-8");
const sourceContent = readFileSync(options.source, "utf-8");
// Stats: before
const sourceBytes = Buffer.byteLength(sourceContent, "utf-8");
const sourceLines = sourceContent.split("\n").length;
const sourceTokens = Math.floor(sourceBytes / 4);
// Header
log(`${c.bold}compile-claude${c.reset} ${c.dim}— semantic CLAUDE.md compiler${c.reset}`);
log(`${c.dim}──────────────────────────────────────────────${c.reset}`);
log(` Source: ${c.blue}${options.source}${c.reset} (${sourceBytes} bytes, ~${sourceTokens} tokens, ${sourceLines} lines)`);
log(` Model: ${c.blue}${options.model}${c.reset} (timeout: ${options.timeout}ms)`);
log(`${c.dim}──────────────────────────────────────────────${c.reset}`);
log("");
// Compress
log(`${c.yellow}Compressing...${c.reset}`);
const result = await runInference(systemPrompt, sourceContent, options.model, options.timeout);
if (!result.success || !result.output) {
logError(`Error: Inference failed - ${result.error || "empty output"}`);
process.exit(1);
}
const compressed = result.output;
// Stats: after
const compressedBytes = Buffer.byteLength(compressed, "utf-8");
const compressedLines = compressed.split("\n").length;
const compressedTokens = Math.floor(compressedBytes / 4);
const reduction = sourceBytes > 0 ? Math.floor(((sourceBytes - compressedBytes) / sourceBytes) * 100) : 0;
const savedBytes = sourceBytes - compressedBytes;
const elapsed = Date.now() - startTime;
// Output stats
log("");
log(`${c.bold}Stats:${c.reset}`);
log(`${c.dim}──────────────────────────────────────────────${c.reset}`);
log(` Before: ${sourceBytes} bytes (~${sourceTokens} tokens, ${sourceLines} lines)`);
log(` After: ${compressedBytes} bytes (~${compressedTokens} tokens, ${compressedLines} lines)`);
log(` Saved: ${c.green}${savedBytes} bytes (${reduction}% reduction)${c.reset}`);
log(` Time: ${c.blue}${(elapsed / 1000).toFixed(1)}s${c.reset} (inference: ${result.latencyMs}ms)`);
log(`${c.dim}──────────────────────────────────────────────${c.reset}`);
if (options.printOnly) {
log("");
log(`${c.bold}Preview:${c.reset}`);
log(`${c.dim}──────────────────────────────────────────────${c.reset}`);
log(compressed);
log(`${c.dim}──────────────────────────────────────────────${c.reset}`);
log("");
log(`${c.yellow}Dry run — no files written. Remove --print to compile.${c.reset}`);
} else {
writeFileSync(options.output, compressed);
log("");
log(`${c.green}Wrote: ${options.output}${c.reset} (${compressedBytes} bytes)`);
}
}
// Run
if (import.meta.main) {
main().catch((err) => {
logError(`Fatal error: ${err.message}`);
process.exit(1);
});
}
You are a semantic compression engine for LLM instruction files (CLAUDE.md).
Your job: rewrite the input to be maximally dense while preserving 100% of semantic meaning. The output will be read by an LLM, not a human — optimize for machine comprehension.
CRITICAL PRESERVATION RULES — NEVER modify these:
1. ALL marker blocks (<!-- *-START --> to <!-- *-END -->) must be reproduced EXACTLY byte-for-byte, including their content between markers.
2. ALL XML blocks (<ToolPolicy>, <system-reminder>, or any XML tag blocks) must be reproduced EXACTLY byte-for-byte.
3. ALL code blocks (``` fenced) must be preserved EXACTLY — code is already dense.
4. ALL file paths, URLs, command examples must be preserved EXACTLY.
COMPRESSION RULES — apply to everything else:
- Tables: convert to pipe-delimited single lines (e.g., "col1|col2|col3;row1a|row1b|row1c;row2a|row2b|row2c")
- Bullet lists: convert to semicolon-separated inline text
- Headers: convert "## Section Name" to "[Section Name]"
- Prose paragraphs: rewrite to maximum density, abbreviate ruthlessly (e.g., "you should always" -> "always", "in order to" -> "to", "make sure to" -> "ensure")
- Remove ALL bold/italic markers (** and *)
- Remove ALL blank lines, horizontal rules (---), decorative elements
- Remove redundant words, filler phrases, unnecessary articles
- Collapse whitespace — single space between elements
- Merge related short sections into single dense blocks
- Remove section numbers if content is self-evident
OUTPUT RULES:
- Output ONLY the compressed content
- NO commentary, explanations, or meta-text
- NO "Here is the compressed version:" preamble
- Start directly with the compressed content
- End with the last line of compressed content, nothing after
TARGET: 50-70% byte reduction from input.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment