refactorlab/Andy — PR Handoff by Drift

Andy — PR companion Handoff by Drift. Open-source performance & FinOps platform Zero-config for consumers.

View on GitHub

Trust Signals

Scorecard Score
not yet scored
Maintenance Recency
Activelast commit Jun 22, 2026
License
MIT

Pinned Snippet

workflow.ymlSHA-pinned
uses: refactorlab/drift@d14dad2c6dac83f804be11e5cdf509c1c34a83ed # drift-static-profiler-v0.9.2

tags can be moved; commit SHAs can't. why a SHA?

namedescriptionrequireddefault
greeterName shown in the hello-world line.noandy
profiler-release-tagPin to a specific release tag (e.g. drift-static-profiler-v0.8.1). Default empty → auto-detect the latest non-prerelease release in profiler-repo whose tag matches drift-static-profiler-v* AND has our binary asset attached. Zero-config for most consumers. no""
profiler-repoGitHub repo hosting the drift-static-profiler binary releases.norefactorlab/drift
profiler-local-binPath to a prebuilt drift-static-profiler binary. When set + executable, skips the GitHub Release download. Used by `make hello-test` for local act runs.no""
debugWhen true, sets DRIFT_LOG=info,drift_static_profiler=debug so the scanner emits verbose tracing events to stderr.nofalse
progressWhen true (default), the scanner shows per-phase progress (CliProgress / indicatif). When false, sets DRIFT_PROGRESS=off.notrue
github-tokenToken used to authenticate the GitHub API call when auto-detecting the latest release. Default = the workflow's GITHUB_TOKEN, which consumers get automatically (no setup required). Raises the API rate limit from 60/hr (anonymous, shared) to 5000/hr per consumer. Public release downloads themselves work without a token. no${{ github.token }}
ai-suggestionsWhen true (default), runs a second, AI-powered review pass via `actions/ai-inference@v1` and merges the resulting code suggestions into the single Drift sticky PR comment (rendered as a markdown red/green diff — no second inline review). This is independent of the deterministic scanner review — if the AI step fails (no `models: read` perm, model unavailable, etc.) the scanner review still ships. Consumer workflow must grant: permissions: contents: read pull-requests: write models: read notrue
ai-modelGitHub Models model ID for the AI suggestion pass. Defaults to `openai/gpt-4.1` — broadly served on org inference endpoints and stronger at generating committable code than gpt-4o. The per-suggestion inference loop sends the correct token field automatically — `max_completion_tokens` for reasoning models (gpt-5, o-series), `max_tokens` for classic models (gpt-4.1, gpt-4o). If your org's Models *inference* endpoint does not serve the chosen model, the preflight below catches it and the AI pass skips fail-soft. `openai/gpt-5` is in the global catalog but is NOT served by every org endpoint until an org admin enables it under Settings → Copilot → Policies → Models — override to `openai/gpt-5` once that's done. noopenai/gpt-4.1
ai-endpointGitHub Models inference endpoint. Default `auto` resolves it from the repo owner: ORG-owned repos get the org-scoped endpoint https://models.github.ai/orgs/<org>/inference and user-owned repos get https://models.github.ai/inference. This matters because the built-in GITHUB_TOKEN has no personal identity — in an org repo the user-scoped endpoint returns 403. Set an explicit URL to override. The org must still have GitHub Models enabled under Settings → Copilot → Models, and the workflow must grant `permissions: models: read`. (see docs.github.com/en/rest/models/inference) noauto
ai-max-filesDEPRECATED / unused since the per-suggestion loop landed. Each AI call now diffs exactly ONE focal file, so there is no multi-file context bundle to cap. Kept for backward compatibility; setting it has no effect. Loop size is governed by `ai-max-suggestions`. no20
ai-max-suggestionsHard cap on the number of AI code suggestions, end-to-end. Used in TWO places to keep the model's prompt inside its token budget: - INPUT: the top-N highest-confidence scanner findings handed to the model as focal points (→ AI_MAX_FOCAL_POINTS). Capping this is what keeps the request body under the 8000-token gpt-4o input limit on GitHub Models. - OUTPUT: suggestions actually posted to the PR, applied AFTER the quality bar (confidence, reference, category). The per-suggestion inference loop runs strictly ONE focal point at a time (never in parallel) — see step 11. Defaults to 1: a single focused AI suggestion beats a batch that gets skimmed and ignored. no1
max-code-suggestionsHard cap on the number of SCANNER code suggestions kept in the report BEFORE any consumer (sticky PR comment, inline review, AI focal-point picker) reads it. The scanner itself emits suggestions uncapped (severity_rank DESC + confidence DESC), and 500-entry reports are common on large refactors. Without this cap the sticky PR comment overflows GitHub's 65 536-byte limit and the size guard collapses sections / hard-cuts the body with a "report truncated" footer — losing information silently. Defaults to '10' — the top-10 highest-priority suggestions fit under the sticky comment's 60 KB budget with room for the value card, risks, architecture, and the call-graph diagram. Applied via `jq` in a dedicated cap step right after the scan, so every downstream consumer (sticky comment, deterministic + AI inline review, AI focal-point picker) reads the SAME capped list. no10
fail-thresholdNOTE (current): failing is GLOBALLY DISABLED — Drift NEVER fails a PR regardless of this value (DRIFT_FAILS_PR=false in the action bundle), so this input is inert for now. The semantics below apply only once that switch is flipped back on. Optional. The number of product-correctness (category B) issues — those that clear the quality bar — ABOVE WHICH the check fails (red ✗). <empty> — never fail the PR (default). Drift is advisory: issues post as ⚠️ warnings in the sticky comment and as ::warning:: annotations, and the PR stays green. 0 — fail if there is ANY product-correctness issue. 3 — fail only if there are MORE THAN 3 such issues. Left empty by default so Drift NEVER fails a consumer's PR. A non-numeric value is ignored (treated as empty) and never raises — the action is fail-soft on its own errors too. no""
open-issueWhen 'true', Drift opens — or updates — a single GitHub Issue summarising THIS PR's findings, deduplicated per-PR via a hidden marker so repeated runs refresh the same issue instead of spamming new ones. Default 'false'. Primarily driven by the `/drift issue` comment command (see examples/drift-on-comment.yml), which sets this to 'true'. REQUIRES the consumer workflow to grant `permissions: issues: write`. Without it the issues.create/update call returns 403 ("Resource not accessible by integration") — which Drift swallows fail-soft, so the sticky comment, inline review, and check run still ship. nofalse
audio-summaryWhen true (default), synthesize a spoken WAV summary of the PR with Kokoro (offline neural TTS, run via the self-contained sherpa-onnx `sherpa-onnx-offline-tts` binary), upload it as a NON-ZIPPED workflow artifact (actions/upload-artifact@v7 with `archive: false`), and link that raw .wav at the END of the Drift sticky comment (posted via Octokit in dist/index.js). The link is the .wav file itself — NOT a zip; on a browser that plays audio/wav natively it streams in-tab, otherwise it downloads the bare .wav (no unzip step). Needs no extra permissions. The spoken TEXT is, by preference, an AI-written handover briefing: a < 300-word, read-aloud script covering the PR's story, its main code locations, risks, and follow-up work. It is generated by one inline GitHub Models call (curl + jq in the briefing step) over the PR title, description, commit history, and diff — so it reuses `ai-model` / `ai-endpoint` and needs the same `models: read` permission as `ai-suggestions`. When Models is unreachable (no `models: read`, model unavailable, network) OR the call's 3 retries all come back empty, the action FALLS BACK to a deterministic, spoken-style briefing built from the PR's commit messages + changed-file churn, so a throttled run still ships audio. Both texts pass through the same TTS sanitiser + sentence cap, so the synthesizer's limits hold regardless of source. If even the commit history is empty, audio is skipped (no title-only substitute). Fully fail-soft: any briefing / TTS / download / upload error is a ::warning:: and never breaks the review. The sherpa-onnx binary AND the Kokoro model are cached across runs, so a warm run adds only synthesis time. notrue
tts-voiceKokoro voice NAME to speak the summary in, from the kokoro-multi-lang-v1_0 catalog. Naming is `<lang><sex>_<name>` where lang a=American / b=British, sex f=female / m=male. The name is mapped to the model's integer speaker id at synth time (see the voice→sid table in the synthesis step). Defaults to af_heart, the only A-grade (highest training-quality) Kokoro voice. An unknown name is fail-soft: the synth step falls back to af_heart with a ::warning::. Available voices (English): American female: af_heart (default, A-grade), af_bella, af_nicole, af_sarah, af_sky, af_alloy, af_aoede, af_jessica, af_kore, af_nova, af_river American male: am_michael (warm, narration), am_adam, am_echo, am_eric, am_fenrir, am_liam, am_onyx, am_puck, am_santa British female: bf_emma, bf_alice, bf_isabella, bf_lily British male: bm_george, bm_daniel, bm_fable, bm_lewis Override per-repo via the `with:` block (see examples/drift.yml) or per-run via a comment: `/drift tts-voice=am_michael`. noaf_heart
sherpa-onnx-versionk2-fsa/sherpa-onnx release TAG for the prebuilt offline-TTS binary (`sherpa-onnx-offline-tts`). On Linux runners we fetch the CPU `shared` assets: `sherpa-onnx-<tag>-linux-x64-shared.tar.bz2` (X64) or `sherpa-onnx-<tag>-linux-aarch64-shared-cpu.tar.bz2` (ARM64). Each expands to a top-level dir with `bin/sherpa-onnx-offline-tts` plus a `lib/` of shared objects (libonnxruntime.so, libsherpa-onnx-*.so). Pinned + SHA256-verified below. nov1.13.2
sherpa-onnx-sha256-x86_64SHA256 of `sherpa-onnx-<version>-linux-x64-shared.tar.bz2`. sherpa-onnx publishes no per-asset checksums, so this pin is the only supply-chain control on the binary itself. On mismatch the action emits ::warning:: and skips extraction — fail-soft (the PR review still ships, just without audio). Set to empty string to opt out of the check. no1ef6741535f7af4d69e394fd440a807108036d26ed4f542660191019da5c0daa
sherpa-onnx-sha256-aarch64SHA256 of `sherpa-onnx-<version>-linux-aarch64-shared-cpu.tar.bz2`. Same fail-soft semantics as the x86_64 variant. nob54178420e9e6ff6c7f308b5f1cde827215b38393356ee0bd2b7595c648b330b
kokoro-modelKokoro model archive name from the sherpa-onnx `tts-models` release. Default `kokoro-multi-lang-v1_0` is FULL-PRECISION fp32 (~333 MB archive, `model.onnx` ~311 MB) with 53 voices including af_heart — highest Kokoro fidelity (no quantization), and on CPU it benchmarks AS FAST OR FASTER than the int8 build (onnxruntime's fp32 GEMM path is well-optimized). The archive bundles `voices.bin`, `tokens.txt` and `espeak-ng-data`, so no system espeak-ng install is needed. To trade fidelity for a smaller cache (~126 MB), set `kokoro-int8-multi-lang-v1_0` + its SHA instead. Downloaded from `github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/<name>.tar.bz2`. NOTE: `*-v1_1` is the Chinese-specialised `v1.1-zh` model (different voice set, no af_heart) — do NOT use it for English summaries. nokokoro-multi-lang-v1_0
kokoro-model-sha256SHA256 of the `<kokoro-model>.tar.bz2` archive. Verified before extraction; on mismatch the action warns and skips audio (fail-soft). Set to empty string to opt out. Bump in lockstep with `kokoro-model`. (int8 build SHA: 75654a84864be26f345f020f4070c2c019e96dd1b7f9bf6e2ffd59efac6aa5a3) noc133d26353d776da730870dac7da07dbfc9a5e3bc80cc5e8e83ab6e823be7046
pr-numberPR number. Empty → derived from the event payload (pull_request or issue_comment).no""
base-shaBase SHA of the PR diff. Empty → derived from the event payload (or a REST call on issue_comment).no""
head-shaHead SHA of the PR diff. Same fallback chain as base-sha.no""
pr-titlePR title (used by the AI briefing + permalink line). Same fallback chain.no""
pr-bodyPR body (used by the AI briefing). Same fallback chain.no""
start-on-pr-commentWhen 'true', ENABLES the `/drift` PR-comment trigger ON TOP OF the normal pull_request flow. The flag is ADDITIVE — turning it on does NOT disable scans on push / PR opened / synchronize / reopened. On a `/drift` comment the action also: • Reacts 👀 to acknowledge the command. • Parses /drift overrides from the comment body (debug, ai-model, …). • Resolves PR SHAs via REST; reacts 😕 and exits on closed/merged PRs. • Checks out the PR head by IMMUTABLE SHA (fork-safe). • Runs the scan + posts the review. • Reacts 🚀 on success / 👎 on failure. Recommended wiring: a SINGLE workflow file with both `on: pull_request` and `on: issue_comment`, setting `start-on-pr-comment: true`. The action handles each event correctly (comment-only steps stay gated behind the /drift gate; pull_request events skip them and scan directly). When 'false' (default) the action runs only on pull_request events as it always has. nofalse

no outputs