Skip to content
crypdickPublic

About

Reusable IaC across hosts and repos

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

cfg

cfg applies host and repository configuration from a separate personalization repository.

The tool owns configuration loading, validation, dependency resolution, planning, safe filesystem changes, and host orchestration. Personal inventory, payloads, and trusted deploy files stay outside this repository.

Install

Until a package is published, install directly from a Git checkout:

uv tool install /path/to/cfg

For tool development:

uv sync --group test
uv run pytest
uv tool install --editable .

Personalization repository

By convention, personal configuration lives at ~/.cfg:

~/.cfg/
  .cfg-root
  hosts/
  repos/
  features/
    host/
    repo/

See examples/personalization for a minimal synthetic configuration.

cfg resolves the personalization root in this order:

  1. CFG_ROOT;
  2. the path stored in $XDG_CONFIG_HOME/cfg/root;
  3. the nearest parent containing .cfg-root;
  4. ~/.cfg.

Use

cfg host current
cfg host settings
cfg host managed
cfg host apply --dry-run
cfg host apply -y
cfg host upgrade --dry-run

cfg repo settings
cfg repo apply --dry-run

cfg validate

Host operations use pyinfra. Repo operations build and execute a deterministic local filesystem plan. Private deploy.py files are trusted Python extensions and run with the user's privileges. cfg host apply applies managed home files and feature deploys; cfg host upgrade separately refreshes package metadata and upgrades installed packages. Host apply compares the installed cfg version with main's pyproject.toml on GitHub, including during --dry-run. If versions differ or the check cannot run, apply stops before changing the host. Run uv tool upgrade cfg, then retry. If cfg was installed from a local checkout, update that checkout before upgrading. Before live host apply, cfg requires a clean personalization Git checkout with a remote upstream. It fetches that upstream, fast-forwards when behind, tests a divergent rebase in a temporary worktree before rebasing locally, and pushes local commits. If the checkout is dirty or the rebase conflicts, apply stops with a fix hint. --dry-run checks local Git state but does not fetch, rebase, or push, so its remote status may be stale. Interactive host applies validate sudo credentials before making changes, so native sudo can reprompt after a mistyped password. Noninteractive applies keep existing askpass behavior.

Repo apply records minimal ownership evidence in .cfg/state.json; host apply records the same evidence in $XDG_CONFIG_HOME/cfg/state.json. When configuration stops managing a mirror, generated file, or overlay, cfg removes the stale output only if it still matches that evidence; user-modified replacements fail safely. Host state is written only after pyinfra succeeds and cfg verifies actual declared outputs.

cfg validate parses and resolves the complete personalization repository without writing to hosts, repositories, or the configuration root.

Managed-path safety

Managed repo outputs cannot target .git components or the root .cfg directory. Mirror plans capture bytes and permissions before applying; later source edits do not change the plan. Stale overlays are removed only when their target still matches recorded ownership. Links without recorded ownership are left untouched.

Host feature generated paths name files created by that feature's deploy.py. Successful host apply verifies those files and records their digests. This makes platform-selected or tool-generated host configuration part of normal ownership cleanup without forcing its bytes into an overlay.

Documentation

About

Reusable IaC across hosts and repos

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages