
Install Skill Tracker
- 10 installs
- 2 repo stars
- Updated August 1, 2026
- vishalsachdev/claude-skills
Helps with ai & agent building tasks.
About
install-skill-tracker is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- install-skill-tracker
- AI & Agent Building
- AI-coding skill
Install Skill Tracker by the numbers
- 10 all-time installs (skills.sh)
- +1 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #11,882 of 16,556 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/vishalsachdev/claude-skills --skill install-skill-trackerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 10 |
|---|---|
| repo stars | ★ 2 |
| Last updated | August 1, 2026 |
| Repository | vishalsachdev/claude-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Install Skill Tracker
Overview
This skill automates the installation of a skill tracking system for Claude Code projects. The system uses Claude Code hooks to automatically log all skill invocations, their duration, and the prompts that triggered them. This data enables pattern analysis to identify frequently repeated workflows that could become new skills.
When to Use This Skill
Use this skill when:
- Setting up skill usage tracking in a new or existing Claude Code project
- Wanting to analyze which skills are used most frequently
- Monitoring API costs and token usage across skill executions
- Identifying time-consuming skills that may need optimization
- Discovering patterns in work that could be automated with new skills
- Tracking productivity gains and cost efficiency from skill automation
- Understanding prompt cache effectiveness and optimization opportunities
Installation Workflow
Step 1: Create Directory Structure
Create the necessary directories for hooks, scripts, and logs:
mkdir -p .claude/hooks .claude/scripts .claude/activity-logsStep 2: Install Hook Scripts
Copy the hook scripts from this skill's scripts/ directory to .claude/hooks/:
- track-prompts.sh - Logs user prompts with timestamps and session IDs
- track-skill-start.sh - Logs when skills begin execution
- track-skill-end.sh - Logs skill completion and calculates duration
Make the hook scripts executable:
chmod +x .claude/hooks/*.shStep 3: Install Analysis Script
Copy the analysis script from this skill's scripts/ directory to .claude/scripts/:
- analyze-skills.py - Processes logs and generates usage reports
Make the analysis script executable:
chmod +x .claude/scripts/analyze-skills.pyStep 4: Configure Hooks
Copy the settings.json template from this skill's assets/ directory to .claude/settings.json. This configuration registers three hooks:
- UserPromptSubmit - Captures all user prompts
- PreToolUse (Skill matcher) - Logs skill start times
- PostToolUse (Skill matcher) - Logs skill completion times
Step 5: Add Documentation
Copy the README.md from this skill's assets/ directory to .claude/README.md. This provides documentation on:
- What data gets tracked
- How the tracking system works
- How to analyze the logs
- Customization options
- Troubleshooting guide
Step 6: Update .gitignore
Add the activity logs directory to .gitignore to prevent tracking log files:
echo ".claude/activity-logs/" >> .gitignore
echo ".claude/settings.local.json" >> .gitignoreStep 7: Verify Installation
Confirm all files are in place:
ls -la .claude/hooks/
ls -la .claude/scripts/
cat .claude/settings.jsonUsing the Tracking System
Automatic Logging
After installation, the tracking system operates automatically: 1. Use skills normally through Claude Code 2. Each skill invocation is logged with timestamp, duration, token usage, and triggering prompt 3. Logs accumulate in .claude/activity-logs/ as JSONL files
What Gets Tracked (v1.2):
- Skill name and invocation time
- Execution duration (in seconds)
- Token usage metrics:
- Input tokens (new content)
- Output tokens (generated response)
- Cache read tokens (from prompt cache)
- Cache creation tokens (creating cache entries)
- Total tokens (sum of all above)
- User prompt that triggered the skill
- Session ID for correlation
Analyzing Usage Data
Run the analysis scripts to generate insights:
Pattern and Performance Analysis:
.claude/scripts/analyze-skills.pyToken Usage and Cost Analysis (v1.2):
.claude/scripts/show-skill-tokens.shThe analysis reports include:
- Skill frequency - Most commonly used skills
- Performance metrics - Average and total duration per skill
- Token usage metrics - Input/output/cache tokens per skill (NEW)
- Cost estimation - Calculate API costs based on token usage (NEW)
- Cache efficiency - Identify cache hit rates and optimization opportunities (NEW)
- Prompt patterns - Common prompts that trigger skills
- Usage history - Recent skill invocations with details
- Insights - Suggestions for optimization and new skill opportunities
Example Analysis Output
# Skill Usage Analysis Report
**Total skill invocations:** 15
## Most Used Skills
- **microsim-p5**: 7x
- **learning-graph-generator**: 5x
- **glossary-generator**: 3x
## Skill Performance (Average Duration)
- **learning-graph-generator**
- Average: 2m 34s
- Total time: 12m 50s
- Invocations: 5x
## Insights & Suggestions
### Frequently Used Skills
- **microsim-p5** (7x): Could benefit from optimization or templates
### Total Time Automated
Skills have automated **45m 23s** of workLog Data Format
The system creates two JSONL log files:
prompts.jsonl
Logs user prompts with session correlation:
{"timestamp": "2025-11-22 14:23:45", "epoch": "1732299825", "session": "abc123", "prompt": "create a learning graph"}skill-usage.jsonl
Logs skill start/end events with duration and token usage:
{"timestamp": "2025-11-22 14:23:46", "epoch": "1732299826", "session": "abc123", "skill": "learning-graph-generator", "event": "start"}
{"timestamp": "2025-11-22 14:26:20", "epoch": "1732299980", "session": "abc123", "skill": "learning-graph-generator", "event": "end", "duration_seconds": "154", "input_tokens": 12000, "output_tokens": 8500, "total_tokens": 84200, "cache_read_tokens": 62400, "cache_creation_tokens": 1300}Customization Options
Global vs Project-Specific Tracking
Current setup: Project-specific tracking (logs in .claude/activity-logs/)
For global tracking across all projects: 1. Move settings.json to ~/.claude/settings.json 2. Update LOG_DIR in hook scripts to ~/.claude/activity-logs 3. Analysis script will aggregate data from all projects
Tracking Additional Metrics
Extend the hook scripts to capture:
- All tool usage (not just skills)
- Error rates and failures
- Custom metadata fields
- Project-specific context
Hooks receive full JSON context via stdin with tool names, parameters, and outputs.
Privacy & Security
All tracking data is stored locally:
- No data transmission to external services
- Logs remain in
.claude/activity-logs/ - Automatically excluded from git via
.gitignore
To delete all tracking data:
rm -rf .claude/activity-logsTroubleshooting
JSON Parsing Errors
IMPORTANT FIX (v1.1): The hook scripts now use jq -nc instead of jq -n to generate compact JSON output. This is critical for proper JSONL format.
If you encounter errors like:
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotesYour existing log files may have pretty-printed JSON. Fix with:
jq -c '.' .claude/activity-logs/prompts.jsonl > temp && mv temp .claude/activity-logs/prompts.jsonl
jq -c '.' .claude/activity-logs/skill-usage.jsonl > temp && mv temp .claude/activity-logs/skill-usage.jsonlHooks Not Executing
Verify hook configuration:
cat .claude/settings.jsonCheck script permissions:
ls -l .claude/hooks/*.shNo Log Files Created
Ensure directories exist:
mkdir -p .claude/activity-logsUse a skill to trigger logging, then check:
ls -la .claude/activity-logs/Analysis Shows No Data
Logs are created only after skill usage. Run any skill first, then execute the analysis script.
Detailed Troubleshooting
For comprehensive troubleshooting, see the README.md in this skill directory, which includes:
- JSONL format requirements and the
-cflag fix - Common issues and solutions
- Hook debugging techniques
- Custom analysis queries
Resources
This skill includes:
scripts/
- track-prompts.sh - Bash hook to log user prompts
- track-skill-start.sh - Bash hook to log skill start times
- track-skill-end.sh - Bash hook to log skill completion, duration, and tokens (v1.2)
- analyze-skills.py - Python script to analyze logs and generate reports
- show-skill-tokens.sh - Bash script to display token usage and cost metrics (v1.2)
assets/
- settings.json - Hook configuration template for
.claude/settings.json - README.md - Complete documentation for the tracking system
Claude Code Skill Tracking System
This directory contains hooks and scripts to automatically track skill usage in Claude Code.
What Gets Tracked
The tracking system logs:
- User prompts that trigger skills
- Skill names being invoked
- Start and end times for each skill
- Duration of skill execution
- Session IDs to correlate prompts with skills
Files
.claude/
├── settings.json # Hook configuration
├── hooks/
│ ├── track-prompts.sh # Logs user prompts
│ ├── track-skill-start.sh # Logs skill start time
│ └── track-skill-end.sh # Logs skill completion and duration
├── scripts/
│ └── analyze-skills.py # Analyzes logs and generates reports
└── activity-logs/ # Created automatically
├── prompts.jsonl # User prompt log (JSONL)
├── skill-usage.jsonl # Skill timing log (JSONL)
└── skill-start-*.tmp # Temporary files for duration trackingHow It Works
1. When you submit a prompt → track-prompts.sh logs it with session ID 2. When a skill starts → track-skill-start.sh logs start time 3. When a skill completes → track-skill-end.sh logs end time and calculates duration 4. All data is correlated by session ID to match prompts with skills
Usage
Normal Usage (Automatic)
The hooks run automatically whenever you use skills in Claude Code. Just work normally and data will accumulate in .claude/activity-logs/.
Analyzing Your Data
Run the analysis script to see insights:
.claude/scripts/analyze-skills.pyThis generates a report showing:
- Most frequently used skills
- Average and total duration for each skill
- Common prompts that trigger skills
- Recent skill usage history
- Efficiency insights and suggestions
Example Output
# Skill Usage Analysis Report
**Total skill invocations:** 15
## Most Used Skills
- **learning-graph-generator**: 5x
- **glossary-generator**: 3x
- **microsim-p5**: 7x
## Skill Performance (Average Duration)
- **learning-graph-generator**
- Average: 2m 34s
- Total time: 12m 50s
- Invocations: 5x
## Insights & Suggestions
### Frequently Used Skills
- **microsim-p5** (7x): Could benefit from optimization or templates
### Total Time Automated
Skills have automated **45m 23s** of workLog Format
prompts.jsonl
{"timestamp": "2025-11-22 14:23:45", "epoch": "1732299825", "session": "abc123", "prompt": "create a learning graph"}skill-usage.jsonl
{"timestamp": "2025-11-22 14:23:46", "epoch": "1732299826", "session": "abc123", "skill": "learning-graph-generator", "event": "start"}
{"timestamp": "2025-11-22 14:26:20", "epoch": "1732299980", "session": "abc123", "skill": "learning-graph-generator", "event": "end", "duration_seconds": "154"}Customization
Change Log Location
Edit the LOG_DIR variable in hook scripts to change where logs are saved:
LOG_DIR="/path/to/custom/logs"Add Additional Tracking
You can extend the hooks to track:
- Tool usage (not just skills)
- Error rates
- Custom metadata
- Project-specific information
Just modify the hook scripts to capture additional fields from the JSON input.
Global vs Project Tracking
Current setup: Project-specific (logs in .claude/activity-logs/)
For global tracking across all projects: 1. Move settings.json to ~/.claude/settings.json 2. Update hook scripts to use ~/.claude/activity-logs for LOG_DIR 3. Analysis script will combine data from all projects
Privacy & Data
All logs are stored locally in .claude/activity-logs/. No data is sent externally.
To delete logs:
rm -rf .claude/activity-logsTo exclude logs from git:
echo ".claude/activity-logs/" >> .gitignoreTroubleshooting
Hooks not running?
Check hook configuration:
cat .claude/settings.jsonVerify scripts are executable:
ls -l .claude/hooks/*.shNo log files created?
Run a skill and check for errors:
ls -la .claude/activity-logs/Check if directory was created:
mkdir -p .claude/activity-logsAnalysis script shows no data?
Ensure you've run at least one skill since installing the hooks. The logs are only created when skills are actually used.
Next Steps
1. Use skills normally - The tracking happens automatically 2. Review weekly - Run analyze-skills.py to see patterns 3. Identify opportunities - Find repetitive tasks that could become new skills 4. Optimize workflows - Use insights to improve your skill usage
For more information about hooks, see the Claude Code hooks documentation.
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": ".claude/hooks/track-prompts.sh",
"description": "Log user prompts to correlate with skill usage"
}
]
}
],
"PreToolUse": [
{
"matcher": "Skill",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/track-skill-start.sh",
"description": "Log skill invocation start time and parameters"
}
]
}
],
"PostToolUse": [
{
"matcher": "Skill",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/track-skill-end.sh",
"description": "Log skill completion time and calculate duration"
}
]
}
]
}
}
Claude Code Skill Tracker
A complete activity tracking system for Claude Code that automatically logs skill usage, execution duration, and user prompts to help identify patterns and opportunities for automation.
Table of Contents
- Overview
- Architecture
- How It Works
- Installation
- Data Format
- Analysis & Reporting
- Common Issues & Troubleshooting
- Privacy & Security
- Customization
Overview
The Skill Tracker system uses Claude Code's hooks mechanism to automatically collect telemetry data about skill usage without requiring any manual intervention. This data enables:
- Pattern Discovery - Identify frequently repeated workflows that could become new skills
- Performance Analysis - Track which skills take the most time and may need optimization
- Productivity Metrics - Quantify time saved through skill automation
- Usage Insights - Understand which skills provide the most value
Key Features
- Zero-overhead tracking - Uses lightweight hooks that don't impact performance
- Automatic correlation - Links prompts to skill invocations via session IDs
- Duration measurement - Calculates precise execution time for each skill
- Token usage tracking - Captures input, output, and cache token metrics for cost analysis
- Rich analytics - Generates comprehensive reports with insights and suggestions
- Privacy-first - All data stored locally, never transmitted externally
- JSONL format - Industry-standard format for easy parsing and analysis
Architecture
The tracking system consists of three components:
┌─────────────────┐
│ Claude Code │
│ │
│ User Prompts │
└────────┬────────┘
│
├──────────────────────────┐
↓ ↓
┌────────────────┐ ┌────────────────┐
│ UserPromptSubmit│ │ Skill Tool │
│ Hook │ │ Invocation │
└────────┬────────┘ └───────┬────────┘
│ │
↓ ├──────────┐
┌────────────────┐ ↓ ↓
│ track-prompts │ ┌────────────┐ ┌────────────┐
│ .sh │ │PreToolUse │ │PostToolUse │
└────────┬────────┘ │ Hook │ │ Hook │
│ └─────┬──────┘ └──────┬─────┘
│ │ │
↓ ↓ ↓
prompts.jsonl track-skill- track-skill-
start.sh end.sh
│ │
↓ ↓
skill-usage.jsonl
┌──────────────────────┴──────────────────────┐
↓ ↓
prompts.jsonl skill-usage.jsonl
│ │
└──────────────────┬───────────────────────────┘
↓
analyze-skills.py
│
↓
Analysis ReportComponent Breakdown
1. Hook Scripts (.claude/hooks/)
track-prompts.sh- Captures user prompts via UserPromptSubmit hooktrack-skill-start.sh- Logs skill start time via PreToolUse hooktrack-skill-end.sh- Logs skill completion and calculates duration via PostToolUse hook
2. Log Files (.claude/activity-logs/)
prompts.jsonl- One JSON object per line, each containing a user prompt with timestampskill-usage.jsonl- One JSON object per line, each containing a skill event (start/end)
3. Analysis Script (.claude/scripts/)
analyze-skills.py- Python script that processes logs and generates reports
How It Works
Data Flow
1. Prompt Capture
User types prompt → UserPromptSubmit hook fires → track-prompts.sh logs to prompts.jsonl2. Skill Start Tracking
Skill invoked → PreToolUse hook fires → track-skill-start.sh:
- Logs start event to skill-usage.jsonl
- Creates temporary file with start timestamp3. Skill End Tracking
Skill completes → PostToolUse hook fires → track-skill-end.sh:
- Reads start timestamp from temporary file
- Calculates duration (end_time - start_time)
- Logs end event with duration to skill-usage.jsonl
- Deletes temporary file4. Session Correlation
All logs include session_id → analyze-skills.py joins prompts with skillsHook Configuration
Hooks are configured in .claude/settings.json:
{
"hooks": {
"UserPromptSubmit": [
{
"command": "bash .claude/hooks/track-prompts.sh"
}
],
"PreToolUse": [
{
"command": "bash .claude/hooks/track-skill-start.sh",
"matcher": {
"tool_name": "Skill"
}
}
],
"PostToolUse": [
{
"command": "bash .claude/hooks/track-skill-end.sh",
"matcher": {
"tool_name": "Skill"
}
}
]
}
}The matcher ensures we only track Skill tool usage, not other tools like Bash, Read, Edit, etc.
Installation
Use the install-skill-tracker skill to automate setup:
# In Claude Code
/skill install-skill-trackerOr install manually:
# Create directories
mkdir -p .claude/hooks .claude/scripts .claude/activity-logs
# Copy hook scripts
cp skills/install-skill-tracker/scripts/track-*.sh .claude/hooks/
chmod +x .claude/hooks/*.sh
# Copy analysis script
cp skills/install-skill-tracker/scripts/analyze-skills.py .claude/scripts/
chmod +x .claude/scripts/analyze-skills.py
# Copy configuration
cp skills/install-skill-tracker/assets/settings.json .claude/settings.json
# Add to .gitignore
echo ".claude/activity-logs/" >> .gitignoreData Format
JSONL (JSON Lines) Format
CRITICAL: All log files use JSONL format, where each line is a complete, self-contained JSON object.
Correct JSONL:
{"timestamp":"2025-11-22 07:04:33","session":"abc123","prompt":"run skill"}
{"timestamp":"2025-11-22 07:05:01","session":"abc123","prompt":"analyze logs"}Incorrect (Pretty-Printed JSON):
{
"timestamp": "2025-11-22 07:04:33",
"session": "abc123",
"prompt": "run skill"
}Why JSONL?
JSONL format enables:
- Streaming processing - Parse one line at a time without loading entire file
- Append-only writes - Add new events without rewriting the file
- Line-oriented tools - Use
head,tail,grepon JSON data - Simple parsing - Read file line-by-line, parse each as JSON
The jq -nc Flag
The hook scripts use jq -nc to generate compact JSON output:
jq -nc \
--arg ts "$TIMESTAMP" \
--arg p "$PROMPT" \
'{timestamp: $ts, prompt: $p}' >> prompts.jsonlFlags:
-n(null input) - Don't read stdin, use only --arg values-c(compact output) - CRITICAL - Output single-line JSON instead of pretty-printed
Without `-c` flag, jq outputs pretty-printed JSON which breaks JSONL parsing!
prompts.jsonl Schema
{
"timestamp": "2025-11-22 07:04:33", // Human-readable timestamp
"epoch": "1763816673", // Unix epoch for sorting/calculations
"session": "9ff87af7-...", // Session ID for correlation
"prompt": "run the skill" // User's prompt text
}skill-usage.jsonl Schema
Start event:
{
"timestamp": "2025-11-22 07:04:42",
"epoch": "1763816682",
"session": "9ff87af7-...",
"skill": "book-metrics-generator",
"event": "start"
}End event:
{
"timestamp": "2025-11-22 07:04:51",
"epoch": "1763816691",
"session": "9ff87af7-...",
"skill": "book-metrics-generator",
"event": "end",
"duration_seconds": "9",
"input_tokens": 8,
"output_tokens": 244,
"total_tokens": 65971,
"cache_read_tokens": 65327,
"cache_creation_tokens": 392
}Token Fields (added in v1.2):
input_tokens- Direct API input tokensoutput_tokens- Generated response tokenstotal_tokens- Sum of all token types (input + output + cache)cache_read_tokens- Tokens read from prompt cachecache_creation_tokens- Tokens used to create cache entries
Analysis & Reporting
Running the Analysis Script
# Analyze current project logs
python .claude/scripts/analyze-skills.py
# Analyze logs from a different directory
python .claude/scripts/analyze-skills.py /path/to/logsToken Usage Analysis (NEW in v1.2)
View token usage for all skill executions:
# Display recent skill token usage
bash .claude/scripts/show-skill-tokens.sh
# Or make it executable and run directly
chmod +x .claude/scripts/show-skill-tokens.sh
.claude/scripts/show-skill-tokens.shSample Output:
Skill Usage with Token Tracking
================================
2025-11-22 07:36:42 book-metrics-generator
Duration: 0s
Tokens: input=8, output=244, total=65971
2025-11-22 07:40:15 learning-graph-generator
Duration: 134s
Tokens: input=12000, output=8500, total=84200
Summary Statistics
==================
Total skill executions: 5
Total tokens used: 328,456
Input: 60,024
Output: 42,150
Average tokens per skill: 65,691Token Cost Estimation:
Using this data, you can estimate API costs:
- Sonnet 4.5: $3 per million input tokens, $15 per million output tokens
- Example: 60K input + 42K output = $0.18 + $0.63 = $0.81 total
Understanding Cache Tokens:
Cache tokens significantly reduce costs:
cache_read_tokensare charged at 10% of normal input rate ($0.30/M vs $3/M)cache_creation_tokensare charged at normal input rate- High cache read counts indicate effective prompt caching
Sample Report Output
# Skill Usage Analysis Report
**Log directory:** `$HOME/project/.claude/activity-logs`
**Total skill invocations:** 15
**Analysis date:** 2025-11-22 14:30:00
## Most Used Skills
- **microsim-p5**: 7x
- **learning-graph-generator**: 5x
- **glossary-generator**: 3x
## Skill Performance (Average Duration)
- **learning-graph-generator**
- Average: 2m 34s
- Total time: 12m 50s
- Invocations: 5x
- **microsim-p5**
- Average: 1m 12s
- Total time: 8m 24s
- Invocations: 7x
## Common Prompts Leading to Skill Usage
3x: "create a new microsim for..."
2x: "generate the learning graph..."
2x: "update the glossary with..."
## Recent Skill Usage (Last 20)
| Timestamp | Skill | Duration | Prompt (truncated) |
|-----------|-------|----------|---------------------|
| 2025-11-22 14:25:33 | microsim-p5 | 1m 15s | create a bubble chart microsim for priority matrix... |
| 2025-11-22 14:12:41 | glossary-generator | 3m 42s | generate glossary from learning graph... |
## Insights & Suggestions
### Frequently Used Skills
- **microsim-p5** (7x): Could benefit from optimization or templates
### Slowest Skills
- **learning-graph-generator**: 12m 50s total (2m 34s avg)
### Total Time Automated
Skills have automated **45m 23s** of workInterpreting Results
High Frequency Skills
- Skills used 3+ times indicate valuable automation
- Consider creating variations or templates for common patterns
High Duration Skills
- Skills taking >2 minutes on average may benefit from optimization
- Consider caching, incremental updates, or parallelization
Common Prompts
- Repeated similar prompts suggest need for new specialized skills
- Look for patterns like "create X", "update Y", "analyze Z"
Common Issues & Troubleshooting
Issue: JSON Parsing Error
Symptom:
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotesCause: Hook scripts are using jq -n instead of jq -nc, causing pretty-printed JSON output that violates JSONL format.
Solution: Update all hook scripts to use jq -nc:
# Fix existing hooks
sed -i '' 's/jq -n \\/jq -nc \\/' .claude/hooks/track-*.sh
# Fix existing log files
jq -c '.' .claude/activity-logs/prompts.jsonl > temp && mv temp .claude/activity-logs/prompts.jsonl
jq -c '.' .claude/activity-logs/skill-usage.jsonl > temp && mv temp .claude/activity-logs/skill-usage.jsonlIssue: No Data Logged
Symptom: Running analysis shows "No skill usage data found yet."
Diagnosis:
# Check if directories exist
ls -la .claude/activity-logs/
# Check hook configuration
cat .claude/settings.json
# Check hook permissions
ls -l .claude/hooks/*.sh
# Verify hooks are executable
file .claude/hooks/*.shSolution:
# Ensure directories exist
mkdir -p .claude/activity-logs
# Make hooks executable
chmod +x .claude/hooks/*.sh
# Verify settings.json exists
test -f .claude/settings.json && echo "Settings found" || echo "Settings missing"Issue: Duration Shows "unknown"
Symptom: Analysis report shows Duration: unknown for skills
Cause:
- Temporary start time file not created
- Start time file deleted before end hook runs
- Permissions issue preventing file creation
Diagnosis:
# Check for orphaned temp files
ls .claude/activity-logs/*.tmp
# Check permissions
ls -la .claude/activity-logs/Solution:
- Ensure
.claude/activity-logs/is writable - Check that skill names don't contain special characters that break filenames
- Verify both PreToolUse and PostToolUse hooks are configured
Issue: Hooks Not Executing
Symptom: Log files not created when using skills
Diagnosis:
# Test hook manually
echo '{"prompt":"test","session_id":"test123"}' | bash .claude/hooks/track-prompts.sh
# Check for errors
echo '{"prompt":"test","session_id":"test123"}' | bash -x .claude/hooks/track-prompts.shSolution:
- Verify
jqis installed:which jq - Check hook script syntax:
bash -n .claude/hooks/track-prompts.sh - Ensure hooks are in
.claude/settings.json - Restart Claude Code to reload settings
Privacy & Security
Local Storage Only
All tracking data is stored locally in .claude/activity-logs/:
- No data transmission to external services
- No cloud sync or remote logging
- Complete control over your data
Excluding from Git
The installation process adds .claude/activity-logs/ to .gitignore to prevent:
- Committing sensitive prompt data
- Exposing project patterns
- Repository bloat from log files
Deleting Logs
Remove all tracking data:
# Delete all logs
rm -rf .claude/activity-logs
# Delete specific log files
rm .claude/activity-logs/prompts.jsonl
rm .claude/activity-logs/skill-usage.jsonlSelective Logging
Disable specific hooks by commenting them out in .claude/settings.json:
{
"hooks": {
// Disable prompt tracking
// "UserPromptSubmit": [...],
// Keep skill tracking enabled
"PreToolUse": [...],
"PostToolUse": [...]
}
}Customization
Global vs Project-Specific Tracking
Current Setup: Project-specific (logs in .claude/activity-logs/)
For Global Tracking:
1. Move settings to user-level config:
mv .claude/settings.json ~/.claude/settings.json2. Update LOG_DIR in all hook scripts:
# Change from:
LOG_DIR="${CLAUDE_PROJECT_DIR:-.}/.claude/activity-logs"
# To:
LOG_DIR="$HOME/.claude/activity-logs"3. Analysis script automatically finds global logs:
python ~/.claude/scripts/analyze-skills.pyTracking Additional Tools
To track all tool usage (not just skills), remove the matcher:
{
"hooks": {
"PreToolUse": [
{
"command": "bash .claude/hooks/track-tool-start.sh"
// No matcher - tracks ALL tools
}
]
}
}Update hook scripts to use $TOOL_NAME instead of $SKILL_NAME.
Adding Custom Metadata
Extend hook scripts to capture additional context:
# In track-skill-end.sh, add project name
PROJECT_NAME=$(basename "$PWD")
jq -nc \
--arg ts "$TIMESTAMP" \
--arg skill "$SKILL_NAME" \
--arg project "$PROJECT_NAME" \
'{timestamp: $ts, skill: $skill, project: $project}' >> "$LOG_FILE"Custom Analysis Queries
Query logs directly with jq:
# Count skills by name
jq -s 'group_by(.skill) | map({skill: .[0].skill, count: length})' \
.claude/activity-logs/skill-usage.jsonl
# Find long-running skills (>60 seconds)
jq 'select(.event == "end" and (.duration_seconds | tonumber) > 60)' \
.claude/activity-logs/skill-usage.jsonl
# Get unique prompts
jq -r '.prompt' .claude/activity-logs/prompts.jsonl | sort -uVersion History
v1.2 (2025-11-22)
- NEW: Added token usage tracking (input, output, cache metrics)
- NEW: Added
show-skill-tokens.shscript for token analysis - Extracts token data from Claude Code transcript files
- Tracks prompt cache efficiency with cache_read and cache_creation tokens
- Enables cost estimation and optimization insights
v1.1 (2025-11-22)
- Fixed JSONL format bug by adding
-cflag to alljqcommands - Added comprehensive troubleshooting section
- Documented data format requirements
v1.0 (2025-11-20)
- Initial release
- Basic tracking and analysis functionality
Resources
Files in This Skill
install-skill-tracker/
├── README.md # This file
├── SKILL.md # Skill definition and installation workflow
├── scripts/
│ ├── track-prompts.sh # Hook: Capture user prompts
│ ├── track-skill-start.sh # Hook: Log skill start times
│ ├── track-skill-end.sh # Hook: Log skill completion, duration, and tokens (v1.2)
│ ├── analyze-skills.py # Analysis script for patterns and insights
│ └── show-skill-tokens.sh # NEW v1.2: Display token usage and cost metrics
└── assets/
├── settings.json # Template for .claude/settings.json
└── README.md # Documentation to copy to .claude/README.mdExternal References
Support
For issues or questions: 1. Check the Troubleshooting section 2. Review the Claude Code documentation 3. Open an issue in the repository
#!/usr/bin/env python3
"""Analyze skill usage logs to identify patterns and performance metrics."""
import json
from collections import Counter, defaultdict
from datetime import datetime
from pathlib import Path
import sys
def load_jsonl(filepath):
"""Load JSONL file into list of dicts."""
if not filepath.exists():
return []
with open(filepath) as f:
return [json.loads(line) for line in f if line.strip()]
def format_duration(seconds):
"""Format duration in human-readable format."""
if seconds == "unknown":
return "unknown"
seconds = int(seconds)
if seconds < 60:
return f"{seconds}s"
elif seconds < 3600:
minutes = seconds // 60
secs = seconds % 60
return f"{minutes}m {secs}s"
else:
hours = seconds // 3600
minutes = (seconds % 3600) // 60
return f"{hours}h {minutes}m"
def correlate_prompts_with_skills(prompts, skill_events):
"""Match user prompts with skill invocations by session ID."""
# Group skill events by session
skills_by_session = defaultdict(list)
for event in skill_events:
if event['event'] == 'end':
skills_by_session[event['session']].append(event)
# Create prompt lookup by session
prompts_by_session = {}
for prompt in prompts:
# Keep the most recent prompt for each session
prompts_by_session[prompt['session']] = prompt['prompt']
# Correlate
correlated = []
for session, skill_list in skills_by_session.items():
prompt = prompts_by_session.get(session, "Unknown prompt")
for skill_event in skill_list:
correlated.append({
'skill': skill_event['skill'],
'prompt': prompt,
'duration': skill_event.get('duration_seconds', 'unknown'),
'timestamp': skill_event['timestamp'],
'session': session
})
return correlated
def analyze_skill_usage(log_dir):
"""Analyze skill usage patterns and generate report."""
log_dir = Path(log_dir)
# Load logs
prompts = load_jsonl(log_dir / "prompts.jsonl")
skill_events = load_jsonl(log_dir / "skill-usage.jsonl")
if not skill_events:
print("No skill usage data found yet.")
print(f"Logs will be created in: {log_dir}")
print("\nUse skills in Claude Code and they'll be tracked automatically.")
return
# Correlate prompts with skills
correlated = correlate_prompts_with_skills(prompts, skill_events)
print("# Skill Usage Analysis Report\n")
print(f"**Log directory:** `{log_dir}`")
print(f"**Total skill invocations:** {len(correlated)}")
print(f"**Analysis date:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
# Skill frequency analysis
skill_counts = Counter(entry['skill'] for entry in correlated)
print("## Most Used Skills\n")
for skill, count in skill_counts.most_common():
print(f"- **{skill}**: {count}x")
# Duration analysis
print("\n## Skill Performance (Average Duration)\n")
skill_durations = defaultdict(list)
for entry in correlated:
if entry['duration'] != 'unknown':
skill_durations[entry['skill']].append(int(entry['duration']))
skill_avg_durations = []
for skill, durations in skill_durations.items():
avg = sum(durations) / len(durations)
total = sum(durations)
skill_avg_durations.append((skill, avg, total, len(durations)))
# Sort by total time spent
skill_avg_durations.sort(key=lambda x: x[2], reverse=True)
for skill, avg, total, count in skill_avg_durations:
print(f"- **{skill}**")
print(f" - Average: {format_duration(avg)}")
print(f" - Total time: {format_duration(total)}")
print(f" - Invocations: {count}x")
# Common prompts that trigger skills
print("\n## Common Prompts Leading to Skill Usage\n")
prompt_counts = Counter(entry['prompt'][:100] for entry in correlated) # Truncate long prompts
for prompt, count in prompt_counts.most_common(10):
if count > 1:
print(f"{count}x: \"{prompt}...\"")
# Detailed log
print("\n## Recent Skill Usage (Last 20)\n")
print("| Timestamp | Skill | Duration | Prompt (truncated) |")
print("|-----------|-------|----------|---------------------|")
for entry in sorted(correlated, key=lambda x: x['timestamp'], reverse=True)[:20]:
duration = format_duration(entry['duration'])
prompt_short = entry['prompt'][:50].replace('|', '\\|')
print(f"| {entry['timestamp']} | {entry['skill']} | {duration} | {prompt_short}... |")
# Efficiency suggestions
print("\n## Insights & Suggestions\n")
# Find frequently used skills
frequent_skills = [s for s, c in skill_counts.items() if c >= 3]
if frequent_skills:
print("### Frequently Used Skills")
print("These skills are used often - consider:")
for skill in frequent_skills[:5]:
count = skill_counts[skill]
print(f"- **{skill}** ({count}x): Could benefit from optimization or templates")
# Find slow skills
if skill_avg_durations:
print("\n### Slowest Skills")
print("These skills take the most total time:")
for skill, avg, total, count in skill_avg_durations[:3]:
print(f"- **{skill}**: {format_duration(total)} total ({format_duration(avg)} avg)")
# Time savings potential
if skill_avg_durations:
total_time_saved = sum(total for _, _, total, _ in skill_avg_durations)
print(f"\n### Total Time Automated")
print(f"Skills have automated **{format_duration(total_time_saved)}** of work")
print("(Time spent running skills vs. doing tasks manually)")
def main():
"""Main entry point."""
# Default log directory
log_dir = Path(__file__).parent.parent / "activity-logs"
# Allow override from command line
if len(sys.argv) > 1:
log_dir = Path(sys.argv[1])
if not log_dir.exists():
print(f"Log directory not found: {log_dir}")
print("\nHooks will create this directory on first skill usage.")
return
analyze_skill_usage(log_dir)
if __name__ == "__main__":
main()
#!/bin/bash
# Display skill usage with token information
LOG_FILE="${CLAUDE_PROJECT_DIR:-.}/.claude/activity-logs/skill-usage.jsonl"
if [ ! -f "$LOG_FILE" ]; then
echo "No skill usage log found at: $LOG_FILE"
exit 1
fi
echo "Skill Usage with Token Tracking"
echo "================================"
echo ""
# Show recent skill executions with token data
jq -r '
select(.event == "end") |
"\(.timestamp) \(.skill)\n" +
" Duration: \(.duration_seconds)s\n" +
" Tokens: input=\(.input_tokens // "N/A"), output=\(.output_tokens // "N/A"), total=\(.total_tokens // "N/A")\n"
' "$LOG_FILE" | tail -20
echo ""
echo "Summary Statistics"
echo "=================="
# Calculate total tokens across all skills
jq -s '
map(select(.event == "end" and .total_tokens != null)) |
{
total_executions: length,
total_tokens: (map(.total_tokens) | add // 0),
total_input_tokens: (map(.input_tokens) | add // 0),
total_output_tokens: (map(.output_tokens) | add // 0),
avg_tokens_per_skill: ((map(.total_tokens) | add // 0) / (length | if . == 0 then 1 else . end))
} |
"Total skill executions: \(.total_executions)\n" +
"Total tokens used: \(.total_tokens)\n" +
" Input: \(.total_input_tokens)\n" +
" Output: \(.total_output_tokens)\n" +
"Average tokens per skill: \(.avg_tokens_per_skill | floor)"
' "$LOG_FILE"
#!/bin/bash
# Track user prompts to correlate with skill usage
HOOK_INPUT=$(cat)
PROMPT=$(echo "$HOOK_INPUT" | jq -r '.prompt')
SESSION_ID=$(echo "$HOOK_INPUT" | jq -r '.session_id')
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
EPOCH=$(date '+%s')
# Create log directory if it doesn't exist
LOG_DIR="${CLAUDE_PROJECT_DIR:-.}/.claude/activity-logs"
mkdir -p "$LOG_DIR"
# Log prompt with session ID for correlation
LOG_FILE="$LOG_DIR/prompts.jsonl"
jq -nc \
--arg ts "$TIMESTAMP" \
--arg epoch "$EPOCH" \
--arg sid "$SESSION_ID" \
--arg p "$PROMPT" \
'{timestamp: $ts, epoch: $epoch, session: $sid, prompt: $p}' >> "$LOG_FILE"
# Allow the prompt to continue (exit 0 = success)
exit 0
#!/bin/bash
# Track skill completion and calculate duration
HOOK_INPUT=$(cat)
TOOL_NAME=$(echo "$HOOK_INPUT" | jq -r '.tool_name')
SKILL_NAME=$(echo "$HOOK_INPUT" | jq -r '.tool_input.skill')
SESSION_ID=$(echo "$HOOK_INPUT" | jq -r '.session_id')
TRANSCRIPT_PATH=$(echo "$HOOK_INPUT" | jq -r '.transcript_path')
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
EPOCH=$(date '+%s')
# Create log directory if it doesn't exist
LOG_DIR="${CLAUDE_PROJECT_DIR:-.}/.claude/activity-logs"
mkdir -p "$LOG_DIR"
# Calculate duration if start time exists
TEMP_FILE="$LOG_DIR/skill-start-${SESSION_ID}-${SKILL_NAME}.tmp"
DURATION="unknown"
if [ -f "$TEMP_FILE" ]; then
START_EPOCH=$(cat "$TEMP_FILE")
DURATION=$((EPOCH - START_EPOCH))
# Clean up temp file
rm -f "$TEMP_FILE"
fi
# Extract token usage from transcript file (JSONL format)
INPUT_TOKENS="null"
OUTPUT_TOKENS="null"
TOTAL_TOKENS="null"
CACHE_READ_TOKENS="null"
CACHE_CREATION_TOKENS="null"
if [ -f "$TRANSCRIPT_PATH" ]; then
# Get the last line from the JSONL file (most recent message)
# Then extract usage data from .message.usage
LAST_MESSAGE=$(tail -1 "$TRANSCRIPT_PATH" 2>/dev/null)
if [ -n "$LAST_MESSAGE" ]; then
INPUT_TOKENS=$(echo "$LAST_MESSAGE" | jq -r '.message.usage.input_tokens // null' 2>/dev/null)
OUTPUT_TOKENS=$(echo "$LAST_MESSAGE" | jq -r '.message.usage.output_tokens // null' 2>/dev/null)
CACHE_READ_TOKENS=$(echo "$LAST_MESSAGE" | jq -r '.message.usage.cache_read_input_tokens // null' 2>/dev/null)
CACHE_CREATION_TOKENS=$(echo "$LAST_MESSAGE" | jq -r '.message.usage.cache_creation_input_tokens // null' 2>/dev/null)
# Calculate total if both input and output are available
if [ "$INPUT_TOKENS" != "null" ] && [ "$OUTPUT_TOKENS" != "null" ]; then
TOTAL_TOKENS=$((INPUT_TOKENS + OUTPUT_TOKENS))
# Add cache tokens if available for a complete picture
if [ "$CACHE_READ_TOKENS" != "null" ]; then
TOTAL_TOKENS=$((TOTAL_TOKENS + CACHE_READ_TOKENS))
fi
if [ "$CACHE_CREATION_TOKENS" != "null" ]; then
TOTAL_TOKENS=$((TOTAL_TOKENS + CACHE_CREATION_TOKENS))
fi
fi
fi
fi
# Log skill completion with duration and token usage
LOG_FILE="$LOG_DIR/skill-usage.jsonl"
jq -nc \
--arg ts "$TIMESTAMP" \
--arg epoch "$EPOCH" \
--arg sid "$SESSION_ID" \
--arg skill "$SKILL_NAME" \
--arg event "end" \
--arg dur "$DURATION" \
--argjson in_tok "${INPUT_TOKENS:-null}" \
--argjson out_tok "${OUTPUT_TOKENS:-null}" \
--argjson tot_tok "${TOTAL_TOKENS:-null}" \
--argjson cache_read "${CACHE_READ_TOKENS:-null}" \
--argjson cache_create "${CACHE_CREATION_TOKENS:-null}" \
'{timestamp: $ts, epoch: $epoch, session: $sid, skill: $skill, event: $event, duration_seconds: $dur, input_tokens: $in_tok, output_tokens: $out_tok, total_tokens: $tot_tok, cache_read_tokens: $cache_read, cache_creation_tokens: $cache_create}' >> "$LOG_FILE"
# Allow normal completion (exit 0 = success)
exit 0
#!/bin/bash
# Track skill invocation start time
HOOK_INPUT=$(cat)
TOOL_NAME=$(echo "$HOOK_INPUT" | jq -r '.tool_name')
SKILL_NAME=$(echo "$HOOK_INPUT" | jq -r '.tool_input.skill')
SESSION_ID=$(echo "$HOOK_INPUT" | jq -r '.session_id')
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
EPOCH=$(date '+%s')
# Create log directory if it doesn't exist
LOG_DIR="${CLAUDE_PROJECT_DIR:-.}/.claude/activity-logs"
mkdir -p "$LOG_DIR"
# Log skill start with timestamp
LOG_FILE="$LOG_DIR/skill-usage.jsonl"
jq -nc \
--arg ts "$TIMESTAMP" \
--arg epoch "$EPOCH" \
--arg sid "$SESSION_ID" \
--arg skill "$SKILL_NAME" \
--arg event "start" \
'{timestamp: $ts, epoch: $epoch, session: $sid, skill: $skill, event: $event}' >> "$LOG_FILE"
# Create a temporary file to track start time for duration calculation
TEMP_FILE="$LOG_DIR/skill-start-${SESSION_ID}-${SKILL_NAME}.tmp"
echo "$EPOCH" > "$TEMP_FILE"
# Allow the skill to execute (exit 0 = success)
exit 0