Initial commit: autonomous maintenance agent for semprini stack

systemd-deployed daemon that drives the semprini-core stack-support agent
headless via Claude Code, monitors health via Uptime Kuma, applies safe
upgrades, and escalates to the operator over Matrix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-21 17:20:06 +12:00
co-authored by Claude Opus 4.8
commit e91b129841
9 changed files with 1090 additions and 0 deletions
Executable
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env bash
# install.sh — install & enable the semprini-maintainer systemd service.
#
# Run from this directory. Requires sudo for the systemd parts.
set -euo pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
UNIT="semprini-maintainer.service"
DEST="/etc/systemd/system/$UNIT"
echo "→ Pre-flight checks"
command -v docker >/dev/null || { echo "ERROR: docker not found"; exit 1; }
command -v python3 >/dev/null || { echo "ERROR: python3 not found"; exit 1; }
CLAUDE_BIN="$(python3 -c "import json;print(json.load(open('$DIR/config.json'))['claude_bin'])" 2>/dev/null || echo /home/paul/.local/bin/claude)"
[ -x "$CLAUDE_BIN" ] || echo "WARN: claude binary not executable at $CLAUDE_BIN"
if [ ! -f "$DIR/config.json" ]; then
echo "ERROR: config.json missing. Run:"
echo " cp $DIR/config.example.json $DIR/config.json"
echo " $DIR/register-matrix-bot.sh"
exit 1
fi
TOKEN="$(python3 -c "import json;print(json.load(open('$DIR/config.json'))['matrix']['access_token'])")"
case "$TOKEN" in
""|FILLED_BY_*) echo "ERROR: Matrix not provisioned. Run register-matrix-bot.sh first."; exit 1;;
esac
echo "→ Syntax-checking maintainer.py"
python3 -m py_compile "$DIR/maintainer.py"
echo "→ Installing $UNIT"
sudo cp "$DIR/$UNIT" "$DEST"
sudo systemctl daemon-reload
sudo systemctl enable "$UNIT"
sudo systemctl restart "$UNIT"
echo
echo "✓ Installed and started."
echo " Logs: journalctl -u $UNIT -f"
echo " Status: systemctl status $UNIT"
echo " Stop: sudo systemctl stop $UNIT"