agent-vitals
README.md
<p align="center">
<img src=".github/assets/banner.png" alt="agent-vitals: your agent, self-aware" width="100%">
</p>
<p align="center">
<a href="https://github.com/anirudhprashant/agent-vitals/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/anirudhprashant/agent-vitals/ci.yml?style=flat-square&label=tests&labelColor=0B0F0E&color=00D992"></a>
<img alt="v0.7.0" src="https://img.shields.io/badge/version-v0.7.0-0B0F0E?style=flat-square&labelColor=0B0F0E&color=1C2B26">
<img alt="Python 3.11+" src="https://img.shields.io/badge/python-3.11%2B-00D992?style=flat-square&labelColor=0B0F0E">
<a href="https://modelcontextprotocol.io"><img alt="MCP" src="https://img.shields.io/badge/MCP-13%20tools-00D992?style=flat-square&labelColor=0B0F0E"></a>
<a href="LICENSE"><img alt="GPL v3" src="https://img.shields.io/badge/license-GPL%20v3-1C2B26?style=flat-square&labelColor=0B0F0E"></a>
</p>
<p align="center">
<b>Give your AI agent a memory of its own infrastructure.</b><br>
An MCP server your agent calls <i>before</i> it touches cron, systemd or your MCP setup,<br>
so it stops saying "your crontab is fine" when it isn't.
</p>
<p align="center">
<code>Claude Code</code> · <code>pi</code> · <code>Cursor</code> · <code>OpenCode</code> · <code>Codex CLI</code> | no daemon · no cloud · read-only
</p>
<br>
## 30-second install
```bash
uv tool install git+https://github.com/anirudhprashant/agent-vitals
av install # finds every agent host on your machine and wires up MCP + a priming skill
```
Restart your agent host. From then on it calls `vitals_summary` before risky work, without you asking.
> [!NOTE]
> An unrelated package called `agent-vitals` exists on PyPI. Install from this repo as shown above.
## The difference
<table>
<tr>
<th width="50%" align="left">Without vitals</th>
<th width="50%" align="left">With vitals</th>
</tr>
<tr>
<td valign="top">
```text
You: schedule a daily backup at 2am
Agent: done.
0 2 * * * /home/me/backup.sh
```
`backup.sh` doesn't exist. The cron job fails silently, every night, forever.
</td>
<td valign="top">
```text
You: schedule a daily backup at 2am
Agent: checking first.
→ shadow_stale no broken jobs
→ backup.sh exists, executable
→ crontab updated
→ shadow_stale still clean ✓
```
</td>
</tr>
<tr>
<td valign="top">
```text
You: is my agent setup healthy?
Agent: looks fine to me!
```
(it has no idea)
</td>
<td valign="top">
```text
You: is my agent setup healthy?
Agent: → vitals_summary
shadow: 13 autonomous things configured
claude code (7d): ⚠ 36 stuck sessions
```
</td>
</tr>
</table>
## How it works
<p align="center"><img src=".github/assets/flow.png" alt="Agent hosts call the vitals MCP server, which reads crontab, systemd, MCP configs, skills and session logs" width="100%"></p>
1. **Install.** `av install` registers the MCP server and a priming skill with each host it finds.
2. **Observe.** The skill tells the agent when to call which tool. Optional hooks go further and *refuse* `crontab` and `systemctl --user` changes until vitals has been checked.
3. **Improve.** `av cost`, `av loops` and `av coach` turn your own session history into cheaper, less loopy agents.
Everything is local and read-only. Session traces are summarised by structure, never by content, so no payloads or secrets leave the log files.
## What it catches
| | |
|---|---|
| **Stale automation** | Cron jobs, systemd timers, MCP servers and scheduled skills that point at things which no longer exist |
| **Stuck sessions** | Per-agent completion rates, trends, and sessions that look stuck |
| **Doom loops** | Exact and soft repeats in Bash and Edit calls, with polling excluded and edits compared by content |
| **Dead weight** | MCP servers and tools you never call, each of which costs context on every turn |
| **Spend** | Model-aware token cost, an Effective Tokens metric, and model downgrade suggestions |
| **SSH polling** | The same command sent to the same host over and over |
| **Overlap** | Duplicate or near-identical tools across MCP servers |
| **Bloat** | Compaction for oversized session files, with a backup and a dry run first |
## MCP tools
The 13 tools your agent can call. All are read-only and safe to call repeatedly.
| Tool | Use it |
|---|---|
| `vitals_summary` | **First**, before any non-trivial task, or when something feels off |
| `shadow_list` | Before infra changes: everything running on your behalf |
| `shadow_stale` | Before claiming cron is fine, or scheduling new work |
| `burnout_summary` | After long tasks, to compare against baseline |
| `burnout_stuck_sessions` | When a loop is suspected |
| `trace_list` · `trace_summary` | Find and summarise recorded sessions |
| `trace_diff` | Compare a good run with a bad one |
| `trace_errors` · `trace_grep` | Only the failures, or only one tool |
| `trace_profile` · `trace_export` · `trace_suggest` | Per-tool timings, JSON export, and concrete fixes |
## Pre-action hooks
Priming *asks* the agent to check. Hooks *enforce* it.
```bash
av hooks install # one-time, about 3 seconds
av hooks status
av hooks disable # or: av hooks uninstall
```
```text
⚡ vitals hook: refused `crontab -e`
reason: vitals stamp is 5m12s old, exceeds 60s window
refresh: call any vitals tool or run `av doctor`
bypass: VITALS_BYPASS=1 crontab -e
```
Gated: `crontab -e/-r/-i/<file>` and `systemctl --user` state changes. Never gated: reads (`crontab -l`, `systemctl status`, `list-*`) and power management. A stale stamp will never block a reboot.
## CLI
```bash
av # one-shot health summary
av doctor # summary + what to fix
av shadow [--watch] # everything configured on this machine
av burnout # completion metrics, last 7 days
av drift # inconsistencies across hosts
av loops # doom-loop detector
av unused # MCP servers and tools you never call
av cost # spend, Effective Tokens, downgrade ideas
av tokens [--suggest]
av ssh # repeated SSH polling to the same host
av overlap # duplicate tools across MCP servers
av sessions # session files with age and size
av snapshot # tar.gz of agent state (MCP configs, skills, hooks)
av detect # list detected agent hosts
av mcp # run the MCP server (stdio)
av init # old alias for `av install`
av compact [--dry-run]
av coach # system prompts built from your real sessions
av trace list | summary | replay | diff | errors | profile | grep | export | suggest | watch
```
## Supported hosts
| Host | MCP config | Priming |
|---|---|---|
| **Claude Code** | `~/.claude/.mcp.json` | `~/.claude/skills/vitals/SKILL.md` |
| **pi** | `~/.pi/agent/mcp.json` | `~/.claude/skills/vitals/SKILL.md` |
| **Cursor** | `~/.cursor/mcp.json` | `~/.cursor/rules/vitals.md` |
| **OpenCode** | `~/.config/opencode/mcp.json` | `~/.config/opencode/AGENTS.md` |
| **Codex CLI** | `~/.codex/config.toml` | `~/.codex/AGENTS.md` |
`av install` is idempotent: re-running it skips existing entries and never duplicates them.
## Roadmap
- [x] **0.1** `shadow` and `burnout`
- [x] **0.2** MCP server, `av install` for five hosts
- [x] **0.3** pre-action hooks
- [x] **0.6** efficiency suite: loops, unused, cost, tokens, ssh, overlap, compact, coach
- [x] **0.7** trace suite for Claude Code and pi sessions
- [ ] `shadow live`: running agent processes as a tree
- [ ] Agent déjà vu: "you researched this codebase three weeks ago"
## Contributing
- **Scanners** in `src/agent_vitals/scanners.py` are independent and fail gracefully. Add a source by writing one `scan_*()` function and registering it in `scan_all()`.
- **Tool docstrings are the product.** The agent reads them as instructions, so write them as directives ("call this first when…"), not API docs.
- Run `pytest -q`. CI tests Python 3.11 to 3.13.
About 6,000 lines of Python and 300+ tests. Built with typer, rich and FastMCP.
---
<p align="center"><sub>GPL v3 · made by <a href="https://github.com/anirudhprashant">Anirudh Prashant</a></sub></p>
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues