Files
a13labs.infra/AGENTS.md

4.3 KiB

AGENTS.md - A13Labs Infrastructure

Repo Structure

  • ansible/ — Playbooks, roles, inventory. Runs against bare-metal servers.
  • terraform/ — IaC (OpenTofu for K8s app deployments + cloud provisioning).
  • inventory/hosts — Ansible inventory. All hosts and groups.
  • requirements/ — pip requirements files: ansible.txt, dev.txt, opentofu.txt.
  • sectool — Secret manager (Bitwarden, configured in sectool.json). Both root and ansible/ have their own sectool.json + sectool.env.

Key Facts

  • No Makefile, no justfile, no pre-commit config. Commands are run directly.
  • All GitHub workflows are .disabled — CI is not active. Verification is local-only.
  • ansible/ansible.cfg points to ../inventory/hosts (relative to ansible/ dir). Always run playbooks from the ansible/ directory, or use -i to override.
  • YAML linting: ansible-lint config at ansible/.ansible-lint. .yamllint.yml at ansible/.yamllint.yml (120 char line warning).
  • No .pre-commit-config.yaml exists — linting is manual or CI-only.

Ansible

Required Environment vars

export ANSIBLE_USER=provision 
export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES # if on a MAC

Running playbooks

cd ansible
sectool exec ansible-playbook -u $ANSIBLE_USER  playbook_<name>.yml

Role testing (Molecule + Podman - Linux Only)

cd ansible/roles/<role_name>
molecule test          # create -> converge -> verify -> destroy
molecule converge       # run converge only
molecule destroy        # clean up

Molecule gotchas:

  • Always run molecule commands from the role directory, not from repo root.
  • Molecule containers use podman driver. No systemd by default — guard service tasks with when: ansible_service_mgr == "systemd".
  • molecule/default/prepare.yml must install python3 and sudo via raw: before Ansible can run Python modules.
  • provisioner.env.ANSIBLE_ROLES_PATH should point up to the parent (e.g., ../../../).

Ansible-lint

ansible-lint  # runs from repo root or ansible/

Excluded paths: .git/, .github/, tests/. Warns on: line-length, yaml[line-length], var-naming[no-role-prefix].

Terraform / OpenTofu

App deployments (K8s)

  • terraform/apps/dev-01/ — dev Kubernetes cluster (microk8s)
  • terraform/apps/prod-01/ — prod Kubernetes cluster (microk8s)
  • Uses Kubernetes + TLS providers. provider.tf sets insecure = true.

Cloud IaC

  • terraform/iac/aws/ — AWS infrastructure
  • terraform/iac/contabo/ — Contabo VPS
  • terraform/iac/cloudns/ — DNS (cloudns)
  • terraform/iac/scaleway/ — Scaleway infrastructure

Secrets

Each terraform directory has its own sectool.env. Run sectool to load secrets before tofu init/plan/apply:

sectool env -d terraform/apps/dev-01/ -- tofu plan

Module structure

  • terraform/modules/apps/ — application modules (Nextcloud, etc.)
  • terraform/modules/db/ — database modules (MariaDB with backups)
  • terraform/modules/utils/ — utilities (exporters, cert-checker, prometheus, trivy, etc.)

Scripts (scripts/)

One-off utility scripts — not library code:

  • install-opnsense.sh — boots OPNsense on a VM via virt-install (one-time router setup)
  • chronograf.shkubectl port-forward wrapper for Chronograf pod
  • proxy-pt.shkubectl port-forward wrapper for m3uproxy pod
  • steamos — launches SteamOS gaming session with sunshine
  • cpu_power_monitor.py — RAPL power monitoring (requires root)

Environment Setup

# Ansible + dev tools
pip install -r requirements/ansible.txt -r requirements/dev.txt

# Terraform/OpenTofu deps
pip install -r requirements/opentofu.txt

Contabo CLI

sectool exec cntb get instances --oauth2-clientid="$CONTABO_CLIENT_ID" ...

Windows hosts

  • Use ConfigureRemotingForAnsible.ps1 in scripts/ to enable WinRM on Windows targets.
  • On MSYS2: install packages listed in Readme.MD (go, python, cryptography, paramiko, rpds-py, etc.).
  • Python venv: python -m venv .venv --system-site-packages

Style Conventions

  • YAML: 120 char line length (warning threshold)
  • Ansible roles follow galaxy conventions: defaults/, tasks/, meta/, files/, templates/
  • tasks/main.yml is the entrypoint for every role
  • Host vars: ansible/host_vars/<hostname>.yml