--- name: wand description: Refactor shell functions and aliases into wand YAML configs. This skill should be used when the user wants to extract shell functions, aliases, or scripts into a wand.yml command runner config, create new wand configs, or add commands to existing wand configs. Triggers on requests like "move these functions to wand", "create a wand config for X", "refactor this script into wand commands". --- # Wand Refactor Extract shell functions and aliases into [wand](https://github.com/chenasraf/wand) YAML configs, replacing inline logic with declarative command definitions and thin alias wrappers. ## Wand Config Reference Wand is a YAML-driven command runner. Config files are auto-discovered from CWD upward, `~/`, and `~/.config/`. A custom path can be specified via `--wand-file ` or `WAND_FILE=`. ### Command Fields | Field | Type | Purpose | | ----------------- | -------------------- | ------------------------------------ | | `description` | `string` | Help text shown in `--help` | | `cmd` | `string` | Shell command to execute | | `children` | `map[string]Command` | Nested subcommands | | `flags` | `map[string]Flag` | Custom typed flags | | `env` | `map[string]string` | Environment variables | | `working_dir` | `string` | Execution directory | | `aliases` | `string[]` | Alternate command names | | `confirm` | `bool` or `string` | Confirmation prompt before execution | | `confirm_default` | `string` | Default answer for confirm | ### Flag Fields | Field | Type | Purpose | | ------------- | -------- | ------------------------------------------- | | `alias` | `string` | Single-letter shorthand (e.g. `o` for `-o`) | | `description` | `string` | Description shown in `--help` | | `default` | `any` | Default value | | `type` | `string` | `"bool"` for boolean flags, omit for string | Flag values are accessible as `$WAND_FLAG_` env vars (uppercased, hyphens become underscores). ### Positional Arguments Extra CLI arguments are available as `$1`, `$2`, `$@` in the command's `cmd`. ## Refactoring Process ### Step 1: Analyze the Source Read the source file(s) containing the shell functions/aliases to refactor. Identify: - **Command groups**: Functions that share a common prefix or domain (e.g. `nc-dev-*`, `nc-aio-*`) - **Shared state**: Variables, config paths, or logic used across multiple functions - **Modal behavior**: Functions that differ only by a mode/target (e.g. dev vs aio) — these become a single command with a flag - **Subcommand hierarchies**: Related commands that naturally nest (e.g. `db-proxy start`/`db-proxy stop`) ### Step 2: Design the Wand Config Map the analyzed functions to wand commands following these principles: 1. **Merge modal variants into flags**: If two functions differ only by target (e.g. `nc-dev-occ` vs `nc-aio-occ`), create one command with a `--` flag (default to the more common mode). 2. **Use `children` for related pairs**: Commands that are natural opposites (start/stop, enable/disable, backup/restore) belong as children of a parent command. 3. **Use `env` for shared config**: Constants like paths, container names, etc. go in the `env` field rather than hardcoded in `cmd`. 4. **Use `working_dir`** instead of `pushd`/`popd` or `cd`. 5. **Use `confirm`** for destructive or long-running operations. 6. **Keep commands self-contained**: Each command's `cmd` must be independently runnable — do not call other wand commands or rely on shell aliases being available. 7. **Add `set -euo pipefail`** at the top of multi-line commands that should fail fast. 8. **Use `aliases`** for common shorthand names within wand itself. ### Step 3: Choose Config File Location - If adding to the existing global wand config: edit `~/.dotfiles/.config/wand.yml` - If creating a domain-specific config (preferred for large command sets): create `~/.dotfiles/.config/wand/.yml` and define an alias: `alias ="wand --wand-file \$HOME/.config/wand/.yml"` After creating or modifying a config file in `~/.dotfiles/.config/`, run `stow -v -d $DOTFILES -t ~ .` to symlink it. ### Step 4: Create Aliases Replace the original shell file with thin aliases that point to wand commands. This preserves backward compatibility with existing muscle memory. Alias conventions: - Define a **base alias** for the wand config (e.g. `alias nxc="wand --wand-file $HOME/.config/wand/nextcloud.yml"`) - Map each old function/alias to ` [--flags] [--]` - Append `--` before positional args when the command has flags, to prevent flag/arg ambiguity - Keep old alias names working so existing scripts and habits are preserved ### Step 5: Clean Up - Remove the original shell functions from the source file, keeping only the alias definitions - Remove any global variables that were only used by the extracted functions (they now live in `env` fields) - If the source file becomes aliases-only, consider whether it should stay as-is or merge into `aliases.zsh` ## Example: Before and After ### Before (shell functions) ```zsh APP_DIR="$HOME/myapp" my-build() { pushd $APP_DIR; make build; popd; } my-test() { pushd $APP_DIR; make test; popd; } my-deploy() { echo "Deploying..." pushd $APP_DIR; make deploy ENV=$1; popd } alias my-deploy-prod="my-deploy prod" alias my-deploy-staging="my-deploy staging" ``` ### After (wand.yml + aliases) ```yaml # ~/.dotfiles/.config/wand/myapp.yml build: description: Build the project working_dir: ~/myapp cmd: make build test: description: Run tests working_dir: ~/myapp cmd: make test deploy: description: Deploy the project working_dir: ~/myapp confirm: Deploy to $1? cmd: | echo "Deploying..." make deploy ENV=$1 ``` ```zsh # aliases alias myapp="wand --wand-file \$HOME/.config/wand/myapp.yml" alias my-build="myapp build" alias my-test="myapp test" alias my-deploy="myapp deploy --" alias my-deploy-prod="myapp deploy prod" alias my-deploy-staging="myapp deploy staging" ```