***
> [!NOTE]
> This repo has been archived by the author. It's no longer receiving updates and remains public just for reference. Please continue to respect [LICENSE](LICENSE).
***
# Claude Code Goblin




> [!WARNING]
> This project is in active development (pre-1.0.0). Issues are not actively tracked until version 1.0.0 is released. Features may change without notice.
Python command line tool to help with Claude Code utilities and Claude Code usage analytics and long-term tracking.
**Quick Start:** Install with `pip install claude-goblin` and use `ccg --help` for commands or `ccg usage` to start tracking. Below are some examples of outputs that this command line can give you.
> [!NOTE]
> Both `claude-goblin` and `ccg` work interchangeably as command aliases.
## Example outputs
**TUI Dashboard:**

---
**GitHub activity-style heatmap of annual usage:**

---
> [!NOTE]
> This tool was developed and tested on macOS (Python 3.13). Should work on Linux and Windows but is untested on those platforms.
## Features
- Local snapshotting of Claude Code logs for analytics
- Dashboard and stats of usage history
- Project anonymization for sharing screenshots (`--anon` flag)
- Hook setup to automate data logging or analysis of Claude Code
- Audio notifications for Claude Code completion, permission requests, and conversation compaction
- Text-to-speech (TTS) notifications with customizable hook selection (macOS only)
- Devcontainer setup for safe `--dangerously-skip-permissions` execution
## Installation
### From PyPI (recommended)
```bash
# Install from PyPI (uv recommended)
uv pip install claude-goblin
# Or with pip
pip install claude-goblin
# Optional: Install export dependencies for PNG/SVG generation
uv pip install "claude-goblin[export]"
```
### From source
```bash
# Clone the repository
git clone https://github.com/data-goblin/claude-goblin.git
cd claude-goblin
# Install with uv (recommended)
uv pip install -e .
# Or with pip
pip install -e .
# Optional: Install export dependencies
uv pip install -e ".[export]"
```
## First-Time Setup
After installation, ensure the `claude` CLI is in your PATH, then start tracking:
```bash
# Verify claude CLI is accessible
which claude
# View your current usage dashboard
ccg usage
# (Optional) Enable automatic tracking with hooks
ccg setup hooks usage
```
**Note**: The `usage` command automatically saves your data to the historical database every time you run it. No manual setup required. If `claude` is not in your PATH, see [Troubleshooting](#troubleshooting) below.
### Commands Explained
- **`update usage`**: Update historical database with latest data and fill in missing date gaps with empty records (use when you want continuous date coverage for the heatmap)
For most users, just run `usage` regularly and it will handle data tracking automatically. Use `setup hooks usage` to automate this completely.
## Commands
| Command | Description |
|---------|-------------|
| **Dashboard & Analytics** | |
| `ccg usage` | Show usage dashboard with KPI cards and breakdowns |
| `ccg usage --live` | Auto-refresh dashboard every 5 seconds |
| `ccg usage --fast` | Skip updates for faster rendering |
| `ccg usage --anon` | Anonymize project names (project-001, project-002, etc.) |
| `ccg stats` | Show detailed statistics and cost analysis |
| `ccg stats --fast` | Skip updates for faster rendering |
| **Export** | |
| `ccg export` | Export yearly heatmap as PNG (default) |
| `ccg export --svg` | Export as SVG image |
| `ccg export --open` | Export and open the image |
| `ccg export -y 2024` | Export specific year |
| `ccg export -o output.png` | Specify output file path |
| **Data Management** | |
| `ccg update usage` | Update historical database with latest data |
| `ccg update usage --rebuild` | Repair inflated history from surviving transcripts |
| `ccg remove usage --force` | Delete historical database (requires --force) |
| `ccg restore usage` | Restore from backup |
| **Setup** | |
| `ccg setup hooks usage` | Auto-track usage after each Claude response |
| `ccg setup hooks audio` | Play sounds for completion, permission & compaction |
| `ccg setup hooks audio-tts` | Speak notifications using TTS (macOS, multi-hook) |
| `ccg setup hooks png` | Auto-generate PNG after each response |
| `ccg setup hooks uv-standard` | Enforce uv instead of pip/pip3 |
| `ccg setup hooks bundler-standard` | Enforce Bun instead of npm/pnpm/yarn |
| `ccg setup hooks file-name-consistency` | Ensure consistent file naming |
| `ccg setup container` | Setup devcontainer for safe Claude Code execution |
| **Remove** | |
| `ccg remove hooks [type]` | Remove hooks (any hook type, or all) |
| `ccg remove usage --force` | Delete historical database (with backup) |
## Sync
Push usage data from the local database to one or more remote sinks so a team
(or your own fleet of machines) gets a centralized view. Two sinks are
supported and can run in parallel from a single `ccg sync push`:
| Provider | Target | Transport |
|----------|--------|-----------|
| `quack` | A remote DuckDB server | Quack protocol (e.g. over Tailscale) |
| `onelake` | A Microsoft Fabric lakehouse | Delta Lake merges over OneLake (delta-rs) |
Both sinks are watermark-incremental and idempotent - cheap when there is
nothing new.
### Counting model
Tokens are counted once per BILLED API response: records are keyed on the
API `message.id` + `requestId`, globally across sessions. This collapses
Claude Code's streaming-flush duplicate entries and session-fork history
replays, matching how ccusage counts. Databases populated by older ccg
versions overstate tokens (every flush entry was counted); repair with:
```bash
ccg update usage --rebuild
```
The repair backs up the database, re-ingests every session whose transcript
still exists on disk, and leaves rows beyond the ~30-day transcript
retention untouched (they are the only surviving record of that usage and
keep the old counting). After a rebuild, quack pushes are blocked until the
remote's old rows are purged (`ccg sync push --quack-purged --full` once
done); the OneLake sink self-corrects with `ccg sync push --full`.
Aggregate storage mode tracks each file's last contribution and applies only
the delta on reparse, so growing session files no longer re-add their whole
history on every update. Prefer `--storage duckdb` with
`"storage_mode": "full"` for exact accounting.
### OneLake (Microsoft Fabric)
Everything is configured per user - bring your own tenant, workspace,
capacity, and lakehouse. Requirements: `pip install "claude-goblin[onelake]"`,
the [fab CLI](https://microsoft.github.io/fabric-cli/) plus `az login` into
your tenant, and any Fabric capacity.
```bash
ccg sync setup --provider onelake --workspace <YourWorkspace> --lakehouse <YourLakehouse>
ccg sync push
```
Setup resolves and stores your workspace/lakehouse ids and tenant via fab/az.
Pushes merge `usage_daily` (daily aggregates per device, model, project
folder, and git branch - token totals and counts only, never message
content or session/message ids), `model_pricing`, and a `devices` dimension
(device -> user/organization/subscription attribution) into Delta tables,
creating them on first push. Optional config keys under
`sync_config.onelake`:
```json
{
"device_filter": ["only-these-device-ids-leave-this-machine"],
"min_push_interval": 900,
"compact_every": 50,
"semantic_model_id": "<set by scripts/create_semantic_model.py --store-id>"
}
```
`device_filter` scopes the push (and its new-data check) to selected device
ids - useful when one machine tracks several profiles but only some may be
shared. Hook-driven pushes respect `min_push_interval`; explicit `ccg sync
push` does not. Every `compact_every` pushes the sink compacts and vacuums
its Delta tables.
To query the lakehouse with DAX, create a Direct Lake semantic model over the
pushed tables (relationships plus token/cost measures included):
```bash
python3 scripts/create_semantic_model.py --store-id
ccg sync query -q 'EVALUATE ROW("Cost", [Est API Cost], "Tokens", [Total Tokens])' # or slice by folder/branch/model/device
```
`Est API Cost` is an estimate at list API prices - subscription plans are
never billed these amounts; treat it as an API-equivalent value metric.
### Automatic pushes
`ccg update usage --push` runs ingest then pushes to every configured sink,
skipping quietly on machines without one - suitable for a Claude Code Stop
hook. Check sink state at any time with `ccg sync status`.
## Data Source
Claude Goblin reads usage data from Claude Code's local session logs:
```
~/.claude/projects/*.jsonl
```
**Important**: Claude Code retains session logs for approximately **30 days** (rolling window). There is no way to get other historical data without contacting Anthropic support. Claude Goblin solves this by:
- Automatically saving data to an SQLite database (`~/.claude/usage/usage_history.db`) whenever you run `--usage`
- Preserving historical data indefinitely
- Merging current + historical data for complete analytics
- Configuration to choose between saving detailed or aggregate data
## How It Works
```mermaid
graph TD
A[Claude Code] -->|writes| B[JSONL Files<br/>~/.claude/projects/*.jsonl]
A -.->|triggers| H[Hooks]
B --> ING{Ingestion<br/>--usage<br/>--update-usage}
H -.->|automates| ING
ING --> DB[(Database<br/>~/.claude/usage/usage_history.db)]
DB --> CMD1{--usage}
DB --> CMD2{--stats}
DB --> CMD3{--export}
CMD1 --> OUT1[TUI Dashboard]
CMD2 --> OUT2[Summary Stats<br/>in Terminal]
CMD3 --> OUT3[Annual Activity PNG]
H -.->|automates| CMD3
style A fill:#e0e0e0,stroke:#333,color:#000
style B fill:#ff8800,stroke:#333,color:#000
style DB fill:#4a9eff,stroke:#333,color:#fff
style OUT1 fill:#90ee90,stroke:#333,color:#000
style OUT2 fill:#90ee90,stroke:#333,color:#000
style OUT3 fill:#90ee90,stroke:#333,color:#000
style H fill:#ffeb3b,stroke:#333,color:#000
```
**Key Points:**
- **JSONL files** are raw logs with a 30-day rolling window (older data disappears)
- **Ingestion** step reads JSONL and saves to DB (with automatic deduplication via `UNIQUE` constraint)
- **Database** is the single source of truth - all display commands read from here only
- **Hooks** can automate ingestion after each Claude response
### Command Behavior
**`ccg usage`** (Display + Ingestion)
1. **Ingestion**: Reads JSONL files from `~/.claude/projects/*.jsonl` and saves to DB
2. **Display**: Reads data from DB and renders dashboard
**`ccg export`** (Display only)
1. Reads data from DB at `~/.claude/usage/usage_history.db`
2. Generates yearly heatmap
3. Exports to current directory as `claude-usage-<timestamp>.png` (or specify with `-o`)
**`ccg stats`** (Display + Ingestion)
1. **Ingestion**: Reads JSONL files from `~/.claude/projects/*.jsonl` and saves to DB
2. **Display**: Reads data from DB and displays comprehensive statistics
**`ccg update-usage`** (Ingestion only)
1. Reads JSONL files from `~/.claude/projects/*.jsonl`
2. Saves to DB at `~/.claude/usage/usage_history.db` (with automatic deduplication)
3. Fills in missing dates with empty records (ensures continuous heatmap)
### File Locations
| File | Location | Purpose |
|------|----------|---------|
| **JSONL logs** | `~/.claude/projects/*.jsonl` | Current 30-day usage data from Claude Code |
| **SQLite DB** | `~/.claude/usage/usage_history.db` | Historical usage data preserved indefinitely |
| **Default exports** | `~/.claude/usage/claude-usage-<timestamp>.png` | PNG/SVG heatmaps (default location unless `-o` is used) |
| **Hook exports** | `~/.claude/usage/claude-usage.png` | Default location for PNG hook auto-updates |
## --usage TUI dashboard
Example TUI:

## --export Heatmap
Export a GitHub-style yearly activity heatmap:
```bash
ccg export --open
```
Example heatmap:

### --export Formats
- **PNG** (default): `ccg export`
## Hooks
Claude Goblin can integrate with Claude Code's hook system to automate various tasks. Hooks trigger automatically based on Claude Code events.
### Claude Goblin Hook Types
#### Usage Hook
Automatically tracks usage data after each Claude response:
```bash
ccg setup hooks usage
```
This adds a hook that runs `ccg update usage` after each Claude response, keeping your historical database up-to-date.
#### Audio Hook
Plays system sounds for three different events:
```bash
ccg setup hooks audio
```
You'll be prompted to select three sounds:
1. **Completion sound**: Plays when Claude finishes responding
2. **Permission sound**: Plays when Claude requests permission
3. **Compaction sound**: Plays before conversation compaction
Supports macOS (10 built-in sounds), Windows, and Linux.
#### Audio TTS Hook (macOS only)
Speaks notifications aloud using macOS text-to-speech:
```bash
ccg setup hooks audio-tts
```
**Multi-hook selection** - Choose which events to speak:
1. Notification only (permission requests) - **[recommended]**
2. Stop only (when Claude finishes responding)
3. PreCompact only (before conversation compaction)
4. Notification + Stop
5. Notification + PreCompact
6. Stop + PreCompact
7. All three (Notification + Stop + PreCompact)
You can also select from 7 different voices (Samantha, Alex, Daniel, Karen, Moira, Fred, Zarvox).
**Example messages:**
- Notification: Speaks the permission request message
- Stop: "Claude finished responding"
- PreCompact: "Auto compacting conversation" or "Manually compacting conversation"
#### PNG Hook
Auto-generates usage heatmap PNG after each Claude response:
```bash
ccg setup hooks png
```
Requires export dependencies: `pip install "claude-goblin[export]"`
### Awesome-hooks (PreToolUse)
Claude Goblin includes PreToolUse hooks from [awesome-hooks](https://github.com/boxabirds/awesome-hooks) by [@boxabirds](https://github.com/boxabirds), plus a custom Python/uv enforcement hook. These hooks intercept and validate commands before they execute.
#### uv-standard Hook
Enforces uv usage instead of pip/pip3:
```bash
ccg setup hooks uv-standard
```
**What it does:**
- Intercepts pip/pip3 commands in Bash
- Blocks them and suggests uv equivalents
- Ensures you use uv for Python package management
**Requirements:** uv package installer ([installation](https://github.com/astral-sh/uv))
#### bundler-standard Hook
Enforces Bun usage instead of npm/pnpm/yarn:
```bash
ccg setup hooks bundler-standard
```
**What it does:**
- Intercepts npm/pnpm/yarn commands in Bash
- Blocks them and suggests Bun equivalents
- Ensures you use Bun for JavaScript package management
**Requirements:** Bun runtime ([installation](https://bun.sh))
#### file-name-consistency Hook
Ensures consistent file naming conventions:
```bash
ccg setup hooks file-name-consistency
```
**What it does:**
- Analyzes your project's file naming patterns using AI
- Blocks files with inconsistent naming
- Suggests correctly formatted filenames
**Requirements:** GEMINI_API_KEY environment variable ([get your key](https://aistudio.google.com/apikey))
Set the API key in your shell profile:
```bash
export GEMINI_API_KEY="your-api-key-here"
```
### Removing Hooks
```bash
# Remove specific hook type
ccg remove hooks usage
ccg remove hooks audio
ccg remove hooks audio-tts
ccg remove hooks png
ccg remove hooks uv-standard
ccg remove hooks bundler-standard
ccg remove hooks file-name-consistency
# Remove all Claude Goblin hooks
ccg remove hooks
```
## Project Anonymization
The `--anon` flag anonymizes project names when displaying usage data, perfect for sharing screenshots:
```bash
ccg usage --anon
ccg stats --anon
```
Projects are renamed to `project-001`, `project-002`, etc., ranked by total token usage (project-001 has the highest usage).
## Historical Data
Claude Goblin automatically saves data every time you run `usage`. To manually manage:
```bash
# View historical stats
ccg stats
# Update database with latest data and fill date gaps
ccg update usage
# Delete all history (creates backup first)
ccg remove usage -f
# Restore from backup
ccg restore usage
```
## What It Tracks
- **Tokens**: Input, output, cache creation, cache read (by model and project)
- **Prompts**: User prompts and assistant responses
- **Sessions**: Unique conversation threads
- **Models**: Which Claude models you've used (Sonnet, Opus, Haiku)
- **Projects**: Folders/directories where you've used Claude
- **Time**: Daily activity patterns throughout the year
It will also compute how much you would have had to pay if you used API pricing instead of a $200 Max plan.
## Technical Details
### Timezone Handling
All timestamps in Claude Code's JSONL files seem to be stored in **UTC**. Claude Goblin should convert to your **local timezone** when grouping activity by date. This has only been tested with European CET.
### Cache Efficiency
The token breakdown shows cache efficiency. High "Cache Read" percentages (80-90%+) mean Claude Code is effectively reusing context, which:
- Speeds up responses
- Can reduce costs on usage-based plans
- Indicates good context management
## Requirements
- Python >= 3.10
- Claude Code (for generating usage data)
- Rich >= 13.7.0 (terminal UI)
- rumps >= 0.4.0 (macOS menu bar app, macOS only)
- Pillow + CairoSVG (optional, for PNG/SVG export)
## License
MIT License - see LICENSE file for details
## Contributing
Contributions welcome! Please:
1. Fork the repository
2. Create a feature branch
3. Submit a pull request
I don't have much time but I'll review PRs when I can.
## Docker Development (Sandboxed Claude Code)
The `.devcontainer/` directory provides a Docker-based development environment for running Claude Code with `--dangerously-skip-permissions` in a safe, network-restricted container.
### Why Use This?
- **Network isolation**: Firewall restricts outbound traffic to only essential services (Anthropic APIs, GitHub, PyPI)
- **Safe `--dangerously-skip-permissions`**: Claude Code can execute commands freely within the container without affecting your host system
- **Reproducible environment**: Consistent Python + uv + Claude Code setup
### Quick Start (devcontainer CLI)
The devcontainer CLI is the recommended way to use this setup.
```bash
# Install devcontainer CLI (one-time)
npm install -g @devcontainers/cli
# Start the container (from repo root)
devcontainer up --workspace-folder .
# Run Claude Code inside the container
devcontainer exec --workspace-folder . claude --dangerously-skip-permissions
```
### Alternative: Direct Docker
```bash
# 1. Build the image (from repo root, using -f to specify Dockerfile)
docker build -t claude-goblin-dev -f .devcontainer/Dockerfile .
# 2. Run the container
docker run -it --cap-add=NET_ADMIN --cap-add=NET_RAW \
-v "$(pwd):/workspace" \
-v claude-goblin-claudeconfig:/home/dev/.claude \
-e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
claude-goblin-dev
# 3. Inside container: initialize firewall
sudo /usr/local/bin/init-firewall.sh
# 4. Run Claude Code with skip-permissions
claude --dangerously-skip-permissions
```
### VS Code Dev Containers
If you use VS Code with the Dev Containers extension:
1. Open this folder in VS Code
2. Click "Reopen in Container" when prompted (or use Command Palette > "Dev Containers: Reopen in Container")
3. The container will build and start with firewall initialized
4. Open a terminal and run `claude --dangerously-skip-permissions`
### What the Firewall Allows
| Service | Purpose |
|---------|---------|
| api.anthropic.com | Claude API |
| claude.ai | Claude web |
| pypi.org, files.pythonhosted.org | Python packages |
| github.com (full IP ranges) | Git operations |
| registry.npmjs.org | npm packages |
All other outbound connections are blocked and logged.
## Troubleshooting
### "No Claude Code data found"
- Ensure Claude Code is installed and you've used it at least once
- Check that `~/.claude/projects/` exists and contains `.jsonl` files
### "Claude Code CLI not found in PATH"
If you see this error, the `claude` command is not accessible. To fix:
```bash
# Check if claude is installed
which claude
# If not found, add to PATH (adjust path based on your installation)
# For zsh (default on macOS):
echo 'export PATH="$HOME/Library/Application Support/Claude/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
# For bash:
echo 'export PATH="$HOME/Library/Application Support/Claude/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
# Verify it works
claude --version
```
### Export fails
- Install export dependencies: `pip install -e ".[export]"`
- For PNG: requires Pillow and CairoSVG
### Database errors
- Try deleting and recreating: `ccg remove usage --force`
- Then run: `ccg usage` to rebuild from current data
## **AI Tools Disclaimer**:
This project was developed with assistance from Claude Code.
## Credits
Built with:
- [Rich](https://github.com/Textualize/rich) - Terminal UI framework
- [Pillow](https://python-pillow.org/) - Image processing (optional)
- [CairoSVG](https://cairosvg.org/) - SVG to PNG conversion (optional)
Includes hooks from:
- [awesome-hooks](https://github.com/boxabirds/awesome-hooks) by [@boxabirds](https://github.com/boxabirds) - PreToolUse hooks for enforcing development standards
See [docs/attributions.md](docs/attributions.md) for full attribution details.