# AutoBott — Agent Guide Ansible playbooks to manage self-hosted services on Debian servers (and basic Debian desktops). ## Project Overview AutoBott automates the installation and configuration of a full self-hosted stack on Debian: - Base system hardening, ZFS, VPN (WireGuard/Tailscale), backup (Borg/Borgmatic) - Web stack: Caddy, PHP-FPM, Authelia, MariaDB - Monitoring: Prometheus, Grafana, Alertmanager, Monit - Media/Servarr: Jellyfin, Kavita, Sonarr, Radarr, etc. - Productivity: Immich, Docmost, MediaWiki, Homepage - Desktop: KDE, developer tools, desktop apps ## Documentation Full project documentation lives in a **separate `docs` repository**, available two ways: - **Online:** https://ansible-autobott.github.io/docs/ - **Locally:** a colocated sibling directory next to this repo — `../docs` (on this machine: `/home/bott/.datos/edit/programacion/autobott/docs`). It is a Hugo site; the Markdown sources live under `../docs/content/docs/`, grouped into `Getting Started/`, `Guides/`, and `roles/`. Prefer the local copy when it is present (it may be ahead of the published site); otherwise use the online version. ## Development Setup ```bash make prepare # Create venv + install ansible==11.6.0 and deps source venv/bin/activate ``` ## Common Commands ```bash # Lint (strict) — CI (.github/workflows/lint.yml) runs `make lint` on every PR make lint make lint-fix # review the diff: the fixer can reflow Jinja/long lines # Run playbook against real inventory make run INV=../inventory/main.yaml HOST=myhost TAG=role_docker make run-verbose INV=../inventory/main.yaml TAG=role_caddy # Enroll a new host make enroll INV=../inventory/main.yaml HOST=myhost ANSIBLE_USER=root # Vagrant testing (Debian 13 VMs; Debian 14 placeholder) make vagrant-up make vagrant-run TAG=role_docker # Test a specific role make vagrant-test # Run validation tests (test.yaml) make vagrant-destroy # Secrets make encrypt INV=../inventory/main.yaml KEY=mariadb_root_pass VALUE=s3cr3t make decrypt INV=../inventory/main.yaml # Release (clean git, on main branch) # First bump autobot_version in roles/base/enroll/defaults/main.yaml, then tag. # Pushing the tag triggers .github/workflows/release.yml, which publishes the # GitHub release (with auto-generated notes). make tag version=v0.2.0 ``` ## Before Opening a PR Review whether the change should ship as a release. If it should, bump `autobot_version` in `roles/base/enroll/defaults/main.yaml` **before** opening the PR, so the version bump is part of the reviewed diff. Tagging later (`make tag`) triggers `.github/workflows/release.yml`, so the version file must already reflect the intended release by the time the PR is merged. ## Architecture ### Playbook Structure `autobott.yaml` has 4 plays: 1. **All hosts** — base, base-services, security foundation 2. **linux_servers** — web-base, monitoring, servarr, webservices 3. **linux_desktop** — KDE, gui-apps, cli-apps, dev-* toolchains 4. **post-setup** — finalization, version write ### Role Organization ``` roles/ base/ # preconditions, enroll, linux-apt, linux-basic, zfs, nullmailer, smartd, hdparm base-services/ # wireguard, tailscale, docker, samba, mariadb, borg, borgmatic, goback security/ # lynis, malwarescan, crowdsec, firewall web-base/ # php-fpm, caddy, authelia, vhosts monitoring/ # prometheus, alertmanager, node_exporter, grafana, monit webservices/ # homepage, docmost, mediawiki, immich, mealie, etnafinance, radicale, fe26, phpmyadmin servarr/ # jellyfin, kavita, transmission, sonarr, radarr, prowlarr, lidarr, whisparr, romm, stash, xbvr desktop/ # linux-desktop, linux-kde, vbox-guest, gui-apps, cli-apps, dev-node, dev-go, dev-java, dev-k8s, dev-ai, dev-generic games/ # minecraft k8s/ # k3s validation/ # test roles ``` > The desktop app catalogue is split across several roles, each following the > same pattern (a `_config` selection mapping validated against a > `_available` list; per-app tasks in `tasks/apps/.yaml`; per-app > defaults in `defaults/main.yaml`): > - **`desktop/gui-apps`** — GUI apps (via `gui_apps_config`) > - **`desktop/cli-apps`** — general CLI utilities: ytdlp, linux-candy, dibs, > todo (via `cli_apps_config`) > - **`desktop/dev-node`** — Node.js toolchain (via `dev_node_config`) > - **`desktop/dev-go`** — Go toolchain + go-deps-view (via `dev_go_config`) > - **`desktop/dev-java`** — jenv + maven (via `dev_java_config`) > - **`desktop/dev-k8s`** — kubectl + k9s (via `dev_k8s_config`) > - **`desktop/dev-ai`** — AI coding agents: herdr, claude-code, pi, > copilot-cli (via `dev_ai_config`) > - **`desktop/dev-generic`** — other dev tools: vagrant, vault, github-cli > (via `dev_generic_config`) > > The candy-tools shared apt repo is used by both `cli-apps` (dibs, linux-candy, > todo) and `dev-go` (go-deps-view); each role adds it idempotently. ### Role Conventions Every role follows this layout: ``` roles/// defaults/main.yaml # All variables; always includes run_role_: true tasks/main.yaml # All tasks wrapped in block: with when: run_role_ guard handlers/main.yaml # Handlers (if needed) templates/ # Jinja2 templates (.j2) meta/main.yaml # Role metadata (if needed) ``` Some roles include an `About.md` file with detailed architecture decisions and technical context. Always check for this file when working on a role. Key rules: - Every role has a boolean `run_role_: true` in defaults — this is how per-host opt-out works - Tasks always use `block:` with `tags: [role_]` and `when: run_role_` - Use `ansible.builtin.*` fully-qualified module names - Variables follow `_` pattern (e.g. `wireguard_port`, `mariadb_root_pass`) - Sensitive defaults (passwords, keys) use empty string `""` — must be overridden in inventory - User-configurable dicts: define `_defaults` in defaults/, merge with inventory dict via `combine(recursive=True)` ### Inventory Structure Per-host config lives in `inventory/host_vars//` with files grouped by category (base.yaml, webservices.yaml, etc.). Secrets are SOPS-encrypted `secrets.sops.yaml` files, decrypted at runtime by the `community.sops` vars plugin; the age private key lives at `/sops_key` (never commit a real key). ## Adding a New Role 1. Create `roles///defaults/main.yaml` and `tasks/main.yaml` 2. In defaults: define `run_role_: true` and all variables 3. In tasks: wrap all tasks in `block:` guarded by `when: run_role_` with `tags: [role_]` 4. Add the role to the correct play in `autobott.yaml` 5. Test: `make vagrant-run TAG=role_` 6. Lint: `make lint` ## Key Files | File | Purpose | |------|---------| | `autobott.yaml` | Main playbook — add new roles here | | `roles/base/enroll/defaults/main.yaml` | Contains `autobot_version` — bump before release | | `Makefile` | All commands — read before running anything | | `inventory/vagrant.yaml` | Vagrant test inventory | | `.sops.yaml` | SOPS creation rules — which age keys encrypt which files; edit secrets via `make edit-secrets` | | `CLAUDE.md` | Symlink to `AGENTS.md` — Claude Code reads the same guide | | `../docs/content/docs/` | Full documentation sources (see [Documentation](#documentation)) |