An AI agent that runs my homelab — I describe a change in plain English, it plans the tool calls and executes them.
GitHub · MIT
I got tired of SSHing through three different boxes to do one small thing — spin up a container, open a port for it, check whether the firewall was actually dropping the scans hitting it. Sentinel is an LLM agent that does all of that from a sentence: I describe what I want, Claude figures out which tools to call, shows me the plan, and only runs it once I confirm.
It's a real agentic system, not a chat wrapper — a single typed tool layer driving my Proxmox host, my OPNsense firewall, and the Docker box, exposed through the Model Context Protocol and the Claude Agent SDK.
Minimal moving parts, but it's a proper agent loop. Here's the whole path from a sentence to a change on the hardware:
plain English
│
▼
Claude Opus 4.8 ── agentic tool-use loop, adaptive thinking
│ picks + sequences tools
▼
tool layer ──▶ safety gate (dry-run / confirm) ──▶ audit log (SQLite)
│
▼
providers ──▶ Proxmox · OPNsense · Docker (API / REST / SSH)
At the center is a Claude Agent SDK loop running Claude Opus 4.8 with adaptive thinking. It's standard tool use / function calling: the model reads the request, decides which tools to call and in what order, reads each result, and either calls more or answers. The model plans; the harness executes. I stay in the loop for anything that changes state.
Every capability is a single typed function in one module. That module is wrapped two ways: a FastMCP server over stdio (the MCP server that Claude Desktop and the Claude Code plugin connect to) and an in-process MCP server registered with the Claude Agent SDK (what the deploy/chat agent and the CLI drive). Same functions behind all of it, so a deploy behaves identically whether it comes from Claude Desktop, Claude Code, or the terminal.
A tool that changes something never just acts. It runs a fixed pipeline:
PlannedChange — a structured description of what it would do, flagged destructive or not;confirm=true, and refuses outright if it's destructive and unconfirmed;ActionResult.The gate and the audit live in the tool layer, not in any one surface — so the same guarantees hold whether the call came from the agent, the MCP server, or the CLI.
Providers are thin and side-effect-honest — a method that mutates, mutates; nothing hides logic.
proxmoxer (token auth), falling back to qm/pct over SSH.httpx) for rules and IPS settings, plus SSH for what the API doesn't expose: configctl, cscli, Suricata, GeoIP via mmdblookup, and the raw filter log. Mutations back up config.xml first and only use supported apply paths.docker CLI over SSH, plus parsing Nginx Proxy Manager access logs for per-domain stats.The one-sentence deploy and the dashboard run as a FastAPI service (the agent) alongside a small Next.js front-end that reads the audit log and calls the agent to plan a deploy.
One sentence becomes a real command. It plans first, then asks.
$ sentinel deploy "run postgres:16, 2GB ram, expose 5432, volume pgdata"
plan (nothing applied yet):
docker run -d --name pg --restart unless-stopped --memory 2g \
-p 5432:5432 -v pgdata:/var/lib/postgresql/data postgres:16
Apply this plan? [y/N]
Every change is a dry run unless I pass a confirm. Anything destructive — stopping a VM, deleting a firewall rule, removing a container — refuses to run without it, and every action gets logged.
I added that after I once stopped sshd mid-change on the firewall and locked myself out. Recoverable, but annoying. Now firewall changes only go through supported paths and back up the config first, so that particular mistake can't happen again.
uv sync
cp config.example.yaml config.yaml # your hosts
cp .env.example .env # API key + ssh key
uv run sentinel status # read-only sanity check
uv run sentinel deploy "..." # plans, then asks
uv run sentinel mcp # expose tools to Claude Desktop / Code
Full setup, including the Claude Desktop and Claude Code wiring, is in the README.
Python · Claude Opus 4.8 · Claude Agent SDK · Model Context Protocol (FastMCP) · tool-use / function calling · FastAPI · Typer · Pydantic · paramiko · proxmoxer · httpx · SQLite · a small Next.js dashboard · Docker.