Session monitor and handoff tool for Claude Code
Project description
ANVL
█████████ ██████ █████ █████ █████ █████
███▒▒▒▒▒███ ▒▒██████ ▒▒███ ▒▒███ ▒▒███ ▒▒███
▒███ ▒███ ▒███▒███ ▒███ ▒███ ▒███ ▒███
▒███████████ ▒███▒▒███▒███ ▒███ ▒███ ▒███
▒███▒▒▒▒▒███ ▒███ ▒▒██████ ▒▒███ ███ ▒███
▒███ ▒███ ▒███ ▒▒█████ ▒▒▒█████▒ ▒███ █
█████ █████ █████ ▒▒█████ ▒▒███ ███████████
▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒
⚒ forged by IronDevz
Session monitor for Claude Code — saves your quota by detecting inflated sessions.
The problem
Claude Code resends the entire conversation history on every turn. This is how the API works — there's no persistent memory, so each request includes everything: system prompt, your messages, Claude's responses, tool results, all of it.
On turn 1, this might be 150K tokens. By turn 20, it's 500K. By turn 50, you're sending 1M+ tokens just to get a 2K response back. Your quota burns exponentially.
ANVL detects when this is happening and rotates your session before it wastes quota.
Quick start
1. Install
pip install anvl-monitor
2. Verify it works
anvl --version
If you get anvl: command not found (or similar), Python's Scripts folder isn't in your PATH. Use this instead:
python -m anvl --version
Windows users:
pip installputsanvl.exein Python'sScripts/folder (e.g.C:\Users\YOU\AppData\Local\Programs\Python\Python313\Scripts\). Ifanvlisn't recognized, either:
- Use
python -m anvleverywhere (always works), or- Add the Scripts folder to your PATH:
# PowerShell (run once, then restart terminal) $scripts = python -c "import sysconfig; print(sysconfig.get_path('scripts'))" [Environment]::SetEnvironmentVariable("Path", "$env:Path;$scripts", "User")
3. Initialize
anvl init
That's it. ANVL runs silently in the background via Claude Code hooks. You'll only see it when your session starts inflating:
[ANVL] Session health: 45% (5.4x waste). Consider starting a new conversation soon.
When it's critical, ANVL blocks the session entirely:
[ANVL] Session blocked -- too inflated to continue efficiently.
Handoff saved: handoff.md
Start a new conversation and say: "Read handoff.md and continue where I left off"
How health is calculated
ANVL measures session health as a percentage from 0% to 100%, based on a single metric: waste factor.
Waste factor
waste = peak_avg_tokens_per_turn / calibrated_baseline
-
Calibrated baseline = the global median of "typical turn cost" across all your sessions. Each session contributes its median tokens/turn from the first 5 turns. With 50+ sessions of data, this is a stable reference for what a normal Claude Code turn costs in your workflow.
-
Peak avg = the worst 5-turn window average across the entire session. Health never improves — once a session inflates, it stays marked as inflated.
A fresh session has waste = 1.0x. As the conversation grows and Claude resends more history, tokens/turn increases, waste goes up.
Health percentage
Health maps waste linearly from 100% (fresh) to 0% (critical), weighted by confidence:
raw_health = 100% × (10 - waste) / 9
confidence = min(1.0, turns / 20)
health = raw_health × confidence + 100% × (1 - confidence)
Young sessions are blended toward 100% because waste isn't reliable with few data points. As turns increase, confidence grows and health reflects real waste:
| Waste | 5 turns | 10 turns | 20+ turns |
|---|---|---|---|
| 1.0x | 100% | 100% | 100% |
| 2.0x | 97% | 94% | 88% |
| 5.0x | 88% | 77% | 55% |
| 8.0x | 80% | 61% | 22% |
| 10.0x | 75% | 50% | 0% |
Why tokens/turn matters
Claude Code pricing uses different rates for different token types:
| Token type | Relative cost | What it is |
|---|---|---|
| Input tokens | 1.0x | New content in the prompt |
| Cache read | 0.1x | Previously cached context (90% cheaper) |
| Cache creation | 1.25x | Writing new content to cache |
| Output tokens | 5.0x | Claude's response |
In early turns, most input is cache reads (cheap). As the conversation grows, cache creation increases and more raw input is sent — the cost per turn grows even though the token count might seem similar.
ANVL measures total tokens per turn (all categories combined) because this reflects the actual volume of data being processed, regardless of caching.
How it works
You're working in Claude Code
|
ANVL monitors every turn via hooks
|
Tokens/turn growing? Waste going up?
|
┌────┴────┐
│ < 60% │ ──→ Warning: "Consider starting a new conversation"
│ < 30% │ ──→ Auto-saves handoff.md
│ = 0% │ ──→ Blocks session (exit code 2)
└─────────┘
|
You open a new conversation
|
"Read handoff.md and continue where I left off"
|
Fresh session — back to 100% health
Hooks
ANVL installs three Claude Code hooks:
| Hook | When it runs | What it does |
|---|---|---|
UserPromptSubmit |
Before Claude processes your message | Checks health, warns or blocks |
PostToolUse |
After each tool call | Same check during autonomous work |
SessionStart |
When a new session opens | Injects handoff.md context if it exists |
The SessionStart hook is what makes handoffs seamless — when you open a new session, Claude automatically knows there's a handoff.md to read.
Handoff
When ANVL detects a critically inflated session, it generates handoff.md containing:
- Session summary and what was being worked on
- Files that were created or modified
- Commands that were run
- The last few conversation turns
- Pending/next steps
This gives the new session full context without carrying the token debt.
Installation
# From PyPI (recommended)
pip install anvl-monitor
# From source (for development)
git clone https://github.com/juanlumanmx29/anvl.git
cd anvl
pip install -e .
Requirements: Python 3.11+ | Only dependency: rich (installed automatically)
Note: On all platforms,
python -m anvlworks as an alternative to theanvlcommand.
Setup
anvl init
Run once. This:
- Creates config at
~/.anvl/config.json - Installs hooks in Claude Code (
UserPromptSubmit,PostToolUse,SessionStart) - Writes
CLAUDE.mdwith instructions for Claude to handle handoffs
The hooks are global — once installed, ANVL monitors all sessions in all projects automatically. You don't need to run anvl init per project.
Commands
| Command | Description |
|---|---|
anvl init |
First-time setup (config + hooks + CLAUDE.md) |
anvl status |
Current session health, waste, tokens breakdown |
anvl status --json |
Machine-readable output |
anvl sessions |
All sessions with health status |
anvl sessions --active |
Only active sessions |
anvl monitor |
Live terminal monitor (auto-refreshes) |
anvl calibrate |
View global calibration baseline |
anvl calibrate --reset |
Reset calibration data |
anvl handoff |
Generate handoff manually |
anvl report |
Multi-session report |
Live monitor
anvl monitor
Shows a live dashboard with:
- Health bar with percentage and waste factor
- Global calibrated baseline (median turn cost across all sessions)
- Table of all active sessions with input/output totals
- Tokens wasted by inflation and tokens saved by rotation
Auto-refreshes every 2 seconds. Press Ctrl+C to exit.
Calibration
ANVL learns what a "normal" turn costs by collecting baselines from all your sessions globally. Each session that reaches 5+ turns contributes its median tokens/turn to the global baseline.
anvl calibrate
Shows the current global baseline, session count, and range. With 3+ sessions, calibration activates and health works from turn 1 — no warmup period needed.
Configuration
File: ~/.anvl/config.json
| Field | Default | Description |
|---|---|---|
waste_threshold |
2 | Waste factor to start showing warnings |
handoff_waste_threshold |
10 | Waste factor to block session + auto-handoff |
min_turns_for_alert |
5 | Minimum turns before any alerts fire |
window_hours |
5 | Rolling window for quota tracking |
Alert levels
| Health | Waste | Action |
|---|---|---|
| 60-100% | 1-5x | No alerts — session is healthy |
| 30-60% | 5-8x | Warning: "Consider starting a new conversation" |
| 1-30% | 8-10x | Handoff auto-generated, strong warning |
| 0% | ≥10x | Session blocked (exit code 2), handoff saved |
Blocking requires at least 20 turns — ANVL won't block a short session even if waste is high, because short sessions are cheap regardless.
Bypass: If ANVL blocks your session and you need to send one more message, type anvl bypass before your message. ANVL will skip all checks for that message.
FAQ
Q: Does ANVL slow down Claude Code? No. The hook runs a lightweight scan of the session file (~10ms). It doesn't parse the full JSONL — it uses a fast token counter.
Q: What if I don't want blocking?
Set handoff_waste_threshold to a very high number (e.g., 9999) in your config. You'll still get warnings.
Q: How much quota does session rotation actually save?
Depends on session length. A 50-turn session that gets rotated at turn 25 typically saves 40-60% of what it would have consumed. Run anvl sessions to see estimated savings.
License
MIT — see LICENSE
⚒ Forged by IronDevz
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file anvl_monitor-0.2.1.tar.gz.
File metadata
- Download URL: anvl_monitor-0.2.1.tar.gz
- Upload date:
- Size: 44.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fd6361e9aa487ba6796ef403ce0fc80a0122edfe5d81e4dcb4672932848e1f32
|
|
| MD5 |
c1a6d2dc2f46f703cd97d8fad894ecac
|
|
| BLAKE2b-256 |
c5f5cd5187a7061025cfeec264b48934cb11bb4cd3198b998898b385cb9eca53
|
File details
Details for the file anvl_monitor-0.2.1-py3-none-any.whl.
File metadata
- Download URL: anvl_monitor-0.2.1-py3-none-any.whl
- Upload date:
- Size: 41.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
401d376e3a51910fd005b59c76bc660d142b00f09ef0c5453961c1ac1f031e90
|
|
| MD5 |
efa49bce4dbbabb38017fa27879b4b4f
|
|
| BLAKE2b-256 |
e352d37c8098de5988872d21f583f2ff52b7e14d049be7834b022337f13304ac
|