Declarative package and dotfile management for Arch Linux.
dekl allows you to define your system's packages and configuration in YAML files, making your Arch Linux setup repeatable and version-controllable.
⚠️ Alpha Development NoticeThis project is in early alpha stage. Features may be incomplete, unstable, or subject to breaking changes. Use at your own risk and expect bugs.
dekl follows the Declarable Arch Manifesto - declare intent, converge state, move on.
Your system matches your declaration, nothing more. Every package belongs to a module. Simplicity over features. Safety first - destructive operations require confirmation by default.
- Confirmation prompts before destructive operations
-
--jsonoutput for scripting - Module dependencies/conflicts
- Dotfile pruning when modules are disabled
- Wiki
Install from the Arch User Repository:
Stable release:
# Using paru
paru -S deklDevelopment version (tracks git master):
# Using paru
paru -S dekl-gitOr build from source: See the Development section for building instructions.
-
Initialize
deklfor your host:dekl init
This creates the configuration directory
~/.config/dekl-arch/with basic structure and prompts you to select an AUR helper (paru recommended, yay, or pacman only). -
Capture your current system state:
dekl merge
This creates a
systemmodule with all currently installed packages. It will be gitignored by default. -
Check the status:
dekl status
See what packages, services, and dotfiles would be installed, enabled, or removed.
-
Sync your system:
dekl sync
Apply the changes to packages, services, and dotfiles. Use
--dry-runto preview first. Use--yesto skip confirmation prompts for removals. Use--pruneor--no-pruneto control removal of undeclared packages (default: prune).
dekl uses YAML files in ~/.config/dekl-arch/.
config.yaml: Main config with host name.hosts/{hostname}.yaml: Host-specific config with modules and AUR helper.modules/: Directory with module definitions.
Each module is a directory with module.yaml containing a list of packages.
Example module (modules/my-tools/module.yaml):
packages:
- firefox
- vim
- git
- htopModules can also declare services to enable:
packages:
- firefox
- vim
services:
- sshd
- docker
- name: my-user-service
user: trueServices can be strings or objects with name, user (for user services), and enabled (defaults to true).
Add modules to your host config (hosts/{hostname}.yaml):
aur_helper: paru # paru (recommended), yay, or pacman
auto_prune: true # Remove undeclared packages (default: true)
modules:
- base
- system
- my-tools~/.config/dekl-arch/
├── config.yaml # Points to host
├── hosts/
│ └── myhost.yaml # Modules list, AUR helper
├── modules/
│ ├── base/
│ │ └── module.yaml # Core packages
│ ├── neovim/
│ │ ├── module.yaml # Packages, hooks, dotfiles
│ │ ├── dotfiles/
│ │ │ └── nvim/ # -> ~/.config/nvim/
│ │ └── scripts/
│ │ └── setup.sh
│ └── system/ # Generated, gitignored
│ └── module.yaml
└── state.yaml # Gitignored, tracks hook runs
Modules and hosts can define hooks: scripts that run at specific points.
Module hooks: pre (before sync), post (after sync).
Host hooks: pre_sync, post_sync, pre_update, post_update.
Example module with hooks (modules/neovim/module.yaml):
packages:
- neovim
hooks:
post: scripts/setup.shExample host config with hooks (hosts/{hostname}.yaml):
modules:
- base
- system
- my-tools
hooks:
post_sync: scripts/restart-services.shHook scripts can be configured with options:
hooks:
post:
run: scripts/setup.sh
always: true # Run every time, not just once
root: true # Run with sudoModules can include dotfiles to symlink into your home directory.
Create a dotfiles/ directory in the module with your config files.
Supported formats:
# Symlink all to ~/.config/
dotfiles: true
# Disabled
dotfiles: false
# Explicit mapping
dotfiles:
nvim: ~/.config/nvim
fonts: ~/.local/share/fonts
conf: ~/.config/app/conf # auto-detect
conf/: ~/.config/app/conf.d/ # explicit directorydotfiles: true: Symlink all files and directories indotfiles/to~/.config/dotfiles: false: Disable dotfiles for this module- Dict format: Map source files/directories to target paths
- Trailing slash on source indicates directory (e.g.,
conf/) - Targets are expanded with
~for home directory
- Trailing slash on source indicates directory (e.g.,
dekl init [--host HOST]: Initialize config for a host (defaults to current hostname) and select AUR helperdekl merge [--services] [--dry-run]: Capture current explicit packages into asystemmoduledekl status [--prune/--no-prune]: Show diff between declared and installed packages, services, and dotfilesdekl sync [--dry-run] [--prune/--no-prune] [--yes] [--no-hooks] [--no-dotfiles] [--no-services]: Apply changes to sync system with declared statedekl update [--dry-run] [--no-hooks]: Upgrade system packagesdekl add <packages>... [-m module] [--dry-run]: Add package(s) to a module and install themdekl drop <packages>... [--dry-run]: Remove package(s) from all modules and uninstall themdekl enable <services>... [-m module] [--user] [--dry-run]: Add service(s) to a module and enable themdekl disable <services>... [-m module] [--remove] [--user] [--dry-run]: Disable service(s) (set enabled: false or remove from module)dekl hook list: List all hooks and their statusdekl hook run <name>: Manually run a hookdekl hook reset <name>: Reset a hook to run again on next syncdekl module list: List all modules and their statusdekl module new <names>...: Create new empty module(s)dekl module on <names>...: Activate module(s)dekl module off <names>...: Deactivate module(s)dekl module show <name>: Show module contents
- Repeatable Arch Manifesto - The philosophy behind dekl
- rebos - Bring repeatable system configuration to any Linux distribution
- dcli - Declarative config tool for Arch Linux
This project uses just for task running.
# Install dependencies
just install
# Run the CLI
just run
# Lint code
just lint
# Show available tasks
just help# PyInstaller (faster to build, larger size, slower startup)
just build-binary
# Nuitka (slower to build, smaller size, faster startup)
just build-nuitka-
Run the release command:
just release 0.2.0
This will bump the version, commit, push, trigger the GitHub release workflow, and wait for it to complete.
-
Review and publish the draft release on GitHub.
-
Update the repos:
just update-repos 0.2.0 ~repo ~aur