fp-dotfiles-manager 0.2.5

Minimal, zero-dependency Chezmoi-based dotfiles manager
fp-dotfiles-manager-0.2.5 is not a library.

fp-dotfiles-manager

A minimal, zero-dependency, ultra-compact Rust-based manager for Chezmoi. This project provides a memory-safe, exceptionally lightweight, and unified control suite for your personal environments.

Features

  • Unified Sync Pipeline: Automated Chezmoi states, recursive adds, and Git staging under the hood.
  • Dry-Run & Preview: Preview state and tracking modifications using --dry-run or -n.
  • Encrypted Profile Backups: Archive tracked files relative to HOME with integrated --age-pass decryption/encryption.
  • Premium Git Logs: Beautiful single-line colored commits and diff statistics (logs).
  • Robust Path Globs: O(N) path resolution supporting complex match patterns and exclusions.
  • Atomic Locking: Self-healing directory lock that reclaims itself when a crashed or killed run leaves it behind.
  • Pre/Post Sync Hooks: Custom script pipelines executed before and after sync operations.
  • Secret Leak Auditing: Finds plaintext secrets in managed files and promotes them to encrypted tracking.
  • Automatic Config Regeneration: Regenerates the chezmoi config when its template changes, so chezmoi's nag never reaches you.
  • Zero-Dependency Footprint: Written in pure Rust. UPX-compressed binary under 70 KB (dynamic) / 207 KB (static LTO).

Configuration

Settings are resolved in the following priority order:

  1. Environment variables
  2. Configuration file at ~/.config/fp-dotfiles-manager/config.yml
  3. Internal defaults

Options & Overrides

Config Property Env Variable Default Value Description
tracked_file DOTFILES_TRACKED ~/.config/fp-dotfiles-manager/tracked File listing standard tracked home paths
tracked_enc_file DOTFILES_TRACKED_ENC ~/.config/fp-dotfiles-manager/tracked_encrypted File listing encrypted home paths
bootstrap_dir DOTFILES_BOOTSTRAP_DIR ~/.config/fp-dotfiles-manager/bootstrap.d Directory of executable post-setup scripts
ssh_key_path DOTFILES_SSH_KEY ~/.config/fp-dotfiles-manager/ssh_gitlab Private SSH key path for repository Git operations
age_pass DOTFILES_AGE_PASS "" Passphrase used to decrypt your age key non-interactively
repo_path DOTFILES_REPO_PATH fptbb/dotfiles Repository identifier on git host
repo_url DOTFILES_REPO_URL git@gitlab.com:fptbb/dotfiles.git Target SSH remote repository address
pre_sync_hook DOTFILES_PRE_SYNC ~/.config/fp-dotfiles-manager/hooks/pre-sync.sh Hook script run before synchronization starts
post_sync_hook DOTFILES_POST_SYNC ~/.config/fp-dotfiles-manager/hooks/post-sync.sh Hook script run after synchronization finishes
secret_scan DOTFILES_SECRET_SCAN enforce Secret-leak scanning coverage: off, warn, or enforce

Other system variables:

  • SKIP_BOOTSTRAP: Set to 1 or true to skip running bootstrap hooks.
  • NO_COLOR: Set to any value to disable ANSI terminal colors.

Concurrency

sync and audit-secrets --fix hold an exclusive lock in $XDG_RUNTIME_DIR/dotfiles-sync.lock.dir, so a second run skips rather than interleaving writes with the first.

The lock records the owning PID, so a lock left behind by a crashed run, a SIGKILL, or a failed git push is detected and reclaimed on the next invocation instead of blocking sync permanently. A lock is only honoured while its owner is alive; as a backstop against PID reuse, anything older than 6 hours is treated as stale. If you ever need to clear it by hand:

rm -rf "${XDG_RUNTIME_DIR:-$HOME/.cache}/dotfiles-sync.lock.dir"

To generate the default configuration template, run the initialization command:

fp-dotfiles-manager init-config

Setup & Usage Quick Tutorial

To start managing your dotfiles with fp-dotfiles-manager, follow these simple steps:

1. Bootstrapping / Initializing your Repository

