Wizard A wizard is a bash script that walks a human, step by step, through a manual procedure that's tedious to do by hand and tedious to re-explain to an AI every time. It opens each URL, says exactly what to click and copy, captures the values, writes them where they belong ( , GitHub secrets), confirms at every stage, and shows how many stages are left. It might configure third-party services, run a one-off migration, or move the project from one state to another. The delightful UX is already solved by template.sh: stage-by-stage progress, confirmation gates, cross-platform URL opening (in…

\\001' e=

Wizard A wizard is a bash script that walks a human, step by step, through a manual procedure that's tedious to do by hand and tedious to re-explain to an AI every time. It opens each URL, says exactly what to click and copy, captures the values, writes them where they belong ( , GitHub secrets), confirms at every stage, and shows how many stages are left. It might configure third-party services, run a one-off migration, or move the project from one state to another. The delightful UX is already solved by template.sh: stage-by-stage progress, confirmation gates, cross-platform URL opening (in…

\\002' p rc=0\n current=$(_existing \"$key\" || true)\n # Readline needs the colour codes wrapped in \\001..\\002 to place the cursor.\n p=\" $s$BOLD$e$prompt$s$RESET$e \"\n [[ -n \"$current\" ]] && p+=\"$s$DIM$e[Enter keeps current]$s$RESET$e \"\n read -e -r -p \"$p\" input || rc=1\n if (( rc )) && [[ -z \"$input\" ]]; then return 1; fi\n [[ -z \"$input\" && -n \"$current\" ]] && input=\"$current\"\n printf -v \"$key\" '%s' \"$input\"\n}\n\n# ask_secret KEY \"Prompt\" is like ask, but input is hidden.\nask_secret() {\n local key=\"$1\" prompt=\"$2\" current input rc=0\n current=$(_existing \"$key\" || true)\n if [[ -n \"$current\" ]]; then\n printf ' %s%s%s %s[Enter keeps current]%s ' \"$BOLD\" \"$prompt\" \"$RESET\" \"$DIM\" \"$RESET\"\n else\n printf ' %s%s%s ' \"$BOLD\" \"$prompt\" \"$RESET\"\n fi\n read -rs input || rc=1\n printf '\\n'\n if (( rc )) && [[ -z \"$input\" ]]; then return 1; fi\n [[ -z \"$input\" && -n \"$current\" ]] && input=\"$current\"\n printf -v \"$key\" '%s' \"$input\"\n}\n\n# write_env KEY VALUE upserts KEY='VALUE' into ENV_FILE (replaces any existing\n# line) and sets $KEY. Idempotent. Creates ENV_FILE at mode 0600; writes through\n# a symlink and keeps an existing file's mode.\nwrite_env() {\n local key=\"$1\" value=\"$2\" tmp sq=\"'\\\\''\"\n [[ -e \"$ENV_FILE\" ]] || (umask 077 && : > \"$ENV_FILE\")\n tmp=$(mktemp)\n grep -vE \"^${key}=\" \"$ENV_FILE\" > \"$tmp\" || true\n printf \"%s='%s'\\n\" \"$key\" \"${value//\\'/$sq}\" >> \"$tmp\"\n cat \"$tmp\" > \"$ENV_FILE\"\n rm -f \"$tmp\"\n printf -v \"$key\" '%s' \"$value\"\n WRITTEN_ENV+=(\"$key\")\n printf ' %s✓ wrote%s %s → %s\\n' \"$GREEN\" \"$RESET\" \"$key\" \"$ENV_FILE\"\n}\n\n# set_secret NAME VALUE sets a GitHub Actions repo secret via gh. Falls back\n# to a warning (and records it) if gh is unavailable or unauthenticated.\nset_secret() {\n local name=\"$1\" value=\"$2\"\n if command -v gh >/dev/null 2>&1 && gh auth status >/dev/null 2>&1; then\n if printf '%s' \"$value\" | gh secret set \"$name\" >/dev/null 2>&1; then\n WRITTEN_SECRET+=(\"$name\")\n printf ' %s✓ set%s GitHub secret %s\\n' \"$GREEN\" \"$RESET\" \"$name\"\n return\n fi\n fi\n SKIPPED+=(\"GitHub secret $name (set it manually: gh secret set $name)\")\n warn \"skipped GitHub secret $name: gh not ready; set it later\"\n}\n\n# set_var NAME VALUE sets a GitHub Actions repo variable (non-secret).\nset_var() {\n local name=\"$1\" value=\"$2\"\n if command -v gh >/dev/null 2>&1 && gh auth status >/dev/null 2>&1; then\n if gh variable set \"$name\" --body \"$value\" >/dev/null 2>&1; then\n printf ' %s✓ set%s GitHub variable %s\\n' \"$GREEN\" \"$RESET\" \"$name\"\n return\n fi\n fi\n SKIPPED+=(\"GitHub variable $name\")\n warn \"skipped GitHub variable $name, gh not ready; set it later\"\n}\n\n# finish clears, then shows a closing summary of everything configured.\nfinish() {\n _clear\n printf '\\n%s%s ✓ Setup complete%s\\n' \"$BOLD\" \"$GREEN\" \"$RESET\"\n (( ${#WRITTEN_ENV[@]} )) && note \"wrote ${#WRITTEN_ENV[@]} value(s) to $ENV_FILE: ${WRITTEN_ENV[*]}\"\n (( ${#WRITTEN_SECRET[@]} )) && note \"set ${#WRITTEN_SECRET[@]} GitHub secret(s): ${WRITTEN_SECRET[*]}\"\n if (( ${#SKIPPED[@]} )); then\n printf '\\n'; warn \"still to do by hand:\"\n for s in \"${SKIPPED[@]}\"; do note \" - $s\"; done\n fi\n printf '\\n'\n}\n\n# ──────────────────────────────────────────────────────────────────────────\n# STAGES: author this section. One stage() per step the human takes.\n# Replace the example below. Set TOTAL_STAGES to match the stages you write.\n# Keep every stage inside run_wizard and the last line as is: bash then parses\n# the whole file before the first prompt, so an edit mid-run can't break it.\n# ──────────────────────────────────────────────────────────────────────────\n\nrun_wizard() {\n\nTOTAL_STAGES=1\n\nbanner \"Stripe setup\"\n\n# ── Example stage: replace with your real steps ───────────────────────────\nstage \"Stripe: API keys\"\nsay \"We'll grab your Stripe test keys and store them for local dev + CI.\"\nopen_url \"https://dashboard.stripe.com/test/apikeys\"\nstep \"On the API keys page, copy the Publishable key (starts pk_test_).\"\nask STRIPE_PUBLISHABLE_KEY \"Paste the publishable key:\"\nstep \"Click 'Reveal test key' on the Secret key row, then copy it.\"\nask_secret STRIPE_SECRET_KEY \"Paste the secret key:\"\nwrite_env STRIPE_PUBLISHABLE_KEY \"$STRIPE_PUBLISHABLE_KEY\"\nwrite_env STRIPE_SECRET_KEY \"$STRIPE_SECRET_KEY\"\nset_secret STRIPE_SECRET_KEY \"$STRIPE_SECRET_KEY\" # CI needs this one\n# ──────────────────────────────────────────────────────────────────────────\n\nfinish\n}\n\nrun_wizard \"$@\"; exit\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":9498,"content_sha256":"6566f147299bc6f1d941e64591ed04385416d543e11f96f564c7228f5018d0ed"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Wizard","type":"text"}]},{"type":"paragraph","content":[{"text":"A ","type":"text"},{"text":"wizard","type":"text","marks":[{"type":"strong"}]},{"text":" is a bash script that walks a human, step by step, through a manual procedure that's tedious to do by hand and tedious to re-explain to an AI every time. It opens each URL, says exactly what to click and copy, captures the values, writes them where they belong (","type":"text"},{"text":".env","type":"text","marks":[{"type":"code_inline"}]},{"text":", GitHub secrets), confirms at every stage, and shows how many stages are left. It might configure third-party services, run a one-off migration, or move the project from one state to another.","type":"text"}]},{"type":"paragraph","content":[{"text":"The delightful UX is already solved by ","type":"text"},{"text":"template.sh","type":"text","marks":[{"type":"link","attrs":{"href":"template.sh","title":null}}]},{"text":": stage-by-stage progress, confirmation gates, cross-platform URL opening (including WSL), hidden secret entry, idempotent ","type":"text"},{"text":".env","type":"text","marks":[{"type":"code_inline"}]},{"text":" upserts, ","type":"text"},{"text":"gh secret","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"gh variable","type":"text","marks":[{"type":"code_inline"}]},{"text":" writes, and a closing summary. ","type":"text"},{"text":"Your job is only to scope the procedure and author its stages.","type":"text","marks":[{"type":"strong"}]},{"text":" The library above the ","type":"text"},{"text":"STAGES","type":"text","marks":[{"type":"code_inline"}]},{"text":" marker is identical in every wizard; that consistency is the point: never hand-edit it.","type":"text"}]},{"type":"paragraph","content":[{"text":"A wizard is ephemeral by default: built for one run, saved to a scratch or ","type":"text"},{"text":"scripts/","type":"text","marks":[{"type":"code_inline"}]},{"text":" path, deleted when the job's done. Commit it only when the user wants a repeatable setup path that should live in the repo.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Process","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"1. Scope the procedure","type":"text"}]},{"type":"paragraph","content":[{"text":"Work out every manual step the human must take and every value that gets captured along the way. Read the repo first, don't ask cold:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For setup: ","type":"text"},{"text":".env","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":".env.example","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":".env.*","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"README","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"docker-compose*","type":"text","marks":[{"type":"code_inline"}]},{"text":", framework config, and ","type":"text"},{"text":".github/workflows/*","type":"text","marks":[{"type":"code_inline"}]},{"text":" (every ","type":"text"},{"text":"secrets.*","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"vars.*","type":"text","marks":[{"type":"code_inline"}]},{"text":" reference is a value the wizard must produce).","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For a migration or transition: the current state, the target state, and the irreversible actions between them.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Then show the user the ordered list of stages and the values each produces, and confirm: they may add, drop, or reorder.","type":"text"}]},{"type":"paragraph","content":[{"text":"Done when:","type":"text","marks":[{"type":"strong"}]},{"text":" every stage is named in order, and for each captured value you know (a) where the human gets it, (b) where it's written (","type":"text"},{"text":".env","type":"text","marks":[{"type":"code_inline"}]},{"text":", a GitHub secret, both, or nowhere; some stages are pure actions), and (c) whether it's secret (hidden entry) or public.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"2. Map each stage's journey","type":"text"}]},{"type":"paragraph","content":[{"text":"For each stage, write the precise path a human follows: which URL to open, what to do there, where a value is shown, which variable it fills: e.g. \"Dashboard → Developers → API keys → Reveal test key → copy\". Where you don't actually know the current UI or the exact command, say so and ask the user or check the docs: never invent steps that may not exist.","type":"text"}]},{"type":"paragraph","content":[{"text":"Done when:","type":"text","marks":[{"type":"strong"}]},{"text":" every stage traces to concrete instructions a stranger could follow.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"3. Author the wizard","type":"text"}]},{"type":"paragraph","content":[{"text":"Copy ","type":"text"},{"text":"template.sh","type":"text","marks":[{"type":"code_inline"}]},{"text":" to the target path. Replace the example stage with one ","type":"text"},{"text":"stage","type":"text","marks":[{"type":"code_inline"}]},{"text":" per step, in dependency order. Use the library helpers: ","type":"text"},{"text":"stage","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"say","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"step","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"open_url","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"ask","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"ask_secret","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"write_env","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"set_secret","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"set_var","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"pause","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"confirm","type":"text","marks":[{"type":"code_inline"}]},{"text":". Set ","type":"text"},{"text":"TOTAL_STAGES","type":"text","marks":[{"type":"code_inline"}]},{"text":" to the number of stages you wrote.","type":"text"}]},{"type":"paragraph","content":[{"text":"Hold the bar the template sets: open the URL before asking for its value, use ","type":"text"},{"text":"ask_secret","type":"text","marks":[{"type":"code_inline"}]},{"text":" for anything secret, ","type":"text"},{"text":"write_env","type":"text","marks":[{"type":"code_inline"}]},{"text":" every persisted value, ","type":"text"},{"text":"set_secret","type":"text","marks":[{"type":"code_inline"}]},{"text":" only the values CI actually needs, and ","type":"text"},{"text":"confirm","type":"text","marks":[{"type":"code_inline"}]},{"text":" before any irreversible action. Each ","type":"text"},{"text":"stage","type":"text","marks":[{"type":"code_inline"}]},{"text":" clears the screen so only the current step is visible: keep a stage to one focused task so nothing the human needs scrolls away. Don't touch the library above the marker.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"4. Verify and hand off","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"bash -n \u003cscript>","type":"text","marks":[{"type":"code_inline"}]},{"text":"; run ","type":"text"},{"text":"shellcheck","type":"text","marks":[{"type":"code_inline"}]},{"text":" if available.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"chmod +x \u003cscript>","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Don't run it end-to-end yourself: it opens browsers and blocks on human input. Trace it statically instead: every value from step 1 is captured and lands where step 1 said, and every ","type":"text"},{"text":"set_secret","type":"text","marks":[{"type":"code_inline"}]},{"text":" name exactly matches a ","type":"text"},{"text":"secrets.*","type":"text","marks":[{"type":"code_inline"}]},{"text":" reference in CI.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Tell the user how to run it. If it's a repeatable setup path, commit it and link it from the README so the next person runs the script instead of asking an AI.","type":"text"}]}]}]}]},"metadata":{"date":"2026-11-02","name":"wizard","author":"@skillopedia","source":{"stars":310004,"repo_name":"skills","origin_url":"https://github.com/mattpocock/skills/blob/HEAD/skills/engineering/wizard/SKILL.md","repo_owner":"mattpocock","body_sha256":"bdf31d48211ea559878f95a4f344aeabf8d85897488ba564382bab0b000daac1","cluster_key":"214025792c58b3c4a2f8fd43cdfbf538f0e2763e636872f63e1385c44a3dbb6f","clean_bundle":{"format":"clean-skill-bundle-v1","source":"mattpocock/skills/skills/engineering/wizard/SKILL.md","text_bytes":9594,"source_commit":"4ae2317ddb22b046e26455e4f9c9b3aaaf62212d","skills_sh_rank":67,"attachment_count":2,"text_attachments":2,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/engineering/wizard/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"devops-infrastructure","category_label":"DevOps"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"devops-infrastructure","import_tag":"skills-sh-top20k-2026-11","description":"Generate an interactive bash wizard that walks a human through steps only they can perform. Use when provisioning infrastructure, setting up credentials or CI secrets, walking an unfamiliar third-party dashboard, or running a one-off migration or cutover. Don't invoke this for steps the agent can perform itself."}},"renderedAt":1793671377842}

Wizard A wizard is a bash script that walks a human, step by step, through a manual procedure that's tedious to do by hand and tedious to re-explain to an AI every time. It opens each URL, says exactly what to click and copy, captures the values, writes them where they belong ( , GitHub secrets), confirms at every stage, and shows how many stages are left. It might configure third-party services, run a one-off migration, or move the project from one state to another. The delightful UX is already solved by template.sh: stage-by-stage progress, confirmation gates, cross-platform URL opening (in…