writing-skills
writing-skills
Use when creating new skills, editing existing skills, or verifying skills work before deployment
install-script-generatorGenerate cross-platform install scripts for any software or library — a standalone install.sh runnable via a curl/wget one-liner with OS, arch, and package manager detection. Don't use for Dockerfiles, CI/CD pipelines, or one-off shell scripts.
Independent GitHub snapshot · Automated classification · Original documentation governs
Generate robust, cross-platform installation scripts that users can run with a single bash command via GitHub raw URLs. This SKILL.md is a lean index — long templates and tables live under references/ to protect the agent's context budget.
curl | bash one-liner for their project.install.sh that auto-detects OS, arch, and package manager.Skip this skill for Dockerfiles, CI/CD pipelines, or one-off local shell scripts.
<owner>/<repo> (check git remote -v) and a default branch.Makefile, package.json, setup.py, Cargo.toml, go.mod, etc.).python3 is available locally for the helper scripts under scripts/. If python3 is missing, skip each helper-script step, record it as not run (python3 not found), and continue; the run then ends PARTIAL.| File | When to read |
|---|---|
references/install-template.md | When generating install.sh — full bash template with detection helpers, dependency installer, and main entry point |
references/readme-snippet.md | When updating the README — copy-paste install block plus URL format notes |
references/edge-cases.md | When handling unusual OS/sudo/path scenarios and writing step reports |
references/final-report.md | When writing the final report — the four parts, status rules, outcome table, examples, reader checks |
scripts/env_explorer.py | Local environment probe (OS, arch, package managers, sudo) |
scripts/plan_generator.py | Generates installation_plan.yaml from env + target |
scripts/executor.py | Dry-runs installation_plan.yaml with rollback, before Phase 3 generation |
scripts/doc_generator.py | Renders user-facing USAGE_GUIDE.md |
Do not inline these contents into the conversation; link to them to preserve the context window.
Run this once, before Phase 1. Before creating, updating, or deleting files in an existing repo, sync the current branch with remote:
branch="$(git rev-parse --abbrev-ref HEAD)"
git fetch origin
git pull --rebase origin "$branch"
If the working tree is dirty, git stash push -u -m pre-sync first, sync, then git stash pop. If origin is missing or rebase/stash conflicts occur, stop and ask the user before continuing.
A fix attempt is one edit followed by a rerun of the failed check. Stop after 3 fix attempts on the same check, record the check as failed, and continue to the next phase. To stop with BLOCKED, skip the remaining phases and print the final report.
Makefile, package.json, setup.py, Cargo.toml, go.mod, ...).BLOCKED.git remote get-url origin to read <owner>/<repo>.git symbolic-ref --short refs/remotes/origin/HEAD and strip origin/ to read the default branch.BLOCKED.python3 scripts/env_explorer.py to capture OS, arch, package managers, shell, and sudo availability into env_info.json.command -v <dep> check install.sh uses to skip one that is already installed.python3 scripts/plan_generator.py --target "<name>" --env-file env_info.json --deps <dep1> <dep2> ... (dependencies from step 1, space-separated; omit --deps only if there are none) to emit installation_plan.yaml.Install <name> step in installation_plan.yaml: set command, verify, and rollback to the commands install_<tool> will run.# TODO placeholder in the plan. Add a step for each dependency that plan_generator.py warned it left out.python3 scripts/executor.py --plan installation_plan.yaml --dry-run.DRY RUN:, stderr has no placeholder command warning, the steps follow the step 1 order, and every Install ... step has a non-null rollback. The package-manager check and final verify steps carry rollback: null by design. If a check fails, fix the plan and rerun step 6.The dry run skips execution, so it checks the plan's shape, not that installation or rollback actually works.
If install.sh already exists at the repo root, show the user the planned changes and ask before overwriting it. If the user declines, stop with BLOCKED.
Generate install.sh at the repo root using references/install-template.md. The template contains four sections you compose:
info, ok, warn, err, die).detect_os, detect_arch, detect_package_manager, need_sudo).install_deps switch covering apt/dnf/yum/pacman/brew/zypper.install_<tool> (customised per target), verify_installation, and main.Read references/install-template.md for the exact code; do not paste it into chat. If Windows support is needed, also generate install.ps1 (one-liner: irm <raw_url> | iex).
Then check the script. If a check fails, fix install.sh and rerun that check:
bash -n install.sh exits 0.grep -nE '<owner>|<repo>|<branch>|<software_name>|<Software Name>|install_<tool>' install.sh prints nothing.shellcheck is on PATH, shellcheck -S error install.sh exits 0. Otherwise record shellcheck not run (not on PATH).Do not run install.sh on the user's machine: it installs software and may call sudo. Run it only when the user asks for a local run or approves a disposable container. When it runs, its last line must be [ OK ] Installation complete!.
references/readme-snippet.md into the project README, substituting <owner>/<repo>/<branch>. If the repo has no README, create README.md holding only that block.python3 scripts/doc_generator.py --target "<name>" --plan installation_plan.yaml to emit USAGE_GUIDE.md.grep -n "raw.githubusercontent.com/<owner>/<repo>/<branch>/install.sh" <README> with the real values; it must print one or more lines.git ls-tree --name-only origin/<branch> install.sh prints install.sh, run curl -fsSI <raw-url> and record the HTTP status. Otherwise record raw URL not live until install.sh is pushed.Print it once, as plain text in the chat, after the last Step Completion Report. Four parts, in order: Result: (status, target, one-liner), Evidence: (only checks that ran, with results), Uncertainty: (untested behavior, including install.sh was not executed), and Decision: (the approval needed, or No approval needed., then the push and cleanup actions). Read references/final-report.md for each part's contents, the outcome table, and examples.
Apply the first status rule that matches:
BLOCKED — <reason> — install.sh was not written.PARTIAL — <reason> — install.sh was written, and a required check failed or did not run: bash -n, the placeholder grep, shellcheck -S error (when on PATH), the Phase 2 dry run, the README one-liner, USAGE_GUIDE.md, or an approved run of install.sh that did not end with [ OK ] Installation complete!.COMPLETE — every required check passed. COMPLETE does not mean install.sh ran.| File | Description |
|---|---|
install.sh | Primary output — standalone installer for curl | bash |
install.ps1 | Optional Windows PowerShell installer |
USAGE_GUIDE.md | User-facing docs |
env_info.json | Local environment probe (working file) |
installation_plan.yaml | Ordered install steps (working file) |
install_report.md | Dry-run report from executor.py (working file) |
The three working files hold this machine's home path and PATH. Do not commit them unless the user asks; list them under Decision: for cleanup.
install.sh exists at repo root, starts with #!/usr/bin/env bash and set -euo pipefail, and passes the three Phase 3 checks.sudo gracefully (root, sudo, or fail-fast).command -v $TOOL_NAME plus --version when available).curl -sSL ... | bash one-liner that points at the raw GitHub URL for <owner>/<repo>/<branch>.install.sh runs successfully, its last line is [ OK ] Installation complete!.Result: and a status from the rules above, and meets the four reader checks in references/final-report.md: result findable, facts apart from assumptions, claims traceable, next decision clear.See references/edge-cases.md for the full list. Highlights:
die with the detected value; user sees what failed.install_deps aborts with Unsupported package manager 'unknown'.need_sudo exits with Requires root. Run as root or install sudo.install.ps1 separately; install.sh warns under MSYS/Cygwin.install_<tool> from the build file.After each phase, emit a ◆ block with √/× checks and a Result: PASS | FAIL | PARTIAL line; the format and per-phase checks are in references/edge-cases.md.
The final report for a complete run (full example in references/final-report.md):
Result: COMPLETE — mytool installer
curl -sSL https://raw.githubusercontent.com/owner/mytool/main/install.sh | bash
Evidence:
bash -n install.sh: exit 0; placeholder grep: no matches; shellcheck -S error: exit 0
executor.py --dry-run: "DRY RUN: 5 step(s) listed for mytool; nothing was executed."
Uncertainty:
install.sh was not executed. Raw URL not live until install.sh is pushed to main.
Decision: No approval needed.
Remaining action: commit and push install.sh; delete the three working files.
When a user later runs the one-liner, the script's banner ends:
[INFO] OS: linux | Arch: x86_64 | Package Manager: apt
[ OK ] Dependencies installed
[ OK ] mytool 1.2.0 installed
[ OK ] Installation complete!