CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | #!/usr/bin/env bash
# =============================================================================
# Gluecron one-command install.
#
# curl -sSL https://gluecron.com/install | bash
#
# What it does (every step is idempotent + verbose):
# 1. Verify git, curl, jq are on PATH
# 2. Resolve Gluecron host (default https://gluecron.com, env override)
# 3. Locate Claude Desktop config (macOS / Linux / WSL)
# 4. Sign in (env vars or interactive prompt) and capture session cookie
# 5. Mint a fresh PAT via POST /api/v2/auth/install-token
# 6. Merge a 'gluecron' MCP server entry into claude_desktop_config.json
# 7. If we're inside a GitHub-origin repo, offer to import it
# 8. Drop the Claude Code skill bundle into ~/.claude/skills/
# 9. Print a "you're done" success banner
#
# No third-party tools beyond plain curl, jq, git. Idempotent. Safe to re-run.
# =============================================================================
set -euo pipefail
# ── pretty printers (match scripts/bootstrap-hetzner.sh style) ───────────────
say() { printf "\n\033[1;34m> %s\033[0m\n" "$*"; }
ok() { printf " \033[32mv\033[0m %s\n" "$*"; }
warn() { printf " \033[33m!\033[0m %s\n" "$*"; }
fail() { printf " \033[31mx\033[0m %s\n" "$*"; exit 1; }
# ── 1. Prerequisites ────────────────────────────────────────────────────────
say "[1/8] Checking prerequisites"
MISSING=()
for tool in git curl jq; do
if ! command -v "$tool" >/dev/null 2>&1; then
MISSING+=("$tool")
fi
done
if [ "${#MISSING[@]}" -gt 0 ]; then
warn "Missing tools: ${MISSING[*]}"
echo " Install them and re-run, e.g.:"
for tool in "${MISSING[@]}"; do
case "$tool" in
jq) echo " macOS: brew install jq | Debian/Ubuntu: sudo apt-get install -y jq" ;;
git) echo " macOS: xcode-select --install | Debian/Ubuntu: sudo apt-get install -y git" ;;
curl) echo " macOS: (preinstalled) | Debian/Ubuntu: sudo apt-get install -y curl" ;;
esac
done
fail "Please install the missing tools above and re-run."
fi
ok "git, curl, jq present"
# ── 2. Host ─────────────────────────────────────────────────────────────────
say "[2/8] Resolving Gluecron host"
HOST="${GLUECRON_HOST:-https://gluecron.com}"
HOST="${HOST%/}" # strip trailing slash
ok "Using host: $HOST"
# ── 3. Locate Claude Desktop config ────────────────────────────────────────
say "[3/8] Locating Claude Desktop config"
UNAME_S="$(uname -s 2>/dev/null || echo unknown)"
MAC_CONF="$HOME/Library/Application Support/Claude/claude_desktop_config.json"
LINUX_CONF="$HOME/.config/Claude/claude_desktop_config.json"
CLAUDE_CONF=""
case "$UNAME_S" in
Darwin*)
CLAUDE_CONF="$MAC_CONF"
;;
Linux*)
# WSL detection
if grep -qi microsoft /proc/version 2>/dev/null; then
if [ -d "$HOME/.config/Claude" ]; then
CLAUDE_CONF="$LINUX_CONF"
else
CLAUDE_CONF="$LINUX_CONF"
warn "WSL detected but no existing Claude config — using $CLAUDE_CONF"
fi
else
CLAUDE_CONF="$LINUX_CONF"
fi
;;
*)
warn "Unknown platform '$UNAME_S' — defaulting to macOS path."
CLAUDE_CONF="$MAC_CONF"
;;
esac
mkdir -p "$(dirname "$CLAUDE_CONF")"
if [ ! -f "$CLAUDE_CONF" ]; then
echo '{}' > "$CLAUDE_CONF"
ok "Created empty $CLAUDE_CONF"
else
ok "Found existing $CLAUDE_CONF"
fi
# ── 4. Sign in ──────────────────────────────────────────────────────────────
say "[4/8] Signing in to $HOST"
USERNAME="${GLUECRON_USERNAME:-}"
PASSWORD="${GLUECRON_PASSWORD:-}" # secrets-ok: read from env var, not a hardcoded credential
if [ -z "$USERNAME" ]; then
if [ ! -t 0 ]; then
fail "GLUECRON_USERNAME is unset and stdin is not a TTY. Re-run as: GLUECRON_USERNAME=you GLUECRON_PASSWORD=*** curl -sSL $HOST/install | bash"
fi
printf " Gluecron username: "
read -r USERNAME
fi
if [ -z "$PASSWORD" ]; then
if [ ! -t 0 ]; then
fail "GLUECRON_PASSWORD is unset and stdin is not a TTY."
fi
printf " Gluecron password: "
stty -echo
read -r PASSWORD
stty echo
printf "\n"
fi
COOKIE_JAR="$(mktemp -t gluecron-cookies.XXXXXX)"
trap 'rm -f "$COOKIE_JAR"' EXIT
LOGIN_BODY="username=$(printf %s "$USERNAME" | jq -sRr @uri)&password=$(printf %s "$PASSWORD" | jq -sRr @uri)"
LOGIN_STATUS=$(
curl -sS -o /dev/null -w "%{http_code}" \
-X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-c "$COOKIE_JAR" \
--data "$LOGIN_BODY" \
"$HOST/login" || echo 000
)
if ! grep -q "session" "$COOKIE_JAR" 2>/dev/null; then
fail "Login failed (HTTP $LOGIN_STATUS). Check username/password."
fi
ok "Signed in as $USERNAME"
# ── 5. Mint PAT ─────────────────────────────────────────────────────────────
say "[5/8] Minting a fresh PAT"
SHORT_TS=$(date +%s | tail -c 7)
MINT_BODY=$(jq -nc --arg name "gluecron-install-$SHORT_TS" --arg scope "admin" \
'{name: $name, scope: $scope}')
MINT_RESPONSE=$(
curl -sS \
-X POST \
-H "Content-Type: application/json" \
-b "$COOKIE_JAR" \
--data "$MINT_BODY" \
"$HOST/api/v2/auth/install-token"
)
PAT=$(printf %s "$MINT_RESPONSE" | jq -r '.token // empty')
if [ -z "$PAT" ]; then
ERR=$(printf %s "$MINT_RESPONSE" | jq -r '.error // .hint // .')
fail "PAT mint failed: $ERR"
fi
PAT_PREFIX=$(printf %s "$PAT" | cut -c1-12)
ok "Created PAT $PAT_PREFIX..."
# ── 6. Merge MCP server entry into Claude Desktop config ───────────────────
say "[6/8] Wiring Claude Desktop -> Gluecron MCP"
TMP_CONF="$(mktemp -t gluecron-conf.XXXXXX)"
jq --arg url "$HOST/mcp" --arg auth "Bearer $PAT" '
. as $root
| (.mcpServers // {}) as $servers
| $root
| .mcpServers = ($servers + {
"gluecron": {
"transport": "http",
"url": $url,
"headers": { "Authorization": $auth }
}
})
' "$CLAUDE_CONF" > "$TMP_CONF"
mv "$TMP_CONF" "$CLAUDE_CONF"
ok "Updated $CLAUDE_CONF"
# ── 7. Optional repo import ─────────────────────────────────────────────────
say "[7/8] Repo import (optional)"
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
ORIGIN_URL=$(git config --get remote.origin.url || true)
if [ -n "$ORIGIN_URL" ] && printf %s "$ORIGIN_URL" | grep -q "github.com"; then
if [ -t 0 ]; then
printf " Import this repo (%s) to Gluecron? [y/N] " "$ORIGIN_URL"
read -r ANSWER
else
ANSWER="${GLUECRON_IMPORT:-n}"
fi
case "$ANSWER" in
y|Y|yes|YES)
IMPORT_BODY="repo_url=$(printf %s "$ORIGIN_URL" | jq -sRr @uri)"
IMPORT_STATUS=$(
curl -sS -o /dev/null -w "%{http_code}" \
-X POST \
-H "Authorization: Bearer $PAT" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data "$IMPORT_BODY" \
"$HOST/import/github/repo" || echo 000
)
case "$IMPORT_STATUS" in
2*|3*) ok "Import dispatched (HTTP $IMPORT_STATUS)" ;;
*) warn "Import returned HTTP $IMPORT_STATUS — you can re-run from $HOST/import" ;;
esac
;;
*)
ok "Skipped import"
;;
esac
else
ok "No GitHub origin detected — skipping import"
fi
else
ok "Not inside a git repo — skipping import"
fi
# ── 8. Claude Code skill bundle ─────────────────────────────────────────────
# Drop the gluecron-pr / gluecron-issue / gluecron-review skills into
# ~/.claude/skills/ so they appear as slash commands inside Claude Code.
# Idempotent: each write overwrites the existing file.
say "[8/8] Installing Claude Code skill bundle (~/.claude/skills/)"
SKILLS_ROOT="$HOME/.claude/skills"
mkdir -p "$SKILLS_ROOT/gluecron-pr" "$SKILLS_ROOT/gluecron-issue" "$SKILLS_ROOT/gluecron-review"
cat > "$SKILLS_ROOT/gluecron-pr/SKILL.md" <<'GLUECRON_SKILL_PR_EOF'
---
name: gluecron-pr
description: Open, list, fetch, comment on, merge, or close pull requests on a Gluecron-hosted repository. Use this skill whenever the user references a Gluecron repo (origin URL contains "gluecron.com" or matches the GLUECRON_HOST env var) and asks to "open a PR", "merge", "review", "comment on PR #N", "list open PRs", or "close PR #N" on a repo that is NOT hosted on GitHub.
tools:
- gluecron_create_pr
- gluecron_get_pr
- gluecron_list_prs
- gluecron_comment_pr
- gluecron_merge_pr
- gluecron_close_pr
- Bash
---
When invoked, drive the Gluecron MCP write surface to manage pull
requests on the active Gluecron-hosted repo. Detect owner/repo from
`git config --get remote.origin.url` (shapes:
`https://<HOST>/<owner>/<repo>.git`, `git@<HOST>:<owner>/<repo>.git` —
strip the `.git`). Default base branch:
`git symbolic-ref refs/remotes/origin/HEAD` (fall back to `main`).
Always read `git diff origin/<base>...HEAD` before opening a PR so the
title and body match the diff. See the bundled SKILL.md in this repo's
`.claude/skills/gluecron-pr/` for the full recipe and example prompts.
GLUECRON_SKILL_PR_EOF
cat > "$SKILLS_ROOT/gluecron-issue/SKILL.md" <<'GLUECRON_SKILL_ISSUE_EOF'
---
name: gluecron-issue
description: Create, list, comment on, close, or reopen issues on a Gluecron-hosted repository. Use this skill whenever the user is on a Gluecron repo (origin URL contains "gluecron.com" or matches the GLUECRON_HOST env var) and asks to "open an issue", "file a bug", "comment on #N", "close #N", or "reopen #N" on a repo that is NOT hosted on GitHub.
tools:
- gluecron_create_issue
- gluecron_comment_issue
- gluecron_close_issue
- gluecron_reopen_issue
- gluecron_repo_list_issues
- Bash
---
When invoked, drive the Gluecron MCP write surface to manage issues on
the active Gluecron-hosted repo. Detect owner/repo from
`git config --get remote.origin.url`. Common ops: file an issue with a
Markdown body (What happened / Expected / Repro), comment on an existing
issue, close, reopen, list open issues. Never bulk-close more than 5
issues in one tool sequence without re-confirming with the user.
GLUECRON_SKILL_ISSUE_EOF
cat > "$SKILLS_ROOT/gluecron-review/SKILL.md" <<'GLUECRON_SKILL_REVIEW_EOF'
---
name: gluecron-review
description: Act as a secondary AI code reviewer on a Gluecron-hosted pull request. Use this skill when the user asks Claude to "review PR #N", "give a second-opinion review", or "leave inline comments" on a Gluecron pull request. Complements Gluecron's built-in AI review.
tools:
- gluecron_get_pr
- gluecron_list_prs
- gluecron_comment_pr
- Bash
---
When invoked, act as a secondary reviewer on top of Gluecron's built-in
AI review pass (`src/lib/ai-review.ts`, marker
`<!-- gluecron-ai-review:summary -->`). Flow: fetch the PR via
`gluecron_get_pr`, fetch the diff locally via `git diff
origin/<base>...origin/<head>`, post one `gluecron_comment_pr` per
finding (file + line + suggestion), then a summary comment prefixed
with `<!-- claude-secondary-review:summary -->` and a verdict line
("**Verdict:** approved" or "**Verdict:** changes requested"). Do not
call `gluecron_merge_pr` from this skill.
GLUECRON_SKILL_REVIEW_EOF
ok "Wrote $SKILLS_ROOT/gluecron-pr/SKILL.md"
ok "Wrote $SKILLS_ROOT/gluecron-issue/SKILL.md"
ok "Wrote $SKILLS_ROOT/gluecron-review/SKILL.md"
# ── Done ────────────────────────────────────────────────────────────────────
printf "\n"
printf "\033[1;32m============================================================\033[0m\n"
printf "\033[1;32m GLUECRON INSTALL COMPLETE\033[0m\n"
printf "\033[1;32m============================================================\033[0m\n"
printf " Host: %s\n" "$HOST"
printf " PAT prefix: %s...\n" "$PAT_PREFIX"
printf " MCP config: %s\n" "$CLAUDE_CONF"
printf " Skills: %s/{gluecron-pr,gluecron-issue,gluecron-review}\n" "$SKILLS_ROOT"
printf "\n"
printf " v Done. Restart Claude Desktop and try:\n"
printf " \"Open a PR on this repo with a one-line README fix\"\n"
printf "\n"
printf " Tip: if you also use Claude Code in this repo, the\n"
printf " .claude/settings.json at the repo root auto-configures\n"
printf " the Gluecron MCP server. Set GLUECRON_PAT in your shell\n"
printf " and future Code sessions wire up with no further config.\n"
printf "\n"
|