{"id":51055793,"url":"https://github.com/chenasraf/wand","last_synced_at":"2026-06-22T21:01:11.251Z","repository":{"id":348051551,"uuid":"1196278286","full_name":"chenasraf/wand","owner":"chenasraf","description":"YAML-driven command runner with nested subcommands","archived":false,"fork":false,"pushed_at":"2026-04-03T06:53:02.000Z","size":45,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-26T00:29:09.711Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/chenasraf.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":"chenasraf","patreon":null,"open_collective":null,"ko_fi":"casraf","tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":["https://www.paypal.com/cgi-bin/webscr?cmd=_donations\u0026business=TSH3C3ABGQM22\u0026currency_code=ILS\u0026source=url"]}},"created_at":"2026-03-30T14:42:42.000Z","updated_at":"2026-04-03T06:51:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/chenasraf/wand","commit_stats":null,"previous_names":["chenasraf/wand"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/chenasraf/wand","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenasraf%2Fwand","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenasraf%2Fwand/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenasraf%2Fwand/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenasraf%2Fwand/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chenasraf","download_url":"https://codeload.github.com/chenasraf/wand/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenasraf%2Fwand/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34665261,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-22T02:00:06.391Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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-06-22T21:01:10.255Z","updated_at":"2026-06-22T21:01:11.245Z","avatar_url":"https://github.com/chenasraf.png","language":"Go","funding_links":["https://github.com/sponsors/chenasraf","https://ko-fi.com/casraf","https://www.paypal.com/cgi-bin/webscr?cmd=_donations\u0026business=TSH3C3ABGQM22\u0026currency_code=ILS\u0026source=url","https://ko-fi.com/casraf'"],"categories":[],"sub_categories":[],"readme":"# wand\n\n**`wand`** is a tiny, cross-platform command runner driven by a simple **YAML config file**, written\nin **Go**. Define your commands and subcommands in a `wand.yml`, and run them from anywhere in your\nproject tree.\n\n![Release](https://img.shields.io/github/v/release/chenasraf/wand)\n![Downloads](https://img.shields.io/github/downloads/chenasraf/wand/total)\n![License](https://img.shields.io/github/license/chenasraf/wand)\n\n---\n\n## 🚀 Features\n\n- **Simple YAML config**: define commands, descriptions, and nested subcommands in a single file.\n- **Auto-discovery**: finds `wand.yml` by searching the current directory, parent directories, `~/`,\n  and `~/.config/`.\n- **Nested subcommands**: commands can have arbitrarily deep children.\n- **Positional arguments**: pass arguments to commands and reference them with `$1`, `$2`, `$@`.\n- **Custom flags**: define typed flags (string or bool) with aliases, defaults, and descriptions,\n  accessible as `$WAND_FLAG_\u003cNAME\u003e` environment variables.\n- **Environment variables**: define env vars globally in `.config` or per command, with\n  command-level overrides.\n- **Working directory**: override the working directory for any command.\n- **Aliases**: define alternate names for commands.\n- **Confirmation prompts**: require `y/N` confirmation before running destructive commands.\n- **Pre/post hooks**: chain other wand commands to run before or after a command, with full\n  flag/argument forwarding.\n- **Built-in help**: auto-generated `--help` for every command and subcommand.\n- **Shell execution**: runs commands via your `$SHELL` with proper stdin/stdout/stderr passthrough.\n\n---\n\n## 🎯 Installation\n\n### Download Precompiled Binaries\n\nGrab the latest release for **Linux**, **macOS**, or **Windows**:\n\n- [Releases →](https://github.com/chenasraf/wand/releases/latest)\n\n### Homebrew (macOS/Linux)\n\nInstall directly from the tap:\n\n```bash\nbrew install chenasraf/tap/wand\n```\n\nOr tap and then install the package:\n\n```bash\nbrew tap chenasraf/tap\nbrew install wand\n```\n\n### From Source\n\n```bash\ngit clone https://github.com/chenasraf/wand\ncd wand\nmake build\n```\n\n---\n\n## ✨ Getting Started\n\nCreate a `wand.yml` in your project root:\n\n```yaml\nmain:\n  description: run the main command\n  cmd: echo hello from wand\n\nbuild:\n  description: build the project\n  cmd: go build -o myapp\n\ntest:\n  description: run tests\n  cmd: go test -v ./...\n  children:\n    coverage:\n      description: run tests with coverage\n      cmd: go test -coverprofile=coverage.out ./...\n```\n\n### Run a command\n\n```bash\n# run the main (default) command\nwand\n\n# run a named command\nwand build\n\n# run a nested subcommand\nwand test coverage\n\n# show help\nwand --help\nwand test --help\n```\n\n---\n\n## 📁 Config Resolution\n\n`wand` searches for `wand.yml` (or `wand.yaml`) in the following order:\n\n1. Current working directory (`./wand.yml`)\n2. Parent directories (searching upward to the filesystem root)\n3. Home directory (`~/.wand.yml`)\n4. Config directory (`~/.config/wand.yml`)\n\nThe first config file found is used.\n\nYou can override config discovery with an explicit path:\n\n```bash\n# via flag\nwand --wand-file ./other-config.yml build\n\n# via environment variable\nWAND_FILE=./other-config.yml wand build\n```\n\nThe `--wand-file` flag takes precedence over `WAND_FILE`.\n\n---\n\n## 📖 Config Reference\n\nEach top-level key defines a command. The special key `main` becomes the root (no-argument) command.\n\n| Field             | Type                 | Description                                 |\n| ----------------- | -------------------- | ------------------------------------------- |\n| `description`     | `string`             | Short description shown in `--help`         |\n| `cmd`             | `string`             | Shell command to execute                    |\n| `children`        | `map[string]Command` | Nested subcommands (same structure)         |\n| `flags`           | `map[string]Flag`    | Custom flags (see below)                    |\n| `env`             | `map[string]string`  | Environment variables for this command      |\n| `working_dir`     | `string`             | Working directory for the command           |\n| `aliases`         | `[]string`           | Alternate names for the command             |\n| `confirm`         | `bool` or `string`   | Prompt for confirmation before running      |\n| `confirm_default` | `string`             | Default answer: `\"yes\"` or `\"no\"` (default) |\n| `pre`             | `[]string`           | Wand commands to run before `cmd`           |\n| `post`            | `[]string`           | Wand commands to run after `cmd`            |\n\n### Flag fields\n\n| Field         | Type     | Description                                       |\n| ------------- | -------- | ------------------------------------------------- |\n| `alias`       | `string` | Single-letter shorthand (e.g. `o` for `-o`)       |\n| `description` | `string` | Description shown in `--help`                     |\n| `default`     | `any`    | Default value (`string` or `bool`)                |\n| `type`        | `string` | `\"bool\"` for boolean flags, omit for string flags |\n\n---\n\n## 📌 Positional Arguments\n\nCommands receive any extra arguments passed on the command line. Use `$1`, `$2`, etc. for specific\npositions, or `$@` for all arguments:\n\n```yaml\ngreet:\n  description: greet someone\n  cmd: echo \"Hello, $1! You said: $@\"\n```\n\n```bash\nwand greet world foo bar\n# → Hello, world! You said: world foo bar\n```\n\n---\n\n## 🚩 Flags\n\nDefine custom flags per command. Flag values are exposed as `$WAND_FLAG_\u003cNAME\u003e` environment\nvariables (uppercased):\n\n```yaml\nbuild:\n  description: build the project\n  cmd: |\n    echo \"output=$WAND_FLAG_OUTPUT verbose=$WAND_FLAG_VERBOSE\"\n  flags:\n    output:\n      alias: o\n      description: output path\n      default: ./bin\n    verbose:\n      alias: v\n      description: enable verbose output\n      type: bool\n```\n\n```bash\nwand build --output ./dist --verbose\n# → output=./dist verbose=true\n\nwand build -o ./dist -v\n# → output=./dist verbose=true\n\nwand build\n# → output=./bin verbose=false\n```\n\n---\n\n## 🌍 Environment Variables\n\nDefine environment variables globally in `.config` or per command. Command-level env vars override\nglobal ones:\n\n```yaml\n.config:\n  env:\n    NODE_ENV: production\n\nbuild:\n  description: build the project\n  cmd: echo \"env=$NODE_ENV out=$OUTPUT_DIR\"\n  env:\n    OUTPUT_DIR: ./dist\n```\n\n```bash\nwand build\n# → env=production out=./dist\n```\n\n---\n\n## ⚠️ Confirmation Prompts\n\nAdd `confirm: true` for a default prompt, or provide a custom message:\n\n```yaml\ndeploy:\n  description: deploy to production\n  cmd: ./deploy.sh\n  confirm: 'Deploy to production?'\n\nclean:\n  description: remove all build artifacts\n  cmd: rm -rf dist/\n  confirm: true\n\nrestart:\n  description: restart service\n  cmd: systemctl restart myapp\n  confirm: 'Restart the service?'\n  confirm_default: 'yes'\n```\n\n```bash\nwand deploy\n# → Deploy to production? [y/N]\n```\n\n---\n\n## 🔗 Pre \u0026 Post Hooks\n\nUse `pre` and `post` to run other wand commands before or after a command. Each entry is a\nshell-style string: the first token is the wand command name (subcommands are nested with\nspaces), followed by any args and flags.\n\n```yaml\nlint:\n  description: lint the project\n  cmd: golangci-lint run\n\ntest:\n  description: run tests\n  cmd: go test ./...\n\nbuild:\n  description: build the project\n  pre:\n    - lint\n    - test\n  post:\n    - 'echo \"build done: $WAND_FLAG_OUTPUT\"'\n  flags:\n    output:\n      alias: o\n      default: ./bin\n  cmd: go build -o $WAND_FLAG_OUTPUT\n```\n\n```bash\nwand build -o ./dist\n# runs: lint → test → go build -o ./dist → echo \"build done: ./dist\"\n```\n\n### Forwarding flags\n\nEntries are passed through environment variable expansion (`$VAR`, `${VAR}`) before being\nparsed, so `$WAND_FLAG_\u003cNAME\u003e` references resolve to the current command's flag values:\n\n```yaml\ndeploy:\n  flags:\n    target:\n      description: deploy target\n      default: staging\n  pre:\n    - 'notify --channel deploys --message \"deploying to $WAND_FLAG_TARGET\"'\n  cmd: ./deploy.sh $WAND_FLAG_TARGET\n```\n\nArbitrary flags and arguments can be passed directly:\n\n```yaml\nrelease:\n  pre:\n    - 'test --verbose'\n    - 'build --output ./dist'\n  cmd: ./release.sh\n```\n\n### Failure semantics\n\n- If a `pre` entry fails, the main `cmd` and remaining `pre`/`post` entries are skipped.\n- If the main `cmd` fails, no `post` entries run.\n- If a `post` entry fails, subsequent `post` entries are skipped.\n\nA command may omit `cmd` and define only `pre`/`post` to act as a pure aggregator.\n\n### Private commands\n\nPrefix a command name with `_` to mark it as private: it is hidden from `--help` output but\nremains fully runnable, both directly (useful for testing) and from `pre`/`post` entries. The\nsame rule applies to nested children.\n\n```yaml\nbuild:\n  pre:\n    - _ensure-deps\n  cmd: go build\n\n_ensure-deps:\n  description: install required tools\n  cmd: ./scripts/install-deps.sh\n```\n\n```bash\nwand --help        # _ensure-deps is not listed\nwand _ensure-deps  # still runs directly\nwand build         # runs _ensure-deps then the build\n```\n\n---\n\n## 🛠️ Contributing\n\nI am developing this package on my free time, so any support, whether code, issues, or just stars is\nvery helpful to sustaining its life. If you are feeling incredibly generous and would like to donate\njust a small amount to help sustain this project, I would be very very thankful!\n\n\u003ca href='https://ko-fi.com/casraf' target='_blank'\u003e\n\u003cimg height='36' style='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi1.png?v=3' alt='Buy Me a Coffee at ko-fi.com' /\u003e\n\u003c/a\u003e\n\nI welcome any issues or pull requests on GitHub. If you find a bug, or would like a new feature,\ndon't hesitate to open an appropriate issue and I will do my best to reply promptly.\n\n---\n\n## 📜 License\n\n`wand` is licensed under the [CC0-1.0 License](/LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchenasraf%2Fwand","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchenasraf%2Fwand","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchenasraf%2Fwand/lists"}