# aconfmgr tracks an Arch system by diffing it into shell scripts

> A single shell script that transcribes an Arch Linux system's packages and /etc changes into reviewable.sh files, then replays them elsewhere. Evaluation compiles the configuration into an output directory, and apply previews actual system changes.

**CyberShadow/aconfmgr** — A configuration manager for Arch Linux

- Repository: https://github.com/CyberShadow/aconfmgr
- Stars: 1,683 · Forks: 50
- Language: Shell
- License: not declared
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/cybershadow-aconfmgr

## Two subcommands, and the diff is always shown first

The whole interface is two verbs. aconfmgr save calculates the difference between the current system's configuration and the configuration described by the configuration directory, and writes it back into that directory. aconfmgr apply does the inverse: it applies the difference between the described configuration and the current system, installing and removing packages and creating and editing files.

Both paths go through an intermediate step that explains the design. Evaluating the scripts in the configuration directory compiles a system configuration description into an output directory. The difference between that output directory and the actual current system configuration is what determines the actions taken.

Because the system state is materialised as a directory before anything is compared, a preview is structural rather than a feature someone had to add. The README says that apply previews and confirms actual system changes before applying them.

The contract is mutual idempotence: after a successful invocation of either command, running it again produces no further change. That is the property that makes the tool safe to re-run from a cron job or a provisioning script.

## Installation is a clone, and dependencies arrive at run time

There is no build step. The README says to simply clone or download and unzip the repository, and that aconfmgr installs its dependencies as needed during execution. An AUR package, aconfmgr-git, is also available.

The repository contents match that description. There is a single aconfmgr entry point, a man page in aconfmgr.1, a src/ directory with the implementation, and a test/ directory. The primary language is shell, and there is a GitHub Actions workflow named test.yml plus a Coveralls coverage badge, so the tool is tested in CI even though it ships as a script rather than a binary.

One practical point from the first-run instructions: you do not need to run aconfmgr via sudo. It elevates as necessary by invoking sudo itself. That matters for a tool that installs packages, because it means the configured sudoers behaviour is what governs escalation, and you can review the elevation rather than granting blanket root.

## The first run dumps everything into 99-unsorted.sh, and that is the hard part

First-run behaviour is blunt by design. aconfmgr save transcribes the whole system into the configuration directory, producing 99-unsorted.sh plus other files describing the system. The configuration directory is usually ~/.config/aconfmgr, or ./config when running from a git checkout, and -c overrides it.

The README then tells you to expect noise, because the first save will likely include temporary or auto-generated files that no package owns. The fix is a file of your own, for example 10-ignores.sh, containing lines such as an IgnorePath directive naming a file or a glob for a directory, followed by deleting everything else from the configuration directory and re-running save so the transcription respects those rules.

The second step is the real work and the README is direct about it: review 99-unsorted.sh and sort its contents into your own files, named with two leading digits, a .sh extension and bash syntax, for example 10-base.sh, 20-drivers.sh, 30-gui.sh, 50-misc.sh. The suggestion that accompanies this is to write a comment for each package explaining why it was installed, so that later you can tell when the reason has expired and the package should go.

There is a third step for anything obsolete. Rather than sorting a package in, you delete 99-unsorted.sh and run apply, which synchronises the system against your curated configuration and removes what you left out.

## The save workflow only appends, so refactoring is your job

This is the limitation the documentation is most candid about. aconfmgr save writes the difference to 99-unsorted.sh as a series of shell commands that attempt to bring the configuration up to date with the current system. Since the script only appends to that file, it may end up undoing configuration changes made earlier in your own scripts, for instance removing a package from the list.

The README states the responsibility directly: refactoring the configuration to remove redundancies, document changes and improve maintainability is up to the user.

So the tool's role is deliberately narrow. It detects and transcribes drift. It does not merge it into a tidy declarative description. That is a defensible division for a script-oriented tool, and it is also the difference between aconfmgr and the declarative alternatives below.

## Maintenance means the diff should always be empty when you commit

