Install command
Not provided
Real-time coding velocity monitor tracking lines added/removed per minute with productivity scoring and daily output projection for Claude Code sessions.
Open the source and read safety notes before installing.
Source-backed facts for citing this resource, derived directly from the registry — also available as plain text for AI assistants.
Decision playbook
Signals are present but mixed. Use the checklist below to confirm the source and operational safety for your environment.
0
78
—
No baseline selected
No major trust-signal divergence detected in the current selection.
Confirm ownership and provenance before trusting install instructions.
Source link availableRequired
Open the canonical repository and verify ownership.
Source provenance statusRequired
Marked as source-backed.
Metadata reviewed
Registry metadata indicates a reviewed listing.
Validate risk disclosures before installation or API wiring.
Safety notes presentRequired
Review the listed safety guidance before running commands.
Privacy notes presentRequired
Review data handling notes before connecting accounts or secrets.
Trust level risk gateRequired
Trust level does not block evaluation.
Check package metadata and artifact integrity signals.
Install payload available
Install or copy payload is available for review.
Package verification flag
No package verification flag provided.
Checksum metadata
No checksum provided for downloaded artifact.
Use compare context to validate trade-offs before adoption.
Compare tray has multiple entries
Add at least one more entry to compare trust differences.
Baseline comparison available
No baseline peer selected yet.
Diverging trust signals identified
No major trust-signal divergence found.
Setup at a glance
Copy-ready — paste the snippet to get started.
Install command
Not provided
Config snippet
Provided
Copy snippet
Provided
Prerequisites
6 to clear
Platforms
1 listed
Difficulty
5/100
Adoption plan
Current risk score 16/100. Use staged verification before broader rollout.
Validate source and review signals before any execution.
Confirm source provenanceRequired
Source URL/provenance metadata is present.
Confirm metadata review state
Listing has review metadata.
Verify install payload
Install/config payload exists and can be inspected.
Confirm safety, privacy, and package integrity signals.
Review safety notesRequired
Safety notes are present.
Review privacy notesRequired
Privacy notes are present.
Verify package integrity metadata
No package verification/checksum metadata.
Adopt in controlled steps based on the selected plan.
Run in isolated sandbox firstRequired
Use a constrained sandbox and observe behavior across multiple tasks.
Roll out graduallyRequired
Roll out to a small cohort before wider usage.
Set monitoring and fallback
Define rollback path and monitor errors after adoption.
Evidence readiness
Required evidence gates are covered (5/6 signals complete).
Source repository/provenance is listed.
Required in this preset
Review metadata is present.
Required in this preset
Safety notes are present.
Required in this preset
Privacy notes are present.
Optional in this preset
Package integrity metadata is missing.
Optional in this preset
Install payload is available.
Required in this preset
Required evidence gates are covered for this preset.
Decision timeline
5/6 steps complete with no blocking gaps for this preset.
triage
Source/provenance metadata is available.
triage
Review metadata is available.
verify
Safety notes are available.
verify
Privacy notes are available.
verify
Package integrity metadata is missing.
rollout
Install payload is available.
No required blockers for this timeline preset.
Prerequisite readiness
6 prerequisites to line up before setup.
Safety & privacy surface
1 safety and 1 privacy notes across 1 risk area. Review closely: credentials & tokens.
#!/usr/bin/env bash
# Lines Per Minute Productivity Tracker for Claude Code
# Calculates coding velocity and productivity metrics
# Read JSON from stdin
read -r input
# Extract values
lines_added=$(echo "$input" | jq -r '.cost.total_lines_added // 0')
lines_removed=$(echo "$input" | jq -r '.cost.total_lines_removed // 0')
total_duration_ms=$(echo "$input" | jq -r '.cost.total_duration_ms // 1')
# Calculate duration in minutes (avoid division by zero)
if [ "$total_duration_ms" -gt 0 ]; then
duration_minutes=$(echo "scale=2; $total_duration_ms / 60000" | bc)
else
duration_minutes=0.01 # Prevent division by zero
fi
# Calculate net lines (added - removed)
net_lines=$((lines_added - lines_removed))
# Calculate total changed lines (added + removed)
total_changed=$((lines_added + lines_removed))
# Calculate lines per minute
if (( $(echo "$duration_minutes > 0" | bc -l) )); then
added_per_min=$(echo "scale=1; $lines_added / $duration_minutes" | bc)
removed_per_min=$(echo "scale=1; $lines_removed / $duration_minutes" | bc)
net_per_min=$(echo "scale=1; $net_lines / $duration_minutes" | bc)
total_per_min=$(echo "scale=1; $total_changed / $duration_minutes" | bc)
else
added_per_min=0
removed_per_min=0
net_per_min=0
total_per_min=0
fi
# Productivity scoring based on total changes per minute
if (( $(echo "$total_per_min > 50" | bc -l) )); then
PROD_COLOR="\033[38;5;46m" # Green: High productivity (>50 lines/min)
PROD_ICON="🚀"
PROD_RATING="HIGH"
elif (( $(echo "$total_per_min > 20" | bc -l) )); then
PROD_COLOR="\033[38;5;226m" # Yellow: Medium productivity (20-50 lines/min)
PROD_ICON="📝"
PROD_RATING="MED"
else
PROD_COLOR="\033[38;5;75m" # Blue: Low/steady productivity (<20 lines/min)
PROD_ICON="✏️"
PROD_RATING="LOW"
fi
# Project daily output (assuming 8-hour workday = 480 minutes)
if (( $(echo "$net_per_min > 0" | bc -l) )); then
daily_projection=$(echo "scale=0; $net_per_min * 480" | bc)
else
daily_projection=0
fi
RESET="\033[0m"
# Format output with net lines indicator
if [ $net_lines -lt 0 ]; then
net_display="${net_lines}"
net_label="(refactoring)"
else
net_display="+${net_lines}"
net_label="(growth)"
fi
# Output statusline
echo -e "${PROD_ICON} ${PROD_RATING}: ${PROD_COLOR}${total_per_min} L/min${RESET} | +${added_per_min} -${removed_per_min} | Net: ${net_display} ${net_label} | 📅 ${daily_projection} L/day"{
"statusLine": {
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/statuslines/lines-per-minute-tracker.sh",
"refreshInterval": 1000
}
}{
"statusLine": {
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/statuslines/lines-per-minute-tracker.sh",
"refreshInterval": 1000
}
}
Extended version tracking velocity trends across multiple sessions
#!/usr/bin/env bash
# Enhanced Lines Per Minute Tracker with Session History
input=$(cat)
session_id=$(echo "$input" | jq -r '.session_id // ""')
lines_added=$(echo "$input" | jq -r '.cost.total_lines_added // 0')
lines_removed=$(echo "$input" | jq -r '.cost.total_lines_removed // 0')
total_duration_ms=$(echo "$input" | jq -r '.cost.total_duration_ms // 1')
# Session history directory
HISTORY_DIR="${HOME}/.claude-code-velocity"
mkdir -p "$HISTORY_DIR"
# Current session file
SESSION_FILE="${HISTORY_DIR}/${session_id}.velocity"
# Store session metrics
if [ -n "$session_id" ]; then
echo "${lines_added}|${lines_removed}|${total_duration_ms}" >> "$SESSION_FILE"
fi
# Calculate current session metrics
if [ "$total_duration_ms" -gt 0 ]; then
duration_minutes=$(echo "scale=2; $total_duration_ms / 60000" | bc 2>/dev/null || echo "0.01")
else
duration_minutes=0.01
fi
net_lines=$((lines_added - lines_removed))
total_changed=$((lines_added + lines_removed))
if (( $(echo "$duration_minutes > 0" | bc -l 2>/dev/null || echo "0") )); then
total_per_min=$(echo "scale=1; $total_changed / $duration_minutes" | bc 2>/dev/null || echo "0")
added_per_min=$(echo "scale=1; $lines_added / $duration_minutes" | bc 2>/dev/null || echo "0")
removed_per_min=$(echo "scale=1; $lines_removed / $duration_minutes" | bc 2>/dev/null || echo "0")
net_per_min=$(echo "scale=1; $net_lines / $duration_minutes" | bc 2>/dev/null || echo "0")
else
total_per_min=0
added_per_min=0
removed_per_min=0
net_per_min=0
fi
# Calculate average velocity from history
if [ -f "$SESSION_FILE" ] && [ -n "$session_id" ]; then
avg_total_per_min=$(awk -F'|' '{added+=$1; removed+=$2; dur+=$3} END {if(dur>0) print (added+removed)/(dur/60000); else print 0}' "$SESSION_FILE" 2>/dev/null || echo "0")
else
avg_total_per_min=$total_per_min
fi
if (( $(echo "$total_per_min > 50" | bc -l 2>/dev/null || echo "0") )); then
PROD_COLOR="\033[38;5;46m"
PROD_ICON="🚀"
PROD_RATING="HIGH"
elif (( $(echo "$total_per_min > 20" | bc -l 2>/dev/null || echo "0") )); then
PROD_COLOR="\033[38;5;226m"
PROD_ICON="📝"
PROD_RATING="MED"
else
PROD_COLOR="\033[38;5;75m"
PROD_ICON="✏️"
PROD_RATING="LOW"
fi
if (( $(echo "$net_per_min > 0" | bc -l 2>/dev/null || echo "0") )); then
daily_projection=$(echo "scale=0; $net_per_min * 480" | bc 2>/dev/null || echo "0")
else
daily_projection=0
fi
RESET="\033[0m"
if [ $net_lines -lt 0 ]; then
net_display="${net_lines}"
net_label="(refactoring)"
else
net_display="+${net_lines}"
net_label="(growth)"
fi
echo -e "${PROD_ICON} ${PROD_RATING}: ${PROD_COLOR}${total_per_min} L/min${RESET} (avg: ${avg_total_per_min}) | +${added_per_min} -${removed_per_min} | Net: ${net_display} ${net_label} | 📅 ${daily_projection} L/day"
Configurable productivity thresholds for different coding styles
#!/usr/bin/env bash
# Lines Per Minute Tracker with Custom Productivity Thresholds
# Configurable thresholds (default: HIGH >50, MED 20-50, LOW <20)
HIGH_THRESHOLD=${LPM_HIGH_THRESHOLD:-50}
MED_THRESHOLD=${LPM_MED_THRESHOLD:-20}
input=$(cat)
lines_added=$(echo "$input" | jq -r '.cost.total_lines_added // 0')
lines_removed=$(echo "$input" | jq -r '.cost.total_lines_removed // 0')
total_duration_ms=$(echo "$input" | jq -r '.cost.total_duration_ms // 1')
if [ "$total_duration_ms" -gt 0 ]; then
duration_minutes=$(echo "scale=2; $total_duration_ms / 60000" | bc 2>/dev/null || echo "0.01")
else
duration_minutes=0.01
fi
net_lines=$((lines_added - lines_removed))
total_changed=$((lines_added + lines_removed))
if (( $(echo "$duration_minutes > 0" | bc -l 2>/dev/null || echo "0") )); then
total_per_min=$(echo "scale=1; $total_changed / $duration_minutes" | bc 2>/dev/null || echo "0")
added_per_min=$(echo "scale=1; $lines_added / $duration_minutes" | bc 2>/dev/null || echo "0")
removed_per_min=$(echo "scale=1; $lines_removed / $duration_minutes" | bc 2>/dev/null || echo "0")
net_per_min=$(echo "scale=1; $net_lines / $duration_minutes" | bc 2>/dev/null || echo "0")
else
total_per_min=0
added_per_min=0
removed_per_min=0
net_per_min=0
fi
# Custom productivity scoring
if (( $(echo "$total_per_min > $HIGH_THRESHOLD" | bc -l 2>/dev/null || echo "0") )); then
PROD_COLOR="\033[38;5;46m"
PROD_ICON="🚀"
PROD_RATING="HIGH"
elif (( $(echo "$total_per_min > $MED_THRESHOLD" | bc -l 2>/dev/null || echo "0") )); then
PROD_COLOR="\033[38;5;226m"
PROD_ICON="📝"
PROD_RATING="MED"
else
PROD_COLOR="\033[38;5;75m"
PROD_ICON="✏️"
PROD_RATING="LOW"
fi
if (( $(echo "$net_per_min > 0" | bc -l 2>/dev/null || echo "0") )); then
daily_projection=$(echo "scale=0; $net_per_min * 480" | bc 2>/dev/null || echo "0")
else
daily_projection=0
fi
RESET="\033[0m"
if [ $net_lines -lt 0 ]; then
net_display="${net_lines}"
net_label="(refactoring)"
else
net_display="+${net_lines}"
net_label="(growth)"
fi
echo -e "${PROD_ICON} ${PROD_RATING}: ${PROD_COLOR}${total_per_min} L/min${RESET} | +${added_per_min} -${removed_per_min} | Net: ${net_display} ${net_label} | 📅 ${daily_projection} L/day"
Complete setup script with bc verification and Unicode character testing
#!/bin/bash
# Installation script for Lines Per Minute Tracker
# Check for bc (required for floating point calculations)
if ! command -v bc &> /dev/null; then
echo "Installing bc for floating point calculations..."
if [[ "$OSTYPE" == "darwin"* ]]; then
brew install bc
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
sudo apt-get install -y bc || sudo yum install -y bc
else
echo "Please install bc manually: https://www.gnu.org/software/bc/"
fi
fi
# Check for jq (required for JSON parsing)
if ! command -v jq &> /dev/null; then
echo "Installing jq for JSON parsing..."
if [[ "$OSTYPE" == "darwin"* ]]; then
brew install jq
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
sudo apt-get install -y jq || sudo yum install -y jq
else
echo "Please install jq manually: https://stedolan.github.io/jq/"
fi
fi
# Test bc installation
if echo '10.5 / 2' | bc &> /dev/null; then
echo "bc calculator working correctly"
else
echo "Warning: bc may not be working correctly"
fi
# Test Unicode characters
if echo -e '🚀 📝 ✏️ 📅' &> /dev/null; then
echo "Unicode characters supported"
else
echo "Warning: Unicode characters may not be supported in your terminal"
fi
mkdir -p .claude/statuslines
cat > .claude/statuslines/lines-per-minute-tracker.sh << 'SCRIPT_EOF'
#!/usr/bin/env bash
# Lines Per Minute Productivity Tracker for Claude Code
# Calculates coding velocity and productivity metrics
read -r input
lines_added=$(echo "$input" | jq -r '.cost.total_lines_added // 0')
lines_removed=$(echo "$input" | jq -r '.cost.total_lines_removed // 0')
total_duration_ms=$(echo "$input" | jq -r '.cost.total_duration_ms // 1')
if [ "$total_duration_ms" -gt 0 ]; then
duration_minutes=$(echo "scale=2; $total_duration_ms / 60000" | bc 2>/dev/null || echo "0.01")
else
duration_minutes=0.01
fi
net_lines=$((lines_added - lines_removed))
total_changed=$((lines_added + lines_removed))
if (( $(echo "$duration_minutes > 0" | bc -l 2>/dev/null || echo "0") )); then
added_per_min=$(echo "scale=1; $lines_added / $duration_minutes" | bc 2>/dev/null || echo "0")
removed_per_min=$(echo "scale=1; $lines_removed / $duration_minutes" | bc 2>/dev/null || echo "0")
net_per_min=$(echo "scale=1; $net_lines / $duration_minutes" | bc 2>/dev/null || echo "0")
total_per_min=$(echo "scale=1; $total_changed / $duration_minutes" | bc 2>/dev/null || echo "0")
else
added_per_min=0
removed_per_min=0
net_per_min=0
total_per_min=0
fi
if (( $(echo "$total_per_min > 50" | bc -l 2>/dev/null || echo "0") )); then
PROD_COLOR="\033[38;5;46m"
PROD_ICON="🚀"
PROD_RATING="HIGH"
elif (( $(echo "$total_per_min > 20" | bc -l 2>/dev/null || echo "0") )); then
PROD_COLOR="\033[38;5;226m"
PROD_ICON="📝"
PROD_RATING="MED"
else
PROD_COLOR="\033[38;5;75m"
PROD_ICON="✏️"
PROD_RATING="LOW"
fi
if (( $(echo "$net_per_min > 0" | bc -l 2>/dev/null || echo "0") )); then
daily_projection=$(echo "scale=0; $net_per_min * 480" | bc 2>/dev/null || echo "0")
else
daily_projection=0
fi
RESET="\033[0m"
if [ $net_lines -lt 0 ]; then
net_display="${net_lines}"
net_label="(refactoring)"
else
net_display="+${net_lines}"
net_label="(growth)"
fi
echo -e "${PROD_ICON} ${PROD_RATING}: ${PROD_COLOR}${total_per_min} L/min${RESET} | +${added_per_min} -${removed_per_min} | Net: ${net_display} ${net_label} | 📅 ${daily_projection} L/day"
SCRIPT_EOF
chmod +x .claude/statuslines/lines-per-minute-tracker.sh
# Add to settings.json
if [ ! -f .claude/settings.json ]; then
echo '{"statusLine":{"type":"command","command":"$CLAUDE_PROJECT_DIR/.claude/statuslines/lines-per-minute-tracker.sh","refreshInterval":1000}}' > .claude/settings.json
else
jq '.statusLine = {"type":"command","command":"$CLAUDE_PROJECT_DIR/.claude/statuslines/lines-per-minute-tracker.sh","refreshInterval":1000}' .claude/settings.json > .claude/settings.json.tmp
mv .claude/settings.json.tmp .claude/settings.json
fi
echo "Lines Per Minute Tracker installed successfully!"
echo "Note: Productivity thresholds: HIGH >50 L/min, MED 20-50 L/min, LOW <20 L/min"
echo "Customize thresholds: export LPM_HIGH_THRESHOLD=60 LPM_MED_THRESHOLD=25"
Verify cost.total_lines_added and cost.total_lines_removed fields exist: echo '$input' | jq .cost. Ensure bc is installed: which bc. Check duration_minutes calculation: should be total_duration_ms / 60000. Very short sessions may show 0 until threshold reached. Verify bc is working: echo '10.5 / 2' | bc (should return 5.25).
Daily projection assumes CONTINUOUS coding at current velocity for 8 hours (480 minutes). This is intentional for productivity goal-setting. Actual daily output will be lower with breaks, meetings, etc. Adjust multiplier from 480 to expected active coding minutes per day. Formula: daily_projection = net_per_min * active_minutes_per_day.
Negative net lines means total_lines_removed > total_lines_added. This is EXPECTED for refactoring/cleanup sessions. Script correctly labels as '(refactoring)'. If unexpected, verify you're looking at correct session - multi-file refactors often have more deletions than additions. Check line counts: echo '$input' | jq '.cost | {added: .total_lines_added, removed: .total_lines_removed}'.
Productivity rating is based on TOTAL changes (added + removed), not net lines. Thresholds: <20 L/min = LOW, 20-50 = MED, >50 = HIGH. Check total_per_min calculation: (lines_added + lines_removed) / duration_minutes. Adjust thresholds if your baseline velocity differs: export LPM_HIGH_THRESHOLD=60 LPM_MED_THRESHOLD=25. Verify bc comparison works: echo '25 > 20' | bc (should return 1).
Install bc: brew install bc (macOS), apt install bc (Linux), yum install bc (RHEL/CentOS). Alternative: use integer math with awk: awk -v added=$lines_added -v dur=$duration_minutes 'BEGIN {print added/dur}' - loses decimal precision but works without bc. Verify installation: which bc. Test bc: echo '10.5 / 2' | bc (should return 5.25).
Verify bc scale setting: duration_minutes=$(echo "scale=2; $total_duration_ms / 60000" | bc). Check scale for per-minute calculations: added_per_min=$(echo "scale=1; $lines_added / $duration_minutes" | bc). Ensure bc is using correct precision: echo 'scale=1; 10/3' | bc (should return 3.3). Adjust scale if needed for more/less precision.
Verify threshold values: HIGH_THRESHOLD=50, MED_THRESHOLD=20. Check bc comparison: echo '45 > 50' | bc (should return 0 for false). Test with known values: total_per_min=45 should be MED (between 20-50). Customize thresholds: export LPM_HIGH_THRESHOLD=60 LPM_MED_THRESHOLD=25. Verify script is using environment variables: echo $LPM_HIGH_THRESHOLD.
Check JSON input is being read: echo '$input' | jq .. Verify cost fields exist: echo '$input' | jq .cost.total_lines_added. Check jq is installed: which jq. Verify duration calculation: duration_minutes=$(echo "scale=2; $total_duration_ms / 60000" | bc). Test with sample JSON: echo '{"cost":{"total_lines_added":100,"total_lines_removed":10,"total_duration_ms":120000}}' | jq -r '.cost.total_lines_added // 0' (should return 100). Check refreshInterval in settings.json is set to 1000ms or lower.
Show that Lines Per Minute Tracker - Statuslines is listed on HeyClaude. Paste this Markdown into your README — it renders the badge and links back to this page.
[](https://heyclau.de/entry/statuslines/lines-per-minute-tracker)Lines Per Minute Tracker - Statuslines side by side with 3 alternatives on trust, install, platform support, and disclosed safety notes — all from reviewed registry metadata.
| Field | Real-time coding velocity monitor tracking lines added/removed per minute with productivity scoring and daily output projection for Claude Code sessions. Open dossier | Claude 5-hour conversation block tracker with visual countdown, expiration warnings, and color-coded indicators to prevent unexpected session terminations. Open dossier | Claude Code daily usage quota tracker showing percentage of daily limit consumed with visual progress bar, time remaining, and budget pacing indicators. Open dossier | A Claude Code statusline script (bash) that reads cost.total_duration_ms from the statusline JSON on stdin via jq, converts it to elapsed minutes, and renders a 20-character progress bar, a percent-used figure, and a countdown against a 300-minute (5-hour) ceiling, with green/yellow/red ANSI color coding at the 50%. Open dossier |
|---|---|---|---|---|
| Next steps | ||||
| Trust | ||||
| Review status | ReviewedMaintainer reviewed | ReviewedMaintainer reviewed | ReviewedMaintainer reviewed | ReviewedMaintainer reviewed |
| Package trust | Package not verified | Package not verified | Package not verified | Package not verified |
| Source provenance | Source-backed | Source-backed | Source-backed | Source-backed |
| Submitter | — | — | — | — |
| Install risk | Review first | Review first | Review first | Review first |
| Notes | Safety ✓ Privacy ✓ | Safety ✓ Privacy ✓ | Safety ✓ Privacy ✓ | Safety ✓ Privacy ✓ |
| Brand | — | — | — | — |
| Category | statuslines | statuslines | statuslines | statuslines |
| Source | source-backed | source-backed | source-backed | source-backed |
| Author | JSONbored | JSONbored | JSONbored | JSONbored |
| Added | 2025-10-25 | 2025-10-23 | 2025-10-25 | 2025-10-25 |
| Platforms | Claude Code | Claude Code | Claude Code | Claude Code |
| Source repo | — | — | — | — |
| Safety notes | ✓Runs as a Claude Code statusline command on every refresh and depends on the local shell environment; a failure only affects status rendering, not your session. | ✓Runs as a Claude Code statusline command on every refresh and depends on the local shell environment; a failure only affects status rendering, not your session. | ✓Runs as a Claude Code statusline command on every refresh and depends on the local shell environment; a failure only affects status rendering, not your session. | ✓The installation example runs package-manager commands with elevated privileges (brew install jq, sudo apt-get/yum install jq) and writes an executable script plus statusLine config into .claude/. Review it before running. The installation example overwrites the statusLine key in .claude/settings.json (via a jq rewrite and mv), which replaces any existing statusline configuration. The statusline command executes on every refresh (refreshInterval 1000ms) and shells out to jq and seq each time. |
| Privacy notes | ✓Reads the Claude Code statusline JSON from stdin (model, workspace path, token usage) and renders it in the local terminal; it does not send data off-machine. | ✓Reads the Claude Code statusline JSON from stdin (model, workspace path, token usage) and renders it in the local terminal; it does not send data off-machine. | ✓Reads the Claude Code statusline JSON from stdin (model, workspace path, token usage) and renders it in the local terminal; it does not send data off-machine. | ✓The enhanced example writes per-session timestamp files keyed by session_id into ~/.claude-code-windows on local disk; these persist until manually deleted. The script parses the statusline JSON Claude Code passes on stdin (session_id, cost.total_duration_ms); it stays local and makes no network calls. |
| Prerequisites |
|
|
|
|
| Install | — | — | — | — |
| Config | | | | |
| Citations | ||||
| Claim | Unclaimed | Unclaimed | Unclaimed | Unclaimed |
Source-backed guides for putting this to work.
Loading live community signals…
A short, calm digest of reviewed Claude resources. Unsubscribe any time.