--- name: "jenkins-debug" description: "[skaile-development] Debug a recently failed Skaile deployment on Jenkins. Defaults to the `skaile_platform` job; pass `target=store` to debug the `skaile_store` job instead. Reads the job over the local SSH tunnel (http://localhost:8090, anonymous read), finds the relevant build (last failed by default, or current/explicit), extracts the failure region from the console log, cross-references recent commits in skaile-dev around the build timestamp, and reports a structured summary with a fix hypothesis. Use when the user says \"why did the deploy fail\", \"debug the jenkins failure\"\ , \"what broke on jenkins\", \"the platform deploy is red\", \"the store deploy is red\", \"check the last platform-deploy\", or otherwise asks about a Jenkins deployment failure." metadata: tags: - "jenkins" - "deploy" - "ci" - "failure" - "debug" - "platform" - "skaile-development" source: "MERGED" stage: "beta" prerequisites: files: - path: ".git" gate: hard description: "Must run from the skaile-dev shell repo (used for commit cross-reference)." inputs_optional: - id: target label: "Deployment to debug" type: select options: - "platform" - "store" default: "platform" hint: "platform = the `skaile_platform` job | store = the `skaile_store` job" - id: mode label: "Build selection mode" type: select options: - "last-failed" - "current" default: "last-failed" hint: "last-failed = walk recent builds backward until a FAILURE is found | current = inspect lastBuild only and report green if green" - id: build label: "Explicit build number" type: text hint: "If set, overrides `mode` and inspects exactly this build (e.g. 252)." reads: - path: "http://localhost:8090/job//api/json" description: "Recent build list for the selected deploy job (anonymous Jenkins read)." - path: "http://localhost:8090/job///consoleText" description: "Console log of the target build." - path: ".git/logs" description: "Local git history for ±2h commit cross-reference (skaile-dev shell + submodules)." produces: [] user_inputs: dialog: - id: "target" label: "Deployment to debug (platform | store)" type: "select" options: ["platform", "store"] required: false default: "platform" - id: "mode" label: "Build selection mode" type: "select" options: ["last-failed", "current"] required: false default: "last-failed" - id: "build" label: "Explicit build number (overrides mode)" type: "text" required: false files: [] --- ## Overview Investigates a failed Skaile deployment by reading a Jenkins job over the local SSH tunnel and producing a structured failure summary the user (or another agent) can act on without copy-pasting from the Jenkins UI. Two jobs are supported, selected by the `target` input: | `target` | Jenkins job | Deploys | | ------------------ | ----------------- | ------------------------------ | | `platform` (default) | `skaile_platform` | the enterprise platform | | `store` | `skaile_store` | the public AI Asset Catalog | The tunnel forwards the Jenkins controller's port 8080 to `localhost:8090`. Anonymous read is enabled, so this skill never needs credentials. It is strictly read-only — it never triggers builds, modifies Jenkins config, or writes to any Jenkins endpoint. ## When to Use Invoke when the user wants to know what broke on Jenkins, including phrases like: - "why did the deploy fail" - "debug the jenkins failure" - "what broke on jenkins" - "the platform deploy is red" - "the store deploy is red" (pass `target=store`) - "check the last platform-deploy" - "show me the jenkins error" ## When NOT to Use - **The user wants to retrigger a build.** This skill is read-only. Use the Jenkins UI (or a separate skill purpose-built for that) to re-run jobs. - **The failure is in a non-deploy job.** Only `skaile_platform` and `skaile_store` are supported. Other jobs (`portfolex`, `alma`, etc.) are not in scope. - **The user is debugging a local `bun run dev` or test failure.** Use `test`, `kill-backend`, or the relevant package's diagnostic skill instead — Jenkins is not involved. - **The SSH tunnel is not up.** Step 1 fails fast and tells the user; do not attempt to start the tunnel automatically. - **The user wants the Jenkins UI.** Direct them to `http://localhost:8090/job//` in a browser. ## Configuration Hardcoded for this monorepo: | Setting | Value | | ---------------- | ------------------------------------------------------------- | | Jenkins base URL | `http://localhost:8090` | | Job name | `skaile_platform` (default) or `skaile_store` (`target=store`) | | Repo for commits | `.` (the skaile-dev shell repo) | Resolve the job name from the `target` input at the start of the procedure: ```bash case "${TARGET_DEPLOY:-platform}" in store) JOB="skaile_store" ;; platform) JOB="skaile_platform" ;; *) echo "[fail] unknown target '${TARGET_DEPLOY}' (expected platform|store)"; exit 1 ;; esac echo "[ok] debugging job: $JOB" ``` Use `$JOB` everywhere a job name appears below. If the tunnel uses a different port or a job is renamed, edit this section before running. ## Procedure Run these steps in order. Each step prints the data it collects so the user can see the chain of reasoning, not just the final summary. ### Step 1 - Verify the tunnel ```bash curl -sf --max-time 3 http://localhost:8090/api/json > /dev/null \ && echo "[ok] jenkins reachable on :8090" \ || { echo "[fail] jenkins not reachable on :8090 - is the SSH tunnel up?"; exit 1; } ``` If this fails, stop and tell the user to bring the tunnel up. Do not attempt to start it automatically. ### Step 2 - Pick the target build Set `BUILD` (the build number to inspect) based on inputs: Note: the `target` input is read into `TARGET_DEPLOY` (the `JOB` resolver above); `TARGET` below is the build *number*. Do not conflate them. ```bash BASE="http://localhost:8090/job/$JOB" if [ -n "$BUILD" ]; then TARGET="$BUILD" elif [ "${MODE:-last-failed}" = "current" ]; then TARGET=$(curl -s "$BASE/lastBuild/api/json?tree=number" | python3 -c 'import json,sys;print(json.load(sys.stdin)["number"])') else # last-failed: walk recent builds backward until we hit FAILURE TARGET=$(curl -s "$BASE/api/json?tree=builds%5Bnumber,result%5D%7B0,30%7D" \ | python3 -c ' import json, sys data = json.load(sys.stdin) for b in data["builds"]: if b.get("result") == "FAILURE": print(b["number"]); break ') fi [ -n "$TARGET" ] || { echo "[fail] no matching build found"; exit 1; } echo "[ok] inspecting build #$TARGET" ``` If `MODE=current` and `lastBuild.result == SUCCESS`, report "deploy is currently green (build #N succeeded at