Once the configuration is curated, the operating rhythm is short. Run aconfmgr save. If it produced uncommitted changes in the configuration directory, that means the live system has changes nobody has accounted for. Review them, sort them into the appropriate numbered files, document them, commit and push.

The README adds a specific warning about what to version: ideally 99-unsorted.sh should not be committed, because it only gets created when the current configuration does not reflect the current system state. In other words, its existence is a signal that drift exists, and committing it would launder that signal.

That is why version control is called for rather than merely suggested. With the curated scripts committed, an empty 99-unsorted.sh means the machine matches the repository. A dirty one records unaccounted system changes for review.

Restoring is the same command in the other direction. Put the right configuration in the configuration directory, run aconfmgr apply, preview and confirm, and the machine is brought into line.

## The syntax is bash, which is the feature and the hazard

The README's stated reason for representing the system configuration as shell scripts is that it is trivially extensible. Extensibility here means genuine control: conditionals, loops, variables computed from the host, and files whose content is decided when the script runs rather than when it was written.

The cost is that the configuration is a program, not data. It executes with the privileges needed to install packages and rewrite /etc, and its correctness depends on shell semantics that a reviewer has to reason about. The README's guidance on naming and syntax is the main guard available: two leading digits for load order, .sh extension, bash syntax.

There is also an inlining mechanism described in the README for embedding file content entirely and for embedding file edits, which is how a configuration directory carries both the list of changes and the content of the files that should result. That is worth reading in full in the README before designing a configuration layout, since it determines whether you hand-edit files or let aconfmgr write them.

## How it differs from the declarative and archiving alternatives

The README includes comparison sections for Puppet, Ansible, NixOS, lostfiles and etckeeper, but the excerpt does not document their feature differences.

## Maintenance and the licence gap

The repository is not archived and the last push was on 2026-10-07, which is recent for a shell utility. There are no GitHub releases, so there is no version boundary to track; the AUR package tracks the git repository.

The repository's licence is listed as unknown, and the README has a License section whose content is not visible here. That is worth resolving before you go further than personal use. aconfmgr configuration directories are full of shell code that describes exactly what is installed on a machine, including hostnames, users and sometimes credentials in configuration files copied out of /etc, and the absence of a stated licence means there is no clear grant for publishing or redistributing one.

For the same reason, treat the configuration directory as sensitive data even when it lives in a private repository.

## Conclusion

Adopt aconfmgr if you run Arch across several machines and want one machine's package list and /etc state reproduced exactly, since save and apply are mutually idempotent and apply shows the change set before touching anything. Do not adopt it if you want unattended convergence or a declarative dependency graph: the configuration is shell code that is executed, so reproducing a machine means running the same script on it rather than solving for a solution. Verify first that your configuration directory is in version control before the first save, because the workflow depends on the diff between the committed scripts and the live system being meaningful, and resolve the repository's unknown licence status before redistributing a derived configuration.

## FAQ

### How do I install aconfmgr on Arch Linux?

Clone or download and unzip the GitHub repository, and aconfmgr installs its dependencies as needed during execution. An AUR package named aconfmgr-git is also available. You do not need to run it via sudo; it invokes sudo itself when it needs elevation.

### What does aconfmgr save and aconfmgr apply each do?

save calculates the difference between the current system and the configuration described by the configuration directory and writes it back there. apply does the inverse, installing or removing packages and creating or editing configuration files. aconfmgr apply previews actual system changes before applying them, and the README states that the two commands are mutually idempotent.

### How do I stop aconfmgr from tracking files it should ignore?

Create a file such as 10-ignores.sh in the configuration directory with IgnorePath lines naming individual files or a directory glob, then delete the rest of the configuration directory and re-run aconfmgr save so the transcription respects the ignore rules.

## Sources

- [CyberShadow/aconfmgr on GitHub](https://github.com/CyberShadow/aconfmgr)
- [Issues](https://github.com/CyberShadow/aconfmgr/issues)
- [README](https://github.com/CyberShadow/aconfmgr/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/cybershadow-aconfmgr
