--- title: "Documentation" html_title: "Enroll Documentation" description: "Current user documentation for Enroll harvest, manifest, diff, explain, validate, SOPS, remote mode, and Ansible output." ---
Documentation

Current Enroll behavior

This page describes how the 0.7 beta CLI works today: what it captures, how it renders Ansible, and where the trust boundaries are.

Mental model

Enroll has two main phases:

  1. Harvest collects host facts and selected files into a harvest bundle containing state.json and artifacts/.
  2. Manifest converts that bundle into Ansible configuration-management output.

Additional commands help you compare harvests (diff), explain why things were included or skipped (explain), and validate bundle structure (validate).

enroll harvest

Harvest writes a local bundle. If --out is omitted, Enroll creates a private randomized cache directory under the user’s Enroll cache. If --out is supplied for plaintext output, the final output directory must be new and safe; Enroll creates it with private permissions.

High-level capture scope

  • Manual packages and installed package inventory
  • Enabled systemd services and relevant package ownership
  • Modified package-owned config where the backend can prove drift
  • Service-relevant unowned files under matching /etc trees
  • Central cron and logrotate snippets
  • Non-system users and SSH public/authorized key material
  • Package-manager config: apt_config or dnf_config
  • Miscellaneous /etc and /usr/local custom files
  • Runtime sysctl and firewall fallback state where appropriate
  • Flatpak, Snap, Docker, and Podman image evidence

Path selection

--include-path adds extra files or directories to the extra_paths role. --exclude-path removes matching paths from all harvesting, including defaults. Excludes win over includes.

enroll harvest --out ./harvest \
  --include-path '/home/*/.profile' \
  --exclude-path '/home/*/.ssh/**' \
  --exclude-path 're:^/var/cache/myapp/.*$'

Pattern styles are plain paths, inferred or explicit globs such as glob:/path/**/*.conf, and regexes prefixed with re: or regex:. Include expansion ignores symlinks, respects caps, and reports unmatched/capped paths as notes.

Remote harvesting

Remote mode runs the harvest over SSH and stores the bundle locally. The remote host does not need Enroll installed in the same way you would for local operation.

enroll harvest --remote-host app01.example.net --remote-user mig --out ./harvest-app01
  • --remote-ssh-config [path] reads OpenSSH-style settings. With no value, it defaults to ~/.ssh/config.
  • Supported ssh config fields include HostName, User, Port, IdentityFile, ProxyCommand, and HostKeyAlias where supported.
  • -K / --ask-become-pass prompts for remote sudo. --no-sudo avoids sudo and produces a more limited harvest.
  • --ask-key-passphrase prompts for an encrypted SSH key. --ssh-key-passphrase-env ENV_VAR reads it from an environment variable for CI.

enroll manifest

Manifest validates the harvest, freezes directory bundles into a private temporary copy, prints the semantic-safety warning, and writes Ansible output.

enroll validate ./harvest
enroll manifest --harvest ./harvest --out ./ansible
cd ./ansible
ansible-galaxy collection install -r requirements.yml
ansible-playbook -i localhost, -c local playbook.yml --check --diff

Output contents

  • playbook.yml in single-site mode, or playbooks/<fqdn>.yml plus inventory in multi-site mode.
  • roles/<role>/tasks/main.yml, with handlers where needed.
  • Harvested files in role files/, generated templates in role templates/, and variables in defaults/main.yml or host vars.
  • requirements.yml for Ansible collections such as container/Flatpak/Snap support when required.
  • A generated README.md summarising layout, roles, excluded paths, notes, and dry-run commands.

Every generated role has a tag named role_<role_name>. Use tags to dry-run or apply a narrow slice, for example --tags role_users,role_services.

Output modes

Single-site: default

Use this for one server or a “golden” role set. Roles are more self-contained; files live under the role; variables live in role defaults.

Multi-site: --fqdn

Use this for several existing servers. Generic shared roles read host-specific variables and per-host files under inventory/host_vars/<fqdn>.

By default, Enroll groups many package and systemd-unit roles into common Debian Section/RPM Group roles. --no-common-roles preserves one generated role per package/unit. --fqdn implies this behavior to avoid cross-host coupling.

SOPS encrypted bundles

--sops <GPG_FINGERPRINT...> writes a single encrypted binary tarball instead of a plaintext directory. This is storage-at-rest encryption for harvest/manifest bundles, not an Ansible inventory-vault workflow.

enroll harvest --out ./harvest --dangerous --sops 54A91143AE0AB4F7743B01FE888ED1B423A3BC99
enroll manifest --harvest ./harvest/harvest.tar.gz.sops \
  --out ./ansible-secure --sops 54A91143AE0AB4F7743B01FE888ED1B423A3BC99
cd ./ansible-secure
sops -d manifest.tar.gz.sops | tar -xzvf -
cd manifest

When manifest output is encrypted, decrypt and extract it before running ansible-playbook.

enroll diff

Diff compares two harvests and reports package, service, user, and managed-file drift. Inputs may be directories, state.json paths, tarballs, or SOPS bundles when --sops is set.

enroll diff --old ./harvest-a --new ./harvest-b --format markdown \
  --ignore-package-versions --exclude-path /var/anacron --exit-code

Notification options include --webhook, --webhook-format json|text|markdown, repeated --webhook-header 'K: V', repeated --email-to, SMTP settings, and --notify-always.

--exit-code returns status 2 when differences are detected, which is useful for cron, CI, or monitoring wrappers.

Explain and validate

enroll explain

Summarises inventory, roles, included reasons, excluded reasons, and examples. Supports --format text|json, --max-examples, tarballs, directories, state.json, and SOPS bundles.

enroll explain ./harvest --format json --max-examples 20

enroll validate

Checks JSON validity, schema compliance, missing referenced artifacts, and orphaned artifact files. Supports --schema, --allow-remote-schema, --no-schema, --fail-on-warnings, JSON output, and report files.

enroll validate ./harvest --format json --out validate.json

Configuration file

Enroll can read INI-style defaults from an explicit --config path, ENROLL_CONFIG, $XDG_CONFIG_HOME/enroll/enroll.ini, or ~/.config/enroll/enroll.ini. It no longer reads .enroll.ini from the current working directory.

Precedence is: explicit CLI flags, subcommand/global INI defaults, then argparse defaults. Use underscores for INI keys that are hyphenated on the CLI.

[harvest]
include_path =
  /home/*/.bashrc
  /home/*/.profile
exclude_path = /usr/local/bin/docker-*, /usr/local/bin/some-tool

[manifest]
no_jinjaturtle = true

[diff]
exclude_path = /var/anacron
ignore_package_versions = true

Install

Enroll requires Python 3.10 or newer. The project’s README documents Debian/Ubuntu and Fedora repositories, AppImage, pip/pipx, and Poetry development installs.

pip / pipx
pip install enroll
# or
pipx install enroll
development checkout
poetry install
poetry run enroll --help

For a beta release, your package manager may require an explicit pre-release opt-in depending on how you install and what stable version is already available.