{"id":47625586,"url":"https://github.com/fgrehm/chezmoi-recipes","last_synced_at":"2026-04-01T22:46:05.263Z","repository":{"id":344838484,"uuid":"1183326812","full_name":"fgrehm/chezmoi-recipes","owner":"fgrehm","description":"A recipe layer for chezmoi","archived":false,"fork":false,"pushed_at":"2026-03-23T23:54:03.000Z","size":223,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-24T11:31:04.995Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fgrehm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-16T13:53:28.000Z","updated_at":"2026-03-23T23:53:43.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/fgrehm/chezmoi-recipes","commit_stats":null,"previous_names":["fgrehm/chezmoi-recipes"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/fgrehm/chezmoi-recipes","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fgrehm%2Fchezmoi-recipes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fgrehm%2Fchezmoi-recipes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fgrehm%2Fchezmoi-recipes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fgrehm%2Fchezmoi-recipes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fgrehm","download_url":"https://codeload.github.com/fgrehm/chezmoi-recipes/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fgrehm%2Fchezmoi-recipes/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31292695,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T21:15:39.731Z","status":"ssl_error","status_checked_at":"2026-04-01T21:15:34.046Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-01T22:46:04.742Z","updated_at":"2026-04-01T22:46:05.255Z","avatar_url":"https://github.com/fgrehm.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# chezmoi-recipes\n\nA recipe layer for [chezmoi](https://www.chezmoi.io/).\n\n\u003e **Status: experimental.** This project is under active development and going through rapid iteration. The architecture recently changed (`.chezmoiroot` approach) and I'm about to dogfood it by migrating my own dotfiles. Expect breaking changes. Feedback welcome via [issues](https://github.com/fgrehm/chezmoi-recipes/issues).\n\u003e\n\u003e **Note on chezmoi compatibility:** chezmoi deliberately uses a single source directory with a 1:1 mapping to target state ([design FAQ](https://www.chezmoi.io/user-guide/frequently-asked-questions/design/#can-chezmoi-support-multiple-sources-or-multiple-source-states)). chezmoi-recipes works outside that model by using [`.chezmoiroot`](https://www.chezmoi.io/reference/special-files/chezmoiroot/) to point chezmoi at a generated `compiled-home/` directory, then overlaying multiple recipe fragments into it. Guard hooks block commands like `chezmoi add` and `chezmoi edit` that would write to `compiled-home/` instead of the real source. This is not endorsed by chezmoi and may interact poorly with future chezmoi changes. Use at your own risk.\n\n## What is this?\n\nchezmoi-recipes lets you split a chezmoi source directory into modular, self-contained **recipes**. Each recipe is a directory containing a chezmoi source fragment (configs, scripts, templates) and a README. chezmoi-recipes overlays recipe files into chezmoi's source directory via a [hook](https://www.chezmoi.io/reference/configuration-file/hooks/), then chezmoi applies as normal.\n\nchezmoi already handles dotfile management, script execution, and templating. chezmoi-recipes adds structure on top: group related chezmoi files into named recipes you can understand and remove without hunting through the source tree.\n\n## The problem\n\nchezmoi is great for managing dotfiles. But its source directory is flat by design: every file mirrors a path in your home directory, and there's no built-in way to group related files together.\n\nThis works fine at first. Once you're managing lots of \"stuff\", the source directory becomes a wall of `dot_`, `private_`, and `run_once_` files with no logical grouping. It gets hard to tell which files belong to which tool, what scripts are for what, and what you can safely remove.\n\nThe usual workarounds within chezmoi:\n\n- Templated `.chezmoiignore` for per-machine differences. Works, but you end up with a giant ignore file that's hard to reason about.\n- `.chezmoiroot` to keep repo root clean. Helps with repo organization but doesn't help with the flat namespace inside the source state.\n- Splitting shell configs into smaller files. Good practice, but orthogonal to the source directory organization problem.\n\nNone of these give you a way to say \"these 5 files and 2 scripts are all part of my neovim setup.\"\n\n### Why not something else?\n\n- **[Nix Home Manager](https://github.com/nix-community/home-manager)** solves this at a deeper level: each program module is self-contained, and packages + configs are declared together. But it requires learning Nix (steep curve) and buying into the Nix ecosystem. If you're already using chezmoi and happy with it, switching to Nix is a big leap.\n- **[GNU Stow](https://www.gnu.org/software/stow/)** has the right mental model (per-tool directories symlinked into place), but no templating, encryption, or script execution.\n- **[Dotter](https://github.com/SuperCuber/dotter)** is a lightweight alternative with Handlebars templates, but has a smaller ecosystem and fewer features than chezmoi.\n\nchezmoi-recipes takes a different approach: keep chezmoi as the foundation (templating, scripts, encryption, cross-platform support) and add a thin organizational layer on top.\n\n## How it works\n\nchezmoi-recipes overlays recipe files into a compiled source directory. It integrates via a single chezmoi hook: `read-source-state.pre` overlays `home/` and `recipes/` into `compiled-home/`. Your workflow is just `chezmoi apply`.\n\n```\nyour-repo/home/                    ───┐\n                                      ├──  overlay  ──\u003e  compiled-home/  ──\u003e  chezmoi apply  ──\u003e  ~/\nyour-repo/recipes/git/chezmoi/     ───┤\nyour-repo/recipes/neovim/chezmoi/  ───┘\n```\n\nInstead of a flat source directory:\n\n```\ncompiled-home/                       \u003c- generated, gitignored\n  dot_gitconfig\n  dot_config/git/ignore\n  dot_config/nvim/init.lua.tmpl\n  .chezmoiscripts/run_once_install-git.sh\n  .chezmoiscripts/run_once_install-neovim.sh\n  .chezmoiscripts/run_after_configure-neovim.sh\n```\n\nYou organize recipes in your own repo:\n\n```\nmy-dotfiles/\n  .chezmoiroot                       \u003c- points chezmoi at compiled-home/\n  home/                              \u003c- tracked chezmoi source files\n    .chezmoi.toml.tmpl\n    dot_bashrc\n  recipes/\n    git/\n      README.md\n      chezmoi/\n        dot_gitconfig\n        dot_config/git/ignore\n        .chezmoiscripts/run_once_install-git.sh\n    neovim/\n      README.md\n      chezmoi/\n        dot_config/nvim/init.lua.tmpl\n        .chezmoiscripts/run_once_install-neovim.sh\n        .chezmoiscripts/run_after_configure-neovim.sh\n  compiled-home/                     \u003c- gitignored, generated by overlay\n```\n\nEverything about a tool is co-located. You can understand, share, or remove a recipe without touching anything else.\n\n## Core principles\n\n- Convention over configuration: a recipe is discovered by its directory structure, no manifest files\n- chezmoi does the work: no reinventing dotfile management, scripting, or templating\n- Recipes are independent: no composition or dependencies between recipes\n- Shareable by default: recipes work for anyone; personal data lives in chezmoi's `.chezmoi.toml.tmpl`\n- Incremental adoption: migrate one tool at a time from an existing chezmoi setup\n- Stay thin: chezmoi-recipes overlays files into the source directory, nothing more. If something starts looking like Ansible, it doesn't belong here\n\n## Recipe structure\n\nA recipe is a directory with a `README.md`:\n\n```\nneovim/\n  README.md                                # documentation (required, used for discovery)\n  chezmoi/                                 # chezmoi source state fragment\n    .chezmoiscripts/\n      run_once_install-neovim.sh           # package installation\n      run_after_configure-neovim.sh        # post-config setup\n    dot_config/nvim/\n      init.lua.tmpl                        # config files using chezmoi naming\n```\n\nThe directory name is the recipe name. The `chezmoi/` subdirectory uses chezmoi's naming conventions (`dot_`, `private_`, `symlink_`, `.tmpl`, etc.) and gets overlaid as-is into chezmoi's source directory.\n\nSee `docs/chezmoi-integration.md` for the full integration design.\n\n## Tech stack\n\n| Component  | Choice            |\n|------------|-------------------|\n| Language   | Go                |\n| Foundation | chezmoi           |\n| Target OS  | Debian 13 (Trixie)|\n| Platform   | Linux (macOS and Windows support can be added if enough interest) |\n| License    | MIT               |\n\n## Installation\n\n**Linux only** (macOS and Windows if enough interest).\n\n**One-liner setup** (recommended): `chezmoi-recipes init` generates a project-specific `install.sh` in your dotfiles repo. It handles the full flow: install binaries, clone, overlay, init, apply. Host it on GitHub and run from a fresh machine:\n\n```bash\n# Full setup from your dotfiles repo\nsh -c \"$(curl -fsSL https://raw.githubusercontent.com/username/dotfiles/main/install.sh)\"\n\n# Non-interactive (provide prompt values)\nsh -c \"$(curl -fsSL https://raw.githubusercontent.com/username/dotfiles/main/install.sh)\" -- \\\n  --promptString \"Full name=Your Name\" \\\n  --promptString \"Email=you@example.com\"\n```\n\n**Go install:**\n```bash\ngo install github.com/fgrehm/chezmoi-recipes@latest\n```\n\n**Build from source:**\n```bash\ngit clone https://github.com/fgrehm/chezmoi-recipes\ncd chezmoi-recipes\nmake build\nmake install  # Installs to ~/.local/bin\n```\n\n## Getting started\n\n1. Create a repo for your dotfiles:\n   ```bash\n   mkdir my-dotfiles \u0026\u0026 cd my-dotfiles\n   git init\n   ```\n\n2. Initialize chezmoi-recipes (creates `home/`, `.chezmoiroot`, `.gitignore`, config template, `recipes/` dir, and a `Makefile` with shell lint targets):\n   ```bash\n   chezmoi-recipes init\n   ```\n\n3. Run `chezmoi init` to process the config template (prompts for name, email, auto-detects environment):\n   ```bash\n   chezmoi init --source .\n   ```\n\n4. Scaffold a new recipe or copy an example:\n   ```bash\n   # Generate a starter recipe with annotated example files\n   chezmoi-recipes scaffold git\n   ```\n\n5. Apply it:\n   ```bash\n   chezmoi apply\n   ```\n\nchezmoi-recipes integrates via a single chezmoi hook. `read-source-state.pre` runs `chezmoi-recipes overlay`, which merges `home/` and recipe fragments into `compiled-home/`. This fires automatically on `chezmoi apply`.\n\nYou can also run the overlay manually:\n\n```bash\nchezmoi-recipes overlay          # overlay all recipes into source dir\nchezmoi-recipes overlay git      # overlay a specific recipe\n```\n\n## Example recipes\n\nExample recipes live in `examples/` in the chezmoi-recipes repo. They are reference implementations you can copy into your own `recipes/` directory.\n\n| Recipe | What it demonstrates |\n|--------|---------------------|\n| `git` | Templated config, SSH signing, global gitignore, shell aliases via `shellrc.d/` |\n| `ripgrep` | Minimal recipe: apt install only, no managed config |\n\n## Usage\n\n```bash\n# Initialize (sets up config template, recipes dir, shared scripts)\nchezmoi-recipes init\n\n# Configure user data (prompts for name, email; auto-detects environment)\nchezmoi init\n\n# List available recipes\nchezmoi-recipes list\n\n# Apply (overlay fires automatically via hook)\nchezmoi apply\n\n# Preview what chezmoi would do\nchezmoi diff\n\n# Sync from remote and apply\nchezmoi update\n\n# Overlay manually (without running chezmoi)\nchezmoi-recipes overlay\n\n# Preview what overlay would change\nchezmoi-recipes overlay --dry-run\n\n# Scaffold a new recipe (generates annotated starter files)\nchezmoi-recipes scaffold mytool\n\n# Remove a recipe (deletes files from source dir, does not undo scripts)\nchezmoi-recipes remove git\n\n# Show applied recipes and their files\nchezmoi-recipes status\n\n# Use a custom recipes directory\nchezmoi-recipes list --recipes-dir /path/to/recipes\n```\n\n### Shell lint and format\n\n`chezmoi-recipes init` writes a `Makefile` to your project root with targets for linting and formatting recipe shell scripts:\n\n```bash\nmake shell-lint       # shellcheck all .sh / .sh.tmpl / .bash files\nmake shell-fmt        # format with shfmt (writes in place)\nmake shell-fmt-check  # check formatting without modifying (exit 1 if dirty)\nmake check            # shell-fmt-check + shell-lint\n```\n\nRequires [shfmt](https://github.com/mvdan/sh) and [shellcheck](https://www.shellcheck.net/).\n\n### Shared script utilities\n\nchezmoi-recipes deploys logging helpers (`log_info`, `log_skip`, `log_error`, `run_quiet`) to the chezmoi source directory. Recipe scripts can source them:\n\n```bash\nsource \"${CHEZMOI_SOURCE_DIR}/scripts/ui.bash\"\n```\n\n### Template data\n\n`chezmoi-recipes init` writes a `.chezmoi.toml.tmpl` to `home/`. When you run `chezmoi init`, chezmoi processes this template, prompting for user data and auto-detecting the environment. The rendered output becomes chezmoi's config file (`chezmoi.toml`).\n\n| Variable | Source |\n|----------|--------|\n| `name` | Prompted via `promptStringOnce` at `chezmoi init` |\n| `email` | Prompted via `promptStringOnce` at `chezmoi init` |\n| `isContainer` | Auto-detected (/.dockerenv, env vars, etc.) |\n| `isDebian` | Auto-detected from `.chezmoi.osRelease.id` |\n| `hasNvidiaGPU` | Auto-detected via `lspci` (skipped in containers) |\n\nRecipes reference these via chezmoi templates (e.g., `{{ .name }}` in `.tmpl` files). The `[hooks.read-source-state.pre]` config is included in the template, so `chezmoi apply` automatically overlays recipes.\n\n## Development\n\nSee [docs/development.md](docs/development.md) for a complete guide to local setup, testing, and development workflows.\n\nQuick start:\n\n```bash\n# Build\nmake build\n\n# Run\n./bin/chezmoi-recipes list\n\n# Test\ngo test ./...\n```\n\n**Using a devcontainer?** See [docs/devcontainer.md](docs/devcontainer.md) for setup and usage instructions.\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffgrehm%2Fchezmoi-recipes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffgrehm%2Fchezmoi-recipes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffgrehm%2Fchezmoi-recipes/lists"}