{"_rev":"3-558eff3bd54b4c6e71335e4626e086a1","time":{"created":"2026-04-24T09:31:11.181Z","modified":"2026-04-24T09:31:11.707Z","1.1.0":"2026-04-24T09:09:07.701Z","1.0.0":"2026-04-24T09:31:11.482Z"},"_id":"@antonisoaho/claudekeeper","name":"@antonisoaho/claudekeeper","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@antonisoaho/claudekeeper","version":"1.0.0","description":"Session management and token optimization for Claude Code","type":"module","bin":{"claudekeeper":"dist/cli.js"},"main":"./dist/index.js","types":"./dist/index.d.ts","scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest run","test:watch":"vitest","lint":"tsc --noEmit","prepublishOnly":"npm run build","postinstall":"node ./dist/postinstall.js || true"},"keywords":["claude","claude-code","token","cache","optimization","cli"],"license":"MIT","repository":{"type":"git","url":"git+https://github.com/antonisoaho/claudekeeper.git"},"publishConfig":{"access":"public"},"engines":{"node":">=20.0.0"},"dependencies":{"commander":"^13.1.0","cosmiconfig":"^9.0.0"},"devDependencies":{"@types/node":"^22.15.0","@vitest/coverage-v8":"^3.2.4","tsup":"^8.4.0","typescript":"^5.8.3","vitest":"^3.1.1"},"gitHead":"082a3e9ce3ee3606946c933cf732892afbdae821","_id":"@antonisoaho/claudekeeper@1.0.0","bugs":{"url":"https://github.com/antonisoaho/claudekeeper/issues"},"homepage":"https://github.com/antonisoaho/claudekeeper#readme","_nodeVersion":"24.14.1","_npmVersion":"11.11.0","dist":{"integrity":"sha512-gBiRLUYo3DEVzWjx5ljN6J03JDNZzMcLjn/KwBwADZEcYVbnTuN3+Rk72GCCYleTZOLCOSeQuUINC6IXo6hd1A==","shasum":"dba35262ac9763ffc04c67af01389ef17d6d3c13","tarball":"https://registry.npmjs.org/@antonisoaho/claudekeeper/-/claudekeeper-1.0.0.tgz","fileCount":55,"unpackedSize":965044,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQD1Qusyv3izFFe9zRPCrm3F9gUx2+l0J1ZqnXLL3LyO6QIhAK8SVwd392oze10z/rSDCKBhcZnwr9uhj1amxEQbRtCa"}]},"_npmUser":{"name":"antonisoaho","email":"isoahoanton@gmail.com"},"directories":{},"maintainers":[{"name":"antonisoaho","email":"isoahoanton@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/claudekeeper_1.0.0_1777023071293_0.6648655035572013"},"_hasShrinkwrap":false}},"maintainers":[{"name":"antonisoaho","email":"isoahoanton@gmail.com"}],"description":"Session management and token optimization for Claude Code","homepage":"https://github.com/antonisoaho/claudekeeper#readme","keywords":["claude","claude-code","token","cache","optimization","cli"],"repository":{"type":"git","url":"git+https://github.com/antonisoaho/claudekeeper.git"},"bugs":{"url":"https://github.com/antonisoaho/claudekeeper/issues"},"license":"MIT","readme":"# claudekeeper\n\n**Stop Claude Code from burning through your quota in 20 minutes.**\n\n---\n\n## The problem\n\nEvery turn in a Claude Code session re-sends your entire conversation history to the API. A fresh session sends ~20k tokens per turn. A 200-turn session sends ~200k per turn. **Same work, 10x more quota.**\n\n```\nTurn    1: ██ 20k tokens\nTurn   50: ██████████ 100k tokens\nTurn  200: ████████████████████ 200k tokens\n```\n\nThis is why your session limit gets hit fast. Sessions grow linearly and nobody tells you to start fresh.\n\n## The solution\n\nclaudekeeper monitors session size, **blocks Claude when you're wasting quota**, saves your progress, and auto-rotates to a fresh session — no manual steps.\n\n```bash\nclaudekeeper run\n```\n\nThat's your daily driver. It wraps `claude` and handles everything:\n\n1. You work normally\n2. Waste factor hits threshold → session blocked → handoff saved\n3. Fresh session starts automatically with context injected\n4. Claude continues where you left off\n5. Repeat (up to 10 rotations by default)\n\n## Install\n\n```bash\nnpm install -g @antonisoaho/claudekeeper\nclaudekeeper install\n```\n\n`claudekeeper install` registers hooks into `~/.claude/settings.json`, installs skills (`/save-skill`, `/claudekeeper-continue`), writes default config, and auto-calibrates the rotation threshold from your session history.\n\nRequires Node.js 20+.\n\n## How to continue a session\n\nThree ways, depending on where you are:\n\n| Method | When to use |\n|---|---|\n| `claudekeeper run` | Best. Auto-rotates and continues automatically |\n| `claudekeeper continue` | From terminal. Spawns fresh `claude` with handoff injected |\n| `/claudekeeper-continue` | From within Claude Code. Reads handoff in current session |\n\nAll three read from `~/.claudekeeper/sessions/` — no copy-pasting paths.\n\n## How it works\n\nclaudekeeper registers 7 hooks into Claude Code:\n\n### `UserPromptSubmit` — blocks before tokens are wasted\n\nBefore Claude processes your prompt, checks the waste factor. If the session is burning too much quota, it blocks with exit code 2, saves context, and tells you to start fresh.\n\nAlso detects \"continue\" prompts (\"continue\", \"resume\", \"pick up where I left off\") and seamlessly injects the most recent handoff as context — no blocking, no copy-paste.\n\n```\nWaste factor = current tokens/turn ÷ baseline tokens/turn\n\n  1x = efficient (fresh session)\n  5x = growing\n 10x = blocked — start fresh\n```\n\nThe threshold auto-calibrates from your session history via `claudekeeper calibrate`.\n\n### `PostToolUse` — blocks during autonomous work + compresses output\n\nWhen Claude works autonomously, there's no user prompt to intercept. PostToolUse checks waste factor after each tool call and blocks if too high.\n\nAlso handles:\n- **Bash output compression** — large command outputs are compressed before hitting Claude's context\n- **Error tracking** — records command failures and successful fixes to the project's error index\n- **File tracking** — records which files are edited/read across sessions\n- **Cache degradation detection** — warns when prompt cache breaks down\n- **Token spike detection** — flags abnormal token consumption\n- **Resume anomaly detection** — catches issues from session resumes\n- **Known buggy version detection** — warns about Claude Code 2.1.69–2.1.89 (broken prompt cache)\n\n### `SessionStart` — injects previous session context\n\nOn every new session, reads saved handoff files and injects them into Claude's context. If a handoff exists, Claude presents the choice: continue or start fresh. Also checks recent session history for health issues (cache degradation, loop patterns) and prunes stale state files.\n\n### `PreCompact` / `PostCompact` — saves context around compaction\n\nPreCompact saves a fallback before compaction. PostCompact captures Claude's own LLM summary merged with mechanically extracted data (files, commits, commands).\n\n### `Stop` — blocks infinite loops\n\nWhen Claude repeats the same tool call 3+ times with identical input/output, Stop blocks it and saves session state.\n\n### `PreToolUse` — prevents known errors\n\nBefore Claude runs a Bash command, checks the project's error index for previous failures. If a known fix exists, injects it as context so Claude can avoid repeating the same mistake.\n\n```\n[claudekeeper]: `npm run build` has failed 5 times on this project.\nLast error: Module not found: Cannot resolve @/lib/db\nKnown fix: `npx drizzle-kit push && npm run build`\n```\n\n## Session handoff format\n\nWhen claudekeeper blocks a session, it tells Claude to write a structured handoff:\n\n```\nTASK: (what you were working on)\nCOMPLETED: (what's done)\nIN_PROGRESS: (what's partially done, with file paths)\nFAILED_APPROACHES: (what was tried and didn't work, and WHY)\nDECISIONS: (choices made and why)\nUSER_PREFERENCES: (what the user asked for or rejected)\nBLOCKERS: (unresolved issues)\n```\n\nThis is merged with mechanical data extracted from the JSONL transcript (files modified, git commits, commands, test results). Together they give the next session the best starting point.\n\nEach handoff is saved as a timestamped file under `~/.claudekeeper/sessions/<project>/`. Files older than 24h are cleaned up automatically.\n\n## Commands\n\n| Command | Description |\n|---|---|\n| `claudekeeper run` | Run claude with auto-rotation (recommended daily driver) |\n| `claudekeeper continue` | Start fresh claude with handoff injected |\n| `claudekeeper install` | Register hooks + skills + config + calibrate |\n| `claudekeeper uninstall` | Remove hooks and skills |\n| `claudekeeper status` | Quick health check (supports `--json`) |\n| `claudekeeper report` | Quota usage report — where your tokens went |\n| `claudekeeper time` | Token usage by hour of day |\n| `claudekeeper sessions` | Per-session breakdown with spike detection |\n| `claudekeeper activity` | Recent actions log (warnings, blocks, loops) |\n| `claudekeeper stats` | Historical usage analysis with cost estimates |\n| `claudekeeper doctor` | Scan for cache degradation |\n| `claudekeeper calibrate` | Auto-calibrate rotation threshold from history |\n| `claudekeeper knowledge` | Show accumulated errors and file activity |\n| `claudekeeper check-memory` | Audit CLAUDE.md token footprint |\n| `claudekeeper share` | Copy-pasteable usage summary |\n\nMost commands support `--json` for machine-readable output and `-p, --project <path>` for project filtering.\n\n## Configuration\n\nEverything works out of the box. Config at `~/.claudekeeper/config.json` (created automatically on install):\n\n```json\n{\n  \"rotation\": {\n    \"enabled\": true,\n    \"writeToClaudeMd\": true,\n    \"tokensPerTurnThreshold\": 100000,\n    \"minTurns\": 30\n  },\n  \"alerts\": {\n    \"cacheBugThreshold\": 3,\n    \"loopDetectionThreshold\": 3,\n    \"claudeMdTokenWarning\": 4000,\n    \"desktopNotifications\": true\n  },\n  \"bashFilter\": {\n    \"enabled\": true,\n    \"maxOutputChars\": 2000,\n    \"preservePatterns\": [\"error\", \"warn\", \"fail\", \"exception\"],\n    \"noisePatterns\": [\"npm warn\", \"added \\\\d+ packages\", \"\\\\[=+\"]\n  },\n  \"watch\": {\n    \"projectsDir\": \"~/.claude/projects\",\n    \"pollInterval\": 1000\n  }\n}\n```\n\n## Development\n\n```bash\ngit clone https://github.com/antonisoaho/claudekeeper.git\ncd claudekeeper\nnpm install\nnpm test\nnpm run build\nnpm link  # links local build as global command\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}