Install script
The README recommends reading the installer before you run it. This is the same
scripts/install.sh
served at /install.sh.
Prefer npm? npx robin-review does the same thing — same workflow file, same
skill install — from the robin-review package.
One-liner
Run this from the root of the Git repository you want Robin to review — not from your home directory. The workflow and secrets are installed per repository; the companion agent skill is global per machine.
terminal
$ curl -fsSL https://robinreview.dev/install.sh | bash What it does
- Verifies you're inside a git repository
- Keeps one canonical
.github/workflows/robin.yml - Moves recognized Robin and Universal Code Reviewer workflow variants to
.github/robin-workflow-archive/, where GitHub cannot trigger them - Preserves an existing modern version pin unless
ROBIN_REFoverrides it - Best-effort install of the Robin chat skill via
npx skills add(skip withROBIN_SKILL=0) - Prints next steps for GitHub secrets and your first commit
What it does not do
- No
sudo, no globally installed npm package, no secrets written to disk - Does not globally enable Robin for every repository. Run it once inside each target repository.
- Does not set GitHub secrets for you. Add those in repo settings or with
gh secret set. - Archives recognized old workflows for inspection; removes an active duplicate only when an identical disabled copy already exists
Options
ROBIN_REF=v1pins the action ref written into the workflow (default:main)ROBIN_SKILL=0skips the companion chat skill install
Prefer manual setup? Follow the three-step guide or the README.
scripts/install.sh
bash
#!/usr/bin/env bash
#
# Robin installer — adds the Robin code-review workflow to the current repo.
#
# From the root of the Git repository you want Robin to review:
# curl -fsSL https://robinreview.dev/install.sh | bash
#
# It keeps one canonical .github/workflows/robin.yml. Historical Robin workflow
# variants are archived outside the workflows directory so they cannot trigger,
# then the companion skill is installed or updated globally. No sudo required.
# Override the action ref with ROBIN_REF=v1.
#
set -euo pipefail
REF="${ROBIN_REF:-main}"
WORKFLOW_PATH=".github/workflows/robin.yml"
WORKFLOW_DIR=".github/workflows"
ARCHIVE_DIR=".github/robin-workflow-archive"
info() { printf '\033[0;32m🏹 %s\033[0m\n' "$1"; }
warn() { printf '\033[0;33m🏹 %s\033[0m\n' "$1"; }
die() { printf '\033[0;31m🏹 %s\033[0m\n' "$1" >&2; exit 1; }
git rev-parse --is-inside-work-tree >/dev/null 2>&1 \
|| die "Not a git repository. cd into your repo and run this again."
cd "$(git rev-parse --show-toplevel)"
is_robin_workflow() {
grep -Eiq '^[[:space:]]*(-[[:space:]]*)?uses:[[:space:]]*antongulin/(robin|universal-code-reviewer)(/\.github/workflows/review\.ya?ml)?@[^[:space:]#]+' "$1"
}
is_robin_source_repository() {
[ -f package.json ] && grep -Eq '"name"[[:space:]]*:[[:space:]]*"robin-review"' package.json \
&& [ -f action.yml ] \
&& [ -f skills/robin/SKILL.md ] \
&& [ -f .github/workflows/self-test.yml ]
}
# Treat CRLF and LF workflow copies as equivalent across Git configurations.
files_equal() {
cmp -s <(sed $'s/\r$//' "$1") <(sed $'s/\r$//' "$2")
}
# Preserve an existing modern Robin ref unless ROBIN_REF explicitly overrides it.
if [ -z "${ROBIN_REF+x}" ]; then
ref_source=""
if [ -f "$WORKFLOW_PATH" ] && is_robin_workflow "$WORKFLOW_PATH"; then
ref_source="$WORKFLOW_PATH"
elif [ -d "$WORKFLOW_DIR" ]; then
while IFS= read -r candidate; do
if is_robin_workflow "$candidate"; then
if [ -n "$ref_source" ]; then
ref_source=""
warn "Multiple Robin workflows found; using default ref ($REF)."
break
fi
ref_source="$candidate"
fi
done < <(find "$WORKFLOW_DIR" -maxdepth 1 -type f \( -name '*.yml' -o -name '*.yaml' \) -print)
fi
if [ -n "$ref_source" ]; then
# Preserve refs only from modern Robin workflows. Legacy Universal Code Reviewer
# refs (including obsolete v0 tags) intentionally migrate to the current default.
existing_ref="$(sed -nE 's|^[[:space:]]*(-[[:space:]]*)?uses:[[:space:]]*antongulin/robin/\.github/workflows/review\.ya?ml@([A-Za-z0-9._/-]+).*|\2|p' "$ref_source" | head -n 1)"
if [ -n "$existing_ref" ] && [ "$existing_ref" != "v0" ]; then REF="$existing_ref"; fi
fi
fi
case "$REF" in
*[!A-Za-z0-9._/-]*|'') die "Invalid ROBIN_REF: $REF" ;;
esac
tmp_workflow="$(mktemp)"
trap 'rm -f "$tmp_workflow"' EXIT
# Quoted heredoc: keeps ${{ secrets.* }} literal for GitHub Actions.
cat > "$tmp_workflow" <<'YAML'
# Generated by robin-review. Re-run `npx robin-review` to check for updates.
name: Robin
on:
pull_request:
types: [opened, reopened, ready_for_review]
issue_comment:
types: [created]
permissions:
actions: read
contents: read
pull-requests: write
jobs:
review:
uses: antongulin/robin/.github/workflows/review.yml@__REF__
secrets:
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_BASE_URL: ${{ secrets.LLM_BASE_URL }}
LLM_MODEL: ${{ secrets.LLM_MODEL }}
YAML
tmp_rendered="$(mktemp)"
trap 'rm -f "$tmp_workflow" "$tmp_rendered"' EXIT
sed "s|@__REF__|@${REF}|" "$tmp_workflow" > "$tmp_rendered"
archive_workflow() {
local source_path="$1" base_name destination suffix=1
mkdir -p "$ARCHIVE_DIR"
base_name="$(basename "$source_path")"
destination="$ARCHIVE_DIR/${base_name}.disabled"
while [ -f "$destination" ] && ! files_equal "$source_path" "$destination"; do
destination="$ARCHIVE_DIR/${base_name}.${suffix}.disabled"
suffix=$((suffix + 1))
done
if [ -f "$destination" ]; then
rm -f "$source_path"
info "Removed $source_path (identical copy already at $destination)."
else
mv "$source_path" "$destination"
info "Archived $source_path → $destination (cannot trigger in this location)."
fi
ARCHIVED_WORKFLOW_COUNT=$((ARCHIVED_WORKFLOW_COUNT + 1))
}
WORKFLOW_CHANGED=0
ARCHIVED_WORKFLOW_COUNT=0
SOURCE_REPOSITORY=0
if is_robin_source_repository; then
SOURCE_REPOSITORY=1
warn "Robin source repository detected — leaving its self-test workflows untouched."
if [ -f "$WORKFLOW_PATH" ] && is_robin_workflow "$WORKFLOW_PATH"; then
warn "$WORKFLOW_PATH is a redundant consumer workflow; remove it instead of committing it here."
fi
else
if [ -f "$WORKFLOW_PATH" ] && ! is_robin_workflow "$WORKFLOW_PATH"; then
die "$WORKFLOW_PATH exists but is not a Robin workflow. Move or rename it, then run again."
fi
canonical_current=0
if [ -f "$WORKFLOW_PATH" ] && files_equal "$WORKFLOW_PATH" "$tmp_rendered"; then canonical_current=1; fi
if [ -d "$WORKFLOW_DIR" ]; then
while IFS= read -r candidate; do
if is_robin_workflow "$candidate"; then
if [ "$candidate" = "$WORKFLOW_PATH" ] && [ "$canonical_current" -eq 1 ]; then continue; fi
archive_workflow "$candidate"
WORKFLOW_CHANGED=1
fi
done < <(find "$WORKFLOW_DIR" -maxdepth 1 -type f \( -name '*.yml' -o -name '*.yaml' \) -print)
fi
if [ "$canonical_current" -eq 1 ]; then
info "$WORKFLOW_PATH is already current."
else
mkdir -p "$WORKFLOW_DIR"
mv "$tmp_rendered" "$WORKFLOW_PATH"
info "Created canonical $WORKFLOW_PATH (ref: ${REF})."
WORKFLOW_CHANGED=1
fi
fi
# Install the companion chat skill so any coding agent can automatically drive Robin's
# review loop during ordinary PR work. Uses the cross-platform skills CLI to
# install for every detected agent, globally. Best-effort — the GitHub Action works
# without it. Set ROBIN_SKILL=0 to skip.
install_skill() {
[ "${ROBIN_SKILL:-1}" = "0" ] && return 0
if ! command -v npx >/dev/null 2>&1; then
warn "Skipping companion skill — Node.js/npx not found."
warn "Install it later: npx skills add https://github.com/antongulin/robin --all --global"
return 0
fi
info "Installing the Robin chat skill for all coding agents…"
# --agent '*' = every supported agent, --global = user-level (available everywhere).
if npx -y skills add https://github.com/antongulin/robin --skill robin --agent '*' --global --yes >/dev/null 2>&1; then
info "Robin chat skill installed (all agents). It activates automatically for PR work."
else
warn "Couldn't auto-install the skill. Run: npx skills add https://github.com/antongulin/robin --all --global"
fi
}
install_skill
if [ "$SOURCE_REPOSITORY" -eq 1 ]; then
cat <<EOF
Robin's source repository already reviews itself through Self-Test.
The global companion skill was installed or updated; no consumer workflow is needed here.
EOF
else
cat <<EOF
Next — set three repository secrets (free OpenRouter shown):
gh secret set LLM_API_KEY --body "sk-or-..." # your OpenRouter key
gh secret set LLM_BASE_URL --body "https://openrouter.ai/api/v1"
gh secret set LLM_MODEL --body "openrouter/free"
(no gh CLI? add them at Settings → Secrets and variables → Actions)
Then commit and push:
git add $WORKFLOW_PATH
git commit -m "ci: add Robin code review"
git push
Open a pull request and Robin will review it. Docs: https://robinreview.dev
EOF
if [ "$ARCHIVED_WORKFLOW_COUNT" -gt 0 ]; then
printf '\nInspect .github/robin-workflow-archive, then remove it after confirming the migration.\n'
printf 'Archived files cannot trigger GitHub Actions from there.\n'
fi
fi
Source of truth: https://github.com/antongulin/robin/blob/main/scripts/install.sh · Raw: robinreview.dev/install.sh