You can use the setup command to either clone your existing configuration or bootstrap a brand new repository from scratch:

  • Scenario A: Bootstrap from an existing GitLab/GitHub Repository If you already have a dotfiles repository, the setup command will safely check for required tools, verify your SSH private key, clone your repository, decrypt your age keys, and apply your dotfiles:

    fp-dotfiles-manager setup --repo-url git@gitlab.com:yourusername/dotfiles.git
    
  • Scenario B: Initialize a Brand New Repository from Scratch If you want to start fresh or do not have a repository yet:

    fp-dotfiles-manager setup --repo-url git@gitlab.com:yourusername/dotfiles.git
    

    The setup engine will automatically:

    1. Detect that the remote repository does not exist or is empty.
    2. Initialize a clean local dotfiles repository (chezmoi init).
    3. Generate a brand new age key pair at ~/.config/chezmoi/.age-private-key.txt (if one doesn't exist).
    4. Create a default .chezmoi.toml.tmpl with your new public key to handle encryption automatically.
    5. Generate ~/.config/chezmoi/chezmoi.toml for immediate local operations.
    6. Bind your SSH repo_url as the git remote origin and establish secure Git configurations.
    7. Stage and create the initial git commit.

    Once complete, your first fp-dotfiles-manager sync will be fully prepared to push everything to your remote.

2. Configuration File

A configuration file should be created at ~/.config/fp-dotfiles-manager/config.yml. You can initialize a default template by running:

fp-dotfiles-manager init-config

3. Tracked Files Lists

By default, the lists of files to track are read from:

  • Standard files: ~/.config/fp-dotfiles-manager/tracked
  • Sensitive files: ~/.config/fp-dotfiles-manager/tracked_encrypted

Place these tracking lists (containing one relative path per line, e.g., .bashrc or .config/git/config) at those paths, or use fp-dotfiles-manager add to automatically append new files to them:

fp-dotfiles-manager add ~/.bashrc
fp-dotfiles-manager add-secret ~/.ssh/config

4. Post-Setup Bootstrap Hooks

Any numerical/alphabetical shell scripts (e.g., 01-packages.sh, 02-symlinks.sh) placed inside:

~/.config/fp-dotfiles-manager/bootstrap.d/

will be executed automatically after setup completes. You can run them manually at any time with:

fp-dotfiles-manager bootstrap

5. Sync & Backup

  • Sync modifications & discover new files:
    fp-dotfiles-manager sync
    
  • Preview sync changes without committing (Dry-Run):
    fp-dotfiles-manager sync --dry-run
    
  • Archive and encrypt tracked dotfiles:
    fp-dotfiles-manager backup [destination_path]
    

Tracking Wildcards, Exclusions, and Encryption Rules

fp-dotfiles-manager features a highly robust path evaluation engine that supports wildcard patterns, granular folder exclusions, and automated encryption fallback rules:

1. Wildcard and Glob Matches

  • You can use standard shell-native wildcards (*, ?, and [...]) inside your tracking files:
    • * matches any sequence of characters (e.g., .config/git/* tracks all files inside the git config directory).
    • .* or * at the end of directories will match files recursively.
    • If a directory path is added (e.g., .config/nvim), it is automatically treated as .config/nvim/* to recursively discover and track all files underneath.

2. Exclusions (Adding a folder except specific files)

  • To track a folder but exclude certain files inside it, prefix the excluded file pattern with an exclamation mark (!) in your tracking lists:
    • Example in your tracked file:
      .config/myfolder
      !.config/myfolder/tmp_*
      !.config/myfolder/local_cache.json
      
    • This tracks everything under .config/myfolder recursively, except for any files starting with tmp_ or named local_cache.json.

3. Folder Staging with Specific Encryption Overrides

  • If you add a folder to the standard tracked file but want specific sensitive files inside that folder to remain encrypted, simply add those sensitive files to your tracked_encrypted file:
    • Example:
      • In tracked:
        .config/myfolder
        
      • In tracked_encrypted:
        .config/myfolder/secret.key
        
    • How it works: The engine evaluates each discovered file. If a file is matched by any pattern in your encrypted list, it is automatically staged with --encrypt, while the rest of the folder remains staged as standard plain text. The encrypted files will always stay secure!

Secret Leak Scanning

Since chezmoi v2.72, chezmoi add scans every unencrypted file for embedded secrets and reports anything it finds on stderr:

chezmoi: /home/you/.config/app/creds:4: Identified a Slack Bot token, which may compromise bot integrations and communication channel security.

Rather than letting those lines leak into the middle of the sync output, fp-dotfiles-manager captures them and re-renders them through its own logger:

 󰧑 Adding 3 new file(s)...
  ⚠ Potential secret in /home/you/.config/app/creds:4: Identified a Slack Bot token, which may compromise bot integrations and communication channel security.
  ⚠ 1 potential secret(s) flagged in 1 file(s). Add them to tracked_encrypted to encrypt them.

Coverage levels

secret_scan Behaviour
off Scanning is disabled entirely. Nothing is scanned and no findings are reported.
warn Only files being added during the current run are scanned.
enforce (default) Also re-scans the whole managed set, so leaks that predate the current run are surfaced too.

Findings are always advisory — they are reported but never block a sync, and a flagged file is still committed as it was staged. The knob controls coverage, not enforcement.

enforce costs one extra pass over your managed files per sync. If your tracked tree is large and you only care about new additions, set secret_scan: "warn".

Auditing existing files

chezmoi add only ever inspects files it is adding, so leaks that were committed before scanning existed stay invisible to sync. The audit-secrets command covers those:

# Report plaintext secrets in already-managed files
fp-dotfiles-manager audit-secrets

# Additionally move the flagged paths into tracked_encrypted and re-encrypt them
fp-dotfiles-manager audit-secrets --fix

--fix appends the offending paths to tracked_encrypted and re-adds them with --encrypt, so the plaintext source entry is replaced by an encrypted_ one. Run fp-dotfiles-manager sync afterwards to commit and push the change. To undo, delete the line from tracked_encrypted.

Encrypted files are never flagged: chezmoi's scanner keys off the prospective add, so scanning a file that is already encrypted would otherwise report it on every single run. Both the enforce pass and audit-secrets therefore work from chezmoi managed --exclude=encrypted.

Suppressing a false positive

If a finding is not a real secret, the simplest fix is to move that path into tracked_encrypted. Alternatively, the scanner honours inline allow comments — adding betterleaks:allow or gitleaks:allow to a line suppresses findings on it:

token = "xoxb-not-a-real-token"  # betterleaks:allow

Requirements and degradation

Secret scanning requires chezmoi >= 2.72. On older versions the manager probes once, prints a single warning, and carries on without scanning rather than passing an unsupported flag and failing the run.


Automatic Config Regeneration

fp-dotfiles-manager generates ~/.config/chezmoi/chezmoi.toml for you from the .chezmoi.toml.tmpl in your repo, so you should never need to edit chezmoi's own files or run chezmoi commands directly.

When the template changes, plain chezmoi reacts by printing this on every state-changing command until you intervene:

chezmoi: warning: config file template has changed, run chezmoi init to regenerate config file

Rather than pass that through, the manager resolves it: sync, apply, update, status, and audit-secrets all detect the drift and regenerate the config automatically.

 󰧑 Chezmoi config template changed; regenerating config file...
 󰄬 Regenerated the chezmoi config from its template.
 󰧑 Previous config backed up to /home/you/.config/chezmoi/chezmoi.toml.fp-manager.bak

Your previous config is always backed up to chezmoi.toml.fp-manager.bak (owner-only, since it can reference your age identity) before being regenerated. The repair only rewrites the config file — it never touches your home directory, and it never commits or pushes. If regeneration fails, the sync continues against the existing config and says so, because a stale config still works.

Regenerating re-renders the template, so any hand-edits you made directly to chezmoi.toml are replaced. Make such changes in .chezmoi.toml.tmpl instead — that is the source of truth.


Command Line Interface

Subcommand names and short descriptions are defined once in catalog/ and shared with the TUI. Run the binary for the live help text:

fp-dotfiles-manager --help
# or
cargo run -p fp-dotfiles-manager -- --help

Compilation and Installation

This repository is a Cargo workspace with three members:

Crate Role Binary
fp-dotfiles-manager CLI (zero external crates.io deps aside from the shared catalog) fp-dotfiles-manager
fp-dotfiles-tui Optional ratatui frontend (tui/) fp-dotfiles-tui
fp-dotfiles-catalog Shared command names / help text for CLI + TUI (library)

Both binaries build into the same workspace target/ tree. The project uses just as a command runner for building and size checks.

Portable Static Build (CLI)

Builds a statically linked release binary utilizing cross-crate Link-Time Optimization (LTO) and panic-abort metadata pruning. UPX is used to perform ultra-brute compression.

just release

Output Path: target/release-static/fp-dotfiles-manager

Portable Static Build (TUI)

just release-tui

Output Path: target/release-static/fp-dotfiles-tui

Build CLI + TUI together

just release-all    # static + UPX for both
just build-all      # debug for both

Dynamic Build

Builds a dynamically linked release binary with an embedded rpath resolving to your Rust compiler toolchain's shared libraries.

just release-dynamic
# or: just release-dynamic-tui / just release-dynamic-all

Output Path: target/release/fp-dotfiles-manager (and fp-dotfiles-tui when using *-all)

Installation

Installs the statically linked portable release binary to your local bin directory.

just install [prefix="~/.bin"]
just install-tui [prefix="~/.bin"]
just install-all [prefix="~/.bin"]

TUI

See tui/README.md. Quick start:

just build-all
just run-tui

Clean Artifacts

just clean