{
  "markdown": "<p align=\"center\">\n  <img src=\"assets/logo.png\" alt=\"HomeButler logo\" width=\"140\">\n</p>\n\n<h1 align=\"center\">HomeButler</h1>\n\n<p align=\"center\">\n  <strong>Only the changes worth mentioning.</strong><br>\n  A single Go binary that remembers what your server looked like last time,\n  and tells you — or an agent — what moved.\n</p>\n\n<p align=\"center\">\n  <a href=\"https://homebutler.dev\">Website</a> ·\n  <a href=\"https://github.com/Higangssh/homebutler#readme\">Docs</a> ·\n  <a href=\"https://github.com/Higangssh/homebutler/releases\">Releases</a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://go.dev\"><img src=\"https://img.shields.io/badge/Go-1.25+-00ADD8?logo=go&logoColor=white\" alt=\"Go 1.25+\"></a>\n  <a href=\"LICENSE\"><img src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" alt=\"License: MIT\"></a>\n  <a href=\"https://github.com/Higangssh/homebutler/releases\"><img src=\"https://img.shields.io/github/v/release/Higangssh/homebutler\" alt=\"Release\"></a>\n  <a href=\"https://glama.ai/mcp/servers/Higangssh/homebutler\"><img src=\"https://glama.ai/mcp/servers/Higangssh/homebutler/badges/score.svg\" alt=\"homebutler MCP server\"></a>\n</p>\n\n<p align=\"center\">\n  <img src=\"assets/mascot.png\" alt=\"HomeButler mascot holding a tiny server\" width=\"220\">\n</p>\n\n<p align=\"center\">\n  <img src=\"assets/report-card.svg\" alt=\"homebutler report output: a port answered by a different service flagged under Needs Attention, then what changed since the last report — a container gone, one new, one recreated behind the same name, a process running a different invocation, a port that changed owner — then current status and the command to verify the port\" width=\"620\">\n</p>\n\nSection rules, labels, and severities are colour-coded in a terminal. Colour is\ndropped automatically when output is piped, redirected, or run from cron.\n\nThat is the whole idea. Most homelab tools show you a graph of right now, and leave\n\"does this matter?\" to you. HomeButler remembers what your server looked like last\ntime, decides what is worth saying, and says it — six containers before and six after\nis not \"no change\" when one of them is a different container.\n\n### Reading a change\n\nEvery line is three columns: **what kind of change**, **what it happened to**, and\n**what exactly happened**. The kind is one of eight words, and it is the same word in\n`--json`, so an agent branches on it without reading prose:\n\n| Kind | Means | You would see it after |\n| --- | --- | --- |\n| `gone` | it was there last time and is not now | `docker rm`, a service stopping, a port closing |\n| `new` | it was not there last time and is now | starting anything |\n| `replaced` | same name, different thing underneath | `docker compose up -d` — the container is recreated, so the name and the count are unchanged |\n| `image` | same container, different image | pulling a new tag |\n| `state` | same container, running where it was stopped, or the reverse | a crash, or bringing something back up |\n| `port` | same port, a different process answering on it | one service taking over another's port |\n| `disk` | a mount moved by more than half a gigabyte | anything that writes |\n| `skipped` | the comparison could not be made | Docker was down when either snapshot was taken |\n\n`replaced` is the one the rest of this exists for. A container recreated under the\nsame name leaves every count identical, which is why a report that compares counts —\nas this one did before 0.26.0 — answers \"no significant changes\" while the thing you\nwere running has been swapped out underneath you.\n\n`skipped` is the second: homebutler says it could not compare rather than reporting\nnothing changed. An all-clear it cannot stand behind is worse than no answer.\n\nThe header names the snapshot being compared against, so \"what changed\" is never\nambiguous about the window it covers.\n\n📖 **[What earns a line, and what is deliberately suppressed →](docs/report.md)**\n\nHomeButler helps you answer the boring but painful questions every homelab eventually creates:\n\n- What is running on my server right now?\n- Which container owns this port?\n- Why did this service restart at 3 AM?\n- Is my backup actually restorable?\n- Can I install this self-hosted app without hand-writing another compose file?\n- Can I let an AI assistant inspect my server without handing it a full SSH shell?\n\nNo daemon required. No database. No always-on web service. Just one Go binary you can use from the terminal, scripts, a web dashboard, or AI tools.\n\nThe design goal is simple: give humans and agents a narrow, structured interface to the server. HomeButler returns readable summaries and JSON instead of asking you to trust a black-box shell session.\n\n<p align=\"center\">\n  <a href=\"https://www.youtube.com/watch?v=MFoDiYRH_nE\">\n    <img src=\"assets/demo-thumbnail.png\" alt=\"homebutler demo\" width=\"800\" />\n  </a>\n</p>\n<p align=\"center\"><em>▶️ 34s demo — monitor, diagnose, and manage your homelab</em></p>\n\n## Quick Start\n\n```bash\n# One-line install (auto-detects OS/arch)\ncurl -fsSL https://raw.githubusercontent.com/Higangssh/homebutler/main/install.sh | sh\n\n# Or via Homebrew\nbrew install Higangssh/homebutler/homebutler\n\n# Interactive setup — add your servers in seconds\nhomebutler init\n```\n\nUse it right away:\n\n```bash\nhomebutler status                    # CPU, memory, disk, uptime\nhomebutler docker list               # running containers\nhomebutler inventory scan            # containers + ports + topology\nhomebutler report                    # butler-style health report + change summary\nhomebutler install uptime-kuma       # deploy a self-hosted app\nhomebutler backup drill uptime-kuma  # verify a backup actually restores\nhomebutler watch tui                 # terminal dashboard\nhomebutler serve                     # web dashboard at http://localhost:8080\n```\n\nMachine-readable output is available everywhere:\n\n```bash\nhomebutler status --json\nhomebutler inventory scan --json\nhomebutler report --json\n```\n\n## What it does\n\n- **Install apps** — deploy Uptime Kuma, Jellyfin, Pi-hole, Gitea, Portainer, and more with one command\n- **Map your server** — see containers, exposed ports, system ports, and service topology\n- **Run a doctor check** — diagnose resource pressure, stopped containers, public ports, backup hygiene, notifications, report baseline readiness, and configured Proxmox endpoint reachability\n- **Catch crashes** — save logs before/after Docker, systemd, or PM2 restarts and detect flapping loops\n- **Verify backups** — boot backups in isolated containers before you trust them\n- **See a Proxmox cluster** — nodes, QEMU and LXC guests, storage, task status, and honest dashboard freshness, with power actions that name their target explicitly\n- **Use it anywhere** — CLI, JSON, web dashboard, or MCP for AI agents without giving them SSH\n\n## Why homebutler?\n\nSelf-hosting is not hard because one `docker compose up` is hard. It is hard because the maintenance never ends: ports collide, containers restart silently, backups look fine until restore day, and every server becomes a slightly different snowflake.\n\nHomeButler is a small operations toolkit for that messy middle.\n\n### Why not just use Portainer, Netdata, or CasaOS?\n\nThose are great dashboards. HomeButler is CLI-first, scriptable, JSON-friendly, air-gap friendly, and safe to copy onto any server. Use it when you want commands you can run from a terminal, cron job, SSH session, CI script, or AI agent — especially when you care more about “what changed?” than another graph.\n\n## Core workflows\n\n### 🧾 Butler Report\n\n```bash\nhomebutler report\nhomebutler report --keep 7      # retain only the latest 7 snapshots\nhomebutler report --no-save     # preview without writing a snapshot\n```\n\n`report` gives you a concise butler-style summary of your homelab: current health, warnings, notable changes since the previous snapshot, and suggested next commands. On the first run, HomeButler creates a baseline under `~/.homebutler/reports/snapshots/`; later runs compare against the latest snapshot. Old snapshots are pruned automatically (`--keep 30` by default) so reports do not grow forever.\n\n### 🩺 Doctor Check\n\n```bash\nhomebutler doctor\nhomebutler doctor --strict          # non-zero exit if warnings/failures are found\nhomebutler doctor --json            # automation / MCP friendly\n```\n\n<p align=\"center\">\n  <img src=\"assets/doctor-card.svg\" alt=\"homebutler doctor reporting a full disk, a stopped container, and a missing report baseline, each with the command to run next\" width=\"700\">\n</p>\n\n`doctor` is a read-only preflight for the problems homelab users usually discover too late: high disk or memory usage, stopped containers, public bind ports, stale or missing backups, missing notifications, whether `report` has a baseline for change detection, and whether each configured Proxmox endpoint is reachable with the token it has. Every finding names the next command to run, so `--strict` makes it usable from cron or CI — including a Proxmox host that is unreachable or rebooting.\n\n### 🗂 Config Validation\n\n```bash\nhomebutler config validate\nhomebutler config validate --strict   # exit non-zero on warnings too\nhomebutler config validate --json\n```\n\n`config validate` reads your config without starting anything and tells you\nwhich file was used, which of the four resolution rules picked it, and what\nhomebutler actually made of each section. It exists because the two ways config\ngoes wrong are both silent: a key homebutler does not recognise is dropped\nwithout a word, and a `--config` path that does not exist falls back to\nbuilt-in defaults rather than failing.\n\n```text\nSections\n   ✓ servers     2 servers (homelab, nas)\n   · notify      not set\n   ✓ alerts      cpu 95% · memory 85% · disk 90%\n\nFindings\n   ⚠️ Line 5: field notifiy not found in the homebutler config\n      → Did you mean \"notify\"? Unrecognised keys are ignored silently.\n```\n\n### 📦 One-Command App Install\n\n<p align=\"center\">\n  <img src=\"assets/install-demo.gif\" alt=\"homebutler install demo\" width=\"900\">\n</p>\n\n> **`homebutler install uptime-kuma`** — Deploy self-hosted apps in seconds. Pre-checks Docker, ports, and duplicates. Generates `docker-compose.yml` automatically. [See all available apps →](#app-install)\n\n### 🗺️ Inventory & Topology\n\n```bash\nhomebutler inventory scan\nhomebutler inventory show --filter exposed\nhomebutler inventory export --format mermaid\nhomebutler --json inventory scan\n```\n\n`inventory scan` gives you a quick map of what is running on a server: system health, Docker containers, app ports, and system ports. Docker-published ports are connected back to the container that owns them, so local forwarding details like Colima/Lima stay understandable.\n\n```text\n🏠 Home Network\n   Server  homelab (192.168.1.10)\n   Summary ✅ 1 running · ⚪ 1 stopped · 🌍 2 public ports · 🔒 4 local ports\n\n📦 Containers (2)\n   ├─ ⚪ vaultwarden · not started\n   │  └─ image vaultwarden/server:latest\n   └─ ✅ api-server · running\n      ├─ image my-api:latest\n      └─ exposes :8080 → 8080/tcp\n\n🌐 App Ports (1)\n   └─ 🌍 :8080/tcp · api-server\n```\n\nTo answer \"what is reachable from outside my machine/network?\" without reading the whole tree, filter the scan to exposed ports only:\n\n```bash\nhomebutler inventory scan --filter exposed\n```\n\n```text\n🏠 Home Network\n   Server  homelab\n\n🌐 Exposed Ports\n   ├─ :8080/tcp · api-server\n   └─ :8443/tcp · dashboard\n```\n\nOnly ports listening on all interfaces (`0.0.0.0`, `::`, `*`) are shown. Anything bound to a specific address is hidden, including loopback and LAN addresses. Unsupported filter values return an error, as does combining `--filter` with `--json`; the default `inventory scan` output is unchanged.\n\nUse Mermaid export when you want a diagram for GitHub, Obsidian, docs, or an AI assistant:\n\n```mermaid\ngraph TD\n  home[\"🏠 Home Network\"] --> homelab[\"🖥 homelab<br/>192.168.1.10\"]\n  homelab --> c1[\"📦 api-server<br/>running\"]\n  homelab --> p1[\"🌍 :8080/tcp<br/>api-server\"]\n  c1 -. exposes .-> p1\n```\n\n## Demo\n\n### 🌐 Web Dashboard\n\n<p align=\"center\">\n  <img src=\"assets/web-dashboard.png\" alt=\"homebutler web dashboard\" width=\"900\">\n</p>\n\n> **`homebutler serve`** — A real-time web dashboard embedded in the single binary via `go:embed`. Monitor all your servers, Docker containers, open ports, alerts, and Wake-on-LAN devices from any browser. Dark theme, auto-refresh every 5 seconds, fully responsive.\n\n<details>\n<summary>✨ Web Dashboard Highlights</summary>\n\n- **Server Overview** — See all servers at a glance with color-coded status (green = online, red = offline)\n- **System Metrics** — CPU, memory, disk usage with progress bars and color thresholds\n- **Docker Containers** — Running/stopped status with friendly labels (\"Running · 4d\", \"Stopped · 6h ago\")\n- **Top Processes** — Top processes sorted by CPU/memory with zombie detection\n- **Resource Warnings** — Visual CPU, memory, and disk thresholds in the dashboard\n- **Network Ports** — Open ports with process names and bind addresses\n- **Wake-on-LAN** — One-click wake buttons for configured devices\n- **Server Switching** — Dropdown to switch between local and remote servers\n- **Zero dependencies** — No Node.js runtime needed. Frontend is compiled into the Go binary at build time\n\n```bash\nhomebutler serve              # Start on port 8080\nhomebutler serve --port 3000  # Custom port\nhomebutler serve --demo       # Demo mode with realistic sample data\n```\n\n</details>\n\n### 🔄 Process Restart Watch\n\nYour container crashed at 3 AM — but **why?** `homebutler watch` catches it the moment it happens, saves the dying logs, figures out the cause, and tells you if it's happening over and over.\n\n**Supported backends:** Docker (real-time event stream) · systemd (polling) · PM2 (polling)\n\n#### Step 1: Add targets to watch\n\n```bash\nhomebutler watch add nginx              # Interactive: choose Docker / systemd / PM2\nhomebutler watch add --kind docker nginx          # or specify directly\nhomebutler watch add --kind systemd nginx.service\nhomebutler watch add --kind pm2 my-api\nhomebutler watch list                   # See what you're watching\n```\n\n#### Step 2: Start monitoring\n\n```bash\nhomebutler watch start                  # Foreground, Ctrl+C to stop\nhomebutler watch start --interval 10s   # Custom poll interval (default 30s)\n```\n\n```bash\nhomebutler watch install     # register it with systemd or launchd\nhomebutler watch installed   # is it registered?\nhomebutler watch uninstall\n```\n\n`watch install` hands the loop to whatever supervises the host — a systemd user\nunit on Linux, a launchd agent on macOS — so monitoring survives logout and\nreboot. Both are user-level and neither is a preference: on Linux the watch list\nlives in your home directory, so a root unit would find an empty list; on macOS\nDocker Desktop only runs inside a logged-in session, so a LaunchDaemon would\npoll a daemon that is not there. On Linux a user unit stops at logout unless you\nrun `sudo loginctl enable-linger $USER`, which `watch install` tells you.\n\n`watch start` is the monitoring process. It watches the containers and services\non the watch list for restarts, checks CPU, memory and disk against your\nthresholds, and runs any remediation rules you have configured — one process,\none set of notification providers. `alerts --watch` still exists and does the\nthreshold half on its own.\n\nEvery endpoint under `proxmox:` in your config is polled too: unreachable or\nACL-filtered endpoints and any guest listed under that endpoint's `guests:`\nreport one incident when the problem starts and one recovery incident when it\nclears. A guest not listed there is observational only — `watch start` never\nalerts on it, deliberately stopped or not. See\n[Proxmox setup →](docs/proxmox.md#watch-integration) for the `guests:` field.\n\nWhen a crash is detected, you'll see:\n\n```\n[03:14:22] INCIDENT: nginx (incident nginx-20260410-031422.581-7a2124)\n  Crash: OOM — process killed by SIGKILL (oom, confidence: high)\n  ⚠ FLAPPING: acute (3 restarts in short window)\n```\n\n#### Step 3: Investigate\n\n```bash\nhomebutler watch history                # List all incidents\nhomebutler watch show <incident-id>     # Full details\n```\n\n`watch show` output includes:\n- **Pre-death logs** — what the process printed right before it died\n- **Post-restart logs** — what happened after the restart\n- **Crash analysis** — category (oom / panic / segfault / timeout / dependency / error), reason, confidence level, matched log patterns\n- **Flapping status** — if the process is stuck in a crash loop\n\n#### Crash Analysis\n\nEvery incident is automatically analyzed using exit codes and log patterns:\n\n| Signal | Exit Code | Meaning |\n|--------|-----------|---------|\n| SIGKILL | 137 | OOM Killer or forced kill |\n| SIGSEGV | 139 | Segmentation fault (memory corruption) |\n| SIGTERM | 143 | Graceful shutdown request |\n| — | 1 | Application error |\n| — | 0 | Clean exit (may be intentional restart) |\n\nLog patterns like `panic:`, `Out of memory`, `Connection refused`, `FATAL`, and `timeout` are matched automatically to help identify the root cause.\n\n#### Flapping Detection\n\nDetects when a process is stuck in a restart loop (e.g., crash → restart → crash again):\n\n- **Acute** — 3+ restarts within 10 minutes (something is broken right now)\n- **Chronic** — 5+ restarts within 24 hours (slow recurring issue)\n\nFlapping incidents are tagged `[FLAPPING]` in history and highlighted in `watch show`.\n\n#### Notifications (optional, off by default)\n\nNotifications are disabled by default, which is useful for air-gapped or closed networks where everything runs locally.\n\nA minimal example in `~/.config/homebutler/config.yaml`:\n\n```yaml\nnotify:\n  telegram:\n    bot_token: \"your-bot-token\"\n    chat_id: \"your-chat-id\"\n\nwatch:\n  enabled: true\n  notify_on: flapping\n  cooldown: 5m\n  flapping:\n    short_window: 10m\n    short_threshold: 3\n    long_window: 24h\n    long_threshold: 5\n  retention:\n    max_incidents: 200\n\nalerts:\n  cpu: 90\n  memory: 85\n  disk: 90\n  rules:\n    - name: cpu-spike\n      metric: cpu\n      threshold: 90\n      action: notify\n\n    - name: elsa-monitor-down\n      metric: container\n      kind: systemd          # docker (default) | systemd | pm2\n      watch: [lh-elsa-monitor.service]\n      action: restart\n```\n\n### Restarting things that are not containers\n\n`action: restart` restarts Docker containers unless the rule says otherwise.\n`kind: systemd` or `kind: pm2` points it at a service or a PM2 app instead.\n\nThe kind is written on the rule rather than looked up from the watch list, so\nrestarting a host service is something you asked for in the config. It also\nmeans every rule written before `kind` existed keeps meaning exactly what it\nmeant.\n\nTwo things worth knowing before using it:\n\n**`systemctl restart` needs root or a polkit rule.** Running homebutler\nunprivileged, a systemd restart will be refused, reported as failed, and\nwarned about when `alerts --watch` starts rather than when the rule first\nfires.\n\n**A target that is flapping is not restarted.** Restarting something already\nin a restart loop feeds the loop, and most systemd units carry\n`Restart=always`, so homebutler restarting them fights systemd's own backoff.\nThe thresholds are the `watch.flapping` ones above, and the skip is reported\nrather than counted as either success or failure. This applies to Docker\ntargets too.\n\nLegacy `~/.homebutler/watch/config.json` is still read as a fallback for watch-specific settings, and legacy `alerts.yaml` notify/webhook provider settings are still accepted for older setups.\n\n- `watch.enabled: true` — allow watch notifications\n- `watch.notify_on: flapping` — notify only when repeated restart loops are detected\n- `watch.notify_on: incident` — notify on every incident\n- `watch.notify_on: all` — notify on both incidents and flapping\n- `watch.notify_on: off` — disable watch notifications without removing provider config\n- `watch.cooldown: 5m` — suppress duplicate notifications for the same event fingerprint during the cooldown window\n- `watch.flapping` — optional advanced tuning for restart-loop detection\n- `watch.retention.max_incidents: 200` — how many incidents to keep on disk, newest first. The directory grows fastest exactly when a service is restarting in a loop. Set `-1` to keep everything.\n\n  Each incident keeps up to 100 captured log lines per side, and at most 64 KB of them. Line counts alone do not bound a file: one stack trace or JSON document on a single line is arbitrarily long, and a container being OOM-killed is exactly the one likely to write one. A log that does not fit keeps its end — the last thing a process said is what explains why it stopped — and says how much was dropped.\n\nThese settings can also be written under a `watch.notify:` block, which is the\ncanonical form:\n\n```yaml\nwatch:\n  notify:\n    enabled: true\n    notify_on: flapping\n    cooldown: 5m\n  flapping:\n    short_window: 10m\n```\n\nBoth spellings are read, so either layout works. If a file contains both, the\n`notify:` block wins and `homebutler config validate` says so.\n\n#### Manage targets\n\n```bash\nhomebutler watch remove nginx           # Stop watching\nhomebutler watch check                  # One-shot check (no continuous monitoring)\n```\n\n### 🧊 Proxmox VE\n\n```bash\nhomebutler proxmox status\nhomebutler proxmox guests --status running\nhomebutler proxmox guest shutdown --node pve1 --type lxc --vmid 105 --confirm\nhomebutler proxmox task UPID:pve1:... --node pve1\n```\n\nA Proxmox endpoint is its own kind of target, configured under `proxmox:` with an\nAPI token rather than SSH, so it does not join the `--server` or `--all` fan-out.\nTLS verification stays on: trust comes from a pinned SHA-256 fingerprint, then a\nCA file, and only then an explicit `insecure` fallback.\n\nReads are plain. Power actions are not: every one of them takes an explicit\nendpoint, node, guest type and VMID, and refuses to run without `--confirm`,\nwhich is checked before any credential is read. They also need their own\n`action_token_id` (plus `action_token` or `action_token_file`) configured on\nthe endpoint — the read token alone will not start, reboot, or shut down a\nguest; see [Proxmox setup →](docs/proxmox.md) for creating that second token.\n`shutdown` asks the guest to shut down cleanly — it is not Proxmox's hard\n`stop`, which cuts power and can leave a filesystem behind it. A successful\naction reports the task it submitted, not that the guest finished; `proxmox\ntask` answers that separately.\n\n`proxmox script` prints the install command for a Community Script pinned to one\ncommit, along with a warning that the script is not reviewed by homebutler and\nruns as root. It never fetches or runs it — see [#62](https://github.com/Higangssh/homebutler/issues/62)\nfor why that line is where it is.\n\n📖 **[Proxmox setup, tokens, and TLS →](docs/proxmox.md)**\n\n### 🖥️ TUI Dashboard\n\n<p align=\"center\">\n  <img src=\"demo/demo-tui.gif\" alt=\"homebutler TUI dashboard\" width=\"800\">\n</p>\n\n> **`homebutler watch tui`** — A terminal-based dashboard powered by Bubble Tea. Monitors all configured servers with real-time updates, color-coded resource bars, and Docker container status. No browser needed.\n\n### 🧠 AI-Powered Management (MCP)\n\n> **Use natural language when you want automation.** MCP clients can call homebutler tools to check server status, list Docker containers, inspect ports, or run operational workflows. [See screenshots & setup →](#mcp-server)\n\n## App Install\n\nDeploy self-hosted apps with a single command. Each app runs via **docker compose** with automatic pre-checks, health verification, and clean lifecycle management.\n\n```bash\n# List available apps\nhomebutler install list\n\n# Install (default port)\nhomebutler install uptime-kuma\n\n# Install with custom port\nhomebutler install uptime-kuma --port 8080\n\n# Install jellyfin with media directory\nhomebutler install jellyfin --media /mnt/movies\n\n# Check status\nhomebutler install status uptime-kuma\n\n# Stop (data preserved)\nhomebutler install uninstall uptime-kuma\n\n# Stop + delete everything\nhomebutler install purge uptime-kuma\n```\n\n### How it works\n\n```\n~/.homebutler/apps/\n  └── uptime-kuma/\n       ├── docker-compose.yml   ← auto-generated, editable\n       └── data/                ← persistent data (bind mount)\n```\n\n- **Pre-checks** — Verifies docker is installed/running, port is available, no duplicate containers\n- **Compose-based** — Each app gets its own `docker-compose.yml` you can inspect and customize\n- **Data safety** — `uninstall` stops containers but keeps your data; `purge` removes everything\n- **Cross-platform** — Auto-detects docker socket (default, colima, podman)\n\n### Available apps\n\n| App | Default Port | Description | Notes |\n|-----|-------------|-------------|-------|\n| `uptime-kuma` | 3001 | Self-hosted monitoring tool | |\n| `plex` | 32400 | Plex Media Server | `--media /path` to mount media dir |\n| `vaultwarden` | 8080 | Bitwarden-compatible password manager | |\n| `filebrowser` | 8081 | Web-based file manager | |\n| `it-tools` | 8082 | Developer utilities (JSON, Base64, Hash, etc.) | |\n| `gitea` | 3002 | Lightweight self-hosted Git service | |\n| `jellyfin` | 8096 | Media system (movies, TV, music) | `--media /path` to mount media dir |\n| `homepage` | 3010 | Modern homelab dashboard | |\n| `stirling-pdf` | 8083 | All-in-one PDF tool (merge, split, convert, OCR) | |\n| `speedtest-tracker` | 8084 | Internet speed test with historical graphs | |\n| `mealie` | 9925 | Recipe manager and meal planner | |\n| `pi-hole` | 8088 | DNS ad blocking | ⚠️ Uses port 53 (DNS), NET_ADMIN capability |\n| `adguard-home` | 3000 | DNS ad blocker and privacy | ⚠️ Uses port 53 (DNS) |\n| `portainer` | 9443 | Docker management GUI | ⚠️ Mounts Docker socket (HTTPS) |\n| `nginx-proxy-manager` | 81 | Reverse proxy with SSL and web UI | ⚠️ Uses ports 80/443 |\n\n### App-specific options\n\n```bash\n# Jellyfin: mount your media library\nhomebutler install jellyfin --media /mnt/movies\n\n# Pi-hole / AdGuard: DNS ad blocking (port 53 required)\nhomebutler install pi-hole\n# ⚠️ If port 53 is in use (Linux): sudo systemctl disable --now systemd-resolved\n\n# Portainer: Docker GUI (mounts docker socket)\nhomebutler install portainer\n# Access via HTTPS: https://localhost:9443\n\n# Nginx Proxy Manager: reverse proxy\nhomebutler install nginx-proxy-manager\n# Default login: admin@example.com / changeme (change immediately!)\n\n# Any app: custom port\nhomebutler install <app> --port 9999\n```\n\n### Safety checks\n\n- **Port conflict detection** — Checks if the port is already in use before install\n- **DNS mutual exclusion** — Warns if pi-hole and adguard-home are both installed\n- **Docker socket warning** — Alerts when an app requires Docker socket access (portainer)\n- **OS-specific guidance** — Linux gets systemd-resolved fix, macOS gets lsof command\n- **Post-install tips** — DNS setup, HTTPS access, default credential warnings\n\n> Want more apps? [Open an issue](https://github.com/Higangssh/homebutler/issues) or see [Contributing](CONTRIBUTING.md).\n\n## Usage\n\n```\nhomebutler <command> [flags]\n\nCommands:\n  status              System status (CPU, memory, disk, uptime)\n  doctor              Diagnose health, exposure, backups, and readiness\n  config validate     Check the config file and report what is ignored\n  docker list         List running containers\n  install <app>       Install a self-hosted app (docker compose)\n  alerts              Show current alert status\n  watch tui           TUI dashboard (monitors all configured servers)\n  watch add/list/remove  Manage watched containers\n  watch check/start   One-shot or continuous restart detection\n  watch history/show  Browse restart history\n  proxmox status      Proxmox VE cluster, nodes, guests, and storage\n  serve               Web dashboard (browser-based, go:embed)\n\nFlags:\n  --json              JSON output (default: human-readable)\n  --verbose, -v       Show detailed error information\n  --server <name>     Run on a specific remote server\n  --all               Run on all configured servers in parallel\n  --port <number>     Port for serve command (default: 8080)\n  --config <path>     Config file (auto-detected, see Configuration)\n```\n\nRun `homebutler --help` for all commands.\n\n<details>\n<summary>📋 All Commands & Flags</summary>\n\n```\nCommands:\n  init                Interactive setup wizard\n  config validate     Check the config file and report what is ignored\n  status              System status (CPU, memory, disk, uptime)\n  doctor              Diagnose health, exposure, backups, and readiness\n  watch tui           TUI dashboard (monitors all configured servers)\n  watch add <name>    Add container to restart watch list\n  watch list          Show watched containers\n  watch remove <name> Remove container from watch list\n  watch check         One-shot restart check\n  watch start         Continuous monitoring: restarts, thresholds, rules\n  watch install       Register watch with systemd or launchd\n  watch installed     Report whether it is registered\n  watch uninstall     Remove the service unit\n  watch history       List restart history (alias: incidents)\n  watch show <id>     Show restart details with logs\n  serve               Web dashboard (browser-based, go:embed)\n  docker list         List running containers\n  docker restart <n>  Restart a container\n  docker stop <n>     Stop a container\n  docker logs <n>     Show container logs\n  docker top <n>      Show processes running inside a container\n  docker inspect <n>  Show image, state, ports, mounts, networks, health\n  report              What changed since the last snapshot\n  inventory scan      Map containers, ports, and topology\n  inventory show      Same as scan (--filter exposed narrows it)\n  inventory export    Export the map (--format mermaid)\n  proxmox status      Proxmox VE cluster, nodes, guests, storage\n  proxmox guests      List QEMU and LXC guests\n  proxmox node <n>    Node detail\n  proxmox guest ...   start / shutdown / reboot (needs --confirm)\n  proxmox task <upid> Task status for an action already submitted\n  proxmox tasks       Recent tasks on a node\n  proxmox script      Community Script install commands (prints, never runs)\n  notify test         Send a test notification through configured providers\n  wake <name>         Send Wake-on-LAN packet\n  ports               List open ports with process info\n  ps                  Show top processes (alias: processes)\n  ps --sort mem       Sort by memory instead of CPU\n  ps --limit 20       Show top 20 (default: 10, 0 = all)\n  network scan        Discover devices on LAN\n  alerts              Show current alert status\n  alerts --watch      Thresholds only (watch start covers these too)\n  trust <server>      Register SSH host key (TOFU)\n  backup              Backup Docker volumes, compose files, and env\n  backup list         List existing backups\n  backup drill <app>  Verify backup restores correctly (isolated)\n  backup drill --all  Verify all apps in backup\n  restore <archive>   Restore from a backup archive\n  upgrade             Upgrade local + all remote servers to latest\n  deploy              Install homebutler on remote servers\n  install <app>       Install a self-hosted app (docker compose)\n  install list        List available apps\n  install status <a>  Check installed app status\n  install uninstall   Stop app (keep data)\n  install purge       Stop app + delete all data\n  mcp                 Start MCP server (JSON-RPC over stdio)\n  version             Print version\n\nFlags:\n  --json              JSON output (default: human-readable)\n  --verbose, -v       Show detailed error information\n  --server <name>     Run on a specific remote server\n  --all               Run on all configured servers in parallel\n  --port <number>     Port for serve command (default: 8080)\n  --demo              Run serve with realistic demo data\n  --watch             Continuous monitoring mode (alerts command)\n  --interval <dur>    Watch interval, e.g. 30s, 1m (default: 30s)\n  --config <path>     Config file (auto-detected, see Configuration)\n  --local             Upgrade only the local binary (skip remote servers)\n  --local <path>      Use local binary for deploy (air-gapped)\n  --service <name>    Target a specific Docker service (backup/restore)\n  --allow-bind <path> Host path a restore may write a bind mount to (repeatable)\n  --endpoint <name>   Proxmox endpoint from config (optional if only one)\n  --confirm           Required for a Proxmox guest power action\n  --to <path>         Custom backup destination directory\n  --archive <path>    Specific backup archive for drill\n  --all               Verify all supported apps (backup drill)\n```\n\n</details>\n\n<details>\n<summary>🌐 Web Dashboard</summary>\n\n`homebutler serve` starts an embedded web dashboard — no Node.js, no Docker, no extra dependencies.\n\n```bash\nhomebutler serve                # http://localhost:8080\nhomebutler serve --port 3000    # custom port\nhomebutler serve --demo         # demo mode with sample data\n```\n\n📖 **[Web dashboard details →](docs/web-dashboard.md)**\n\n</details>\n\n## Backup & Restore\n\nOne-command Docker backup — volumes, compose files, and env variables.\n\n```bash\nhomebutler backup                          # backup everything\nhomebutler backup --service jellyfin       # specific service\nhomebutler backup --to /mnt/nas/backups/   # custom destination\nhomebutler backup list                     # list backups\nhomebutler restore ./backup.tar.gz         # restore\n```\n\n> ⚠️ Database services should be paused before backup for data consistency.\n\n📖 **[Full backup documentation →](docs/backup.md)** — how it works, archive structure, security notes.\n\n### Alert Thresholds (Advanced)\n\n`alerts` still exists for CPU, memory, and disk threshold checks, but it is an advanced flow and not the recommended first step for new users.\n\n```bash\nhomebutler alerts --watch                  # default: 30s interval\nhomebutler alerts --watch --interval 10s   # check every 10 seconds\nhomebutler alerts history                  # view alert history\nhomebutler notify test                     # test your notification channels\n```\n\nDefault thresholds: CPU 90%, Memory 85%, Disk 90%. Start with `watch`, then add `alerts` only if you specifically want threshold-based checks.\n\n### 🔍 Backup Drill\n\n**\"Having a backup\" and \"being able to restore\" are different things.**\n\nBackup Drill boots your backup in an isolated Docker environment and verifies the app actually responds — like a fire drill for your data.\n\n```bash\nhomebutler backup drill uptime-kuma        # verify one app\nhomebutler backup drill --all              # verify all apps\nhomebutler backup drill --json             # machine-readable output\nhomebutler backup drill --archive ./file   # use a specific backup\n```\n\n**What happens:**\n1. Finds the latest backup archive\n2. Verifies archive integrity (`tar` validation)\n3. Creates an isolated Docker network + random port\n4. Boots the app from backup data\n5. Runs an HTTP health check\n6. Reports pass/fail and cleans up everything\n\n```\n🔍 Backup Drill — uptime-kuma\n\n  📦 Backup: ~/.homebutler/backups/backup_2026-04-04_1711.tar.gz\n  📏 Size: 18.6 MB\n  🔐 Integrity: ✅ tar valid (8 files)\n\n  🚀 Boot: ✅ container started in 0s\n  🌐 Health: ✅ HTTP 200 on port 58574\n  ⏱️  Total: 2s\n\n  ✅ DRILL PASSED\n```\n\n**Zero risk** — runs in a completely isolated environment. Your running services are never touched.\n\nSupports health checks for: `nginx-proxy-manager`, `vaultwarden`, `uptime-kuma`, `pi-hole`, `gitea`, `jellyfin`, `plex`, `portainer`, `homepage`, `adguard-home`.\n\n## Configuration\n\n```bash\nhomebutler init    # interactive setup wizard\n```\n\n📖 **[What `report` compares →](docs/report.md)** — what earns a line, what is deliberately suppressed, and why.\n\n📖 **[Configuration details →](docs/configuration.md)** — config file locations, watch/notify options, and advanced alert thresholds.\n\n## Multi-server\n\nManage multiple servers from a single machine over SSH.\n\n```bash\nhomebutler status --server rpi     # query specific server\nhomebutler status --all            # query all in parallel\nhomebutler deploy --server rpi     # install on remote server\nhomebutler upgrade                 # upgrade all servers\n```\n\n📖 **[Multi-server setup →](docs/multi-server.md)** — SSH auth, config examples, deploy & upgrade.\n\n## MCP Server\n\nBuilt-in [MCP](https://modelcontextprotocol.io/) server — manage your homelab from any AI tool with natural language.\n\n```json\n{\n  \"mcpServers\": {\n    \"homebutler\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"homebutler@latest\"]\n    }\n  }\n}\n```\n\nWorks with Claude Desktop, ChatGPT, Cursor, Windsurf, and any MCP client.\n\n📖 **[MCP server setup →](docs/mcp-server.md)** — supported clients, available tools, agent skills.\n\n## Installation\n\n### Homebrew (Recommended)\n\n```bash\nbrew install Higangssh/homebutler/homebutler\n```\n\nAutomatically installs to PATH. Works on macOS and Linux.\n\n### One-line Install\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/Higangssh/homebutler/main/install.sh | sh\n```\n\nAuto-detects OS/architecture, downloads the latest release, and installs to PATH.\n\n### npm (MCP server)\n\n```bash\nnpm install -g homebutler\n```\n\nDownloads the Go binary automatically. Use `npx -y homebutler@latest` to run without installing globally.\n\n### Go Install\n\n```bash\ngo install github.com/Higangssh/homebutler@latest\n```\n\n### Build from Source\n\n```bash\ngit clone https://github.com/Higangssh/homebutler.git\ncd homebutler\nmake build-all\n```\n\n`make build-all` compiles the web dashboard into the binary and needs Node\ninstalled. `make build` skips it — the CLI is complete either way, and\n`homebutler serve` then says the dashboard is missing and names the two ways\nto get it.\n\n## Uninstall\n\n```bash\nrm $(which homebutler)           # Remove binary\nrm -rf ~/.config/homebutler      # Remove config (optional)\n```\n\n## Architecture\n\n> **Goal: Engineers manage servers from chat — not SSH.**\n>\n> Alert fires → AI diagnoses → AI fixes → you get a summary on your phone.\n\nhomebutler is the **tool layer** in an AI ChatOps stack. It doesn't care what's above it — use any chat platform, any AI agent, or just your terminal.\n\n```\n┌──────────────────────────────────────────────────┐\n│  Layer 3 — Chat Interface                        │\n│  Telegram · Slack · Discord · Terminal · Browser │\n│  (Your choice — homebutler doesn't touch this)   │\n└──────────────────────┬───────────────────────────┘\n                       │\n┌──────────────────────▼───────────────────────────┐\n│  Layer 2 — AI Agent                              │\n│  OpenClaw · LangChain · n8n · Claude Desktop     │\n│  (Understands intent → calls the right tool)     │\n└──────────────────────┬───────────────────────────┘\n                       │  CLI exec or MCP (stdio)\n┌──────────────────────▼───────────────────────────┐\n│  Layer 1 — Tool (homebutler)       ← YOU ARE HERE │\n│                                                   │\n│  ┌─────────┐  ┌─────────┐  ┌─────────┐           │\n│  │   CLI   │  │   MCP   │  │   Web   │           │\n│  │ stdout  │  │  stdio  │  │  :8080  │           │\n│  └────┬────┘  └────┬────┘  └────┬────┘           │\n│       └────────────┼────────────┘                 │\n│                    ▼                              │\n│             internal/*                            │\n│   system · docker · ports · network               │\n│   wake · alerts · remote (SSH)                    │\n└───────────────────────────────────────────────────┘\n```\n\n**Three interfaces, one core:**\n\n| Interface | Transport | Use case |\n|-----------|-----------|----------|\n| **CLI** | Shell stdout/stderr | Terminal, scripts, AI agents via `exec` |\n| **MCP** | JSON-RPC over stdio | Claude Desktop, ChatGPT, Cursor, any MCP client |\n| **Web** | HTTP (`go:embed`) | Browser dashboard, on-demand with `homebutler serve` |\n\nAll three call the same `internal/` packages — no code duplication.\n\n**homebutler is Layer 1.** Swap Layer 2 and 3 to fit your stack:\n\n- **Terminal only** → `homebutler status` (no agent needed)\n- **Claude Desktop** → MCP server, Claude calls tools directly\n- **OpenClaw + Telegram** → Agent runs CLI commands from chat\n- **Custom Python bot** → `subprocess.run([\"homebutler\", \"status\", \"--json\"])`\n- **n8n / Dify** → Execute node calling homebutler CLI\n\n**No ports opened by default.** CLI and MCP use stdin/stdout only. The web dashboard is opt-in (`homebutler serve`, binds `127.0.0.1`).\n\n**Now:** CLI + MCP + Web dashboard — you ask, it answers.\n\n**Goal:** Full AI ChatOps — infrastructure that manages itself.\n\n\n\n## Contributing\n\nContributions welcome! Please open an issue first to discuss what you'd like to change.\n[CONTRIBUTING.md](CONTRIBUTING.md) covers what homebutler accepts and what a new\ntarget has to prove.\n\n## Security\n\nFound a vulnerability? Report it privately through\n[the Security tab](https://github.com/Higangssh/homebutler/security/advisories/new)\nrather than a public issue. [SECURITY.md](SECURITY.md) covers what is in scope\nand what to expect.\n\n## License\n\n[MIT](LICENSE)\n",
  "bytes": 40938,
  "sha": "a12365bb60f662f602a06e03efe2ffd2fdc0f1c7da6bb9f45986d046bffdd69a",
  "repo_slug": "higangssh/homebutler",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_higangssh_homebutler_a483c424/readme"
}