Audience: engineers wiring Azure DevOps build completed service hooks to OpenClaw on a remote Mac for dependency prefetch, JSON summaries, and secret checks before heavy work. Focus here is service hook envelopes plus Basic auth as the shared secret, not JetBrains or registry-only webhooks. Baseline: docs.openclaw.ai, Node 22+, openclaw onboard, loopback gateway, TLS in front. More context: gateway security, CodeBuild delivery patterns, GHCR pull matrix.
  • Payload shape: notifications reference resource URLs; commits may need a follow-up REST read or variables you emit from YAML.
  • HTTPS is not auth: add Basic password or proxy-injected headers because Azure egress ranges are broad.
  • Hardware: laptops sleep; a rented remote Mac keeps listeners and logs steady.

2026 gateway baseline: Node, OpenClaw port, and PAT least privilege

Install Node 22 LTS (or Node 24 when openclaw doctor is clean), run openclaw onboard plus optional --install-daemon, then clear warnings.

Read ~/.openclaw/openclaw.json for the real gateway port; 127.0.0.1:18789 is a common default—verify before scripting curl health checks and pin NODE_BINARY in launchd.

Signal Azure DevOps angle Minimal Mac pattern
Secret Service hooks can send HTTP Basic Decode Authorization, timing-safe compare, then parse JSON
PAT Prefetch: Code Read + Build Read ADO_PREFETCH_PAT mode 600, rotate on expiry mail
Network Published Microsoft CIDR ranges Allow list at the edge, still require Basic password

Tip: map the Basic password to one high-entropy shared secret so Azure delivers credentials every call without custom header hacks.

Service hook trigger fields, filters, and verification checklist

Project Settings → Service hooks → Web Hooks → Build completed. Filter to one definition, paste your TLS URL, enable HTTP Basic for the shared secret.

Parse resource for id, buildNumber, status, sourceBranch, requestedFor, url or _links.web.href, definition.id, project.id, repository.id.

1
TLS with random path, preserve raw body bytes for any digest work.
2
Basic auth: static user ado-hook, password equals the shared secret file beside OpenClaw.
3
Sample JSON from hook history after one green build.
4
Auth first, then allow list definition.id and project.id; else HTTP 401.
5
Ack fast, offload prefetch to a worker so Azure never waits on git clone.
6
Replay: curl --user ado-hook:$SECRET --data-binary @sample.json from a hosted agent.
# After TLS terminates, verify Basic before JSON.parse (Node-style sketch)
# const [u,p]=decodeBasic(req.headers.authorization);
# if (u!=='ado-hook' || !timingSafeEqual(p, process.env.ADO_HOOK_SECRET)) return 401;

Executable prefetch commands and disposable workdirs

One temp dir per event: GIT_TERMINAL_PROMPT=0, mktemp, clone with PAT only inside that shell, then rm -rf.

export GIT_TERMINAL_PROMPT=0
WORKDIR=$(mktemp -d /var/tmp/ado-openclaw.XXXXXX)
git -C "$WORKDIR" clone --depth 1 "https://anything:$(printf %s "$ADO_PREFETCH_PAT")@dev.azure.com/org/project/_git/repo" src
cd "$WORKDIR/src" || exit 1
npm ci --dry-run 2>/dev/null || npm install --dry-run --ignore-scripts
pnpm fetch --frozen-lockfile 2>/dev/null || true
composer install --dry-run --no-interaction --no-ansi 2>/dev/null || true
rm -rf "$WORKDIR"
curl -fsS --max-time 8 "http://127.0.0.1:18789/health" || echo "health failed"

Ship exit codes plus a short log tail in summaries; push big logs to object storage.

Build summary JSON, log excerpt template, and retry backoff

POST small JSON to your observability URL or Azure REST only with a narrowly scoped PAT. Include openclawJobId, prefetchMs, optional logSha256 when logs live in blob storage.

read -r -d '' PAYLOAD <<'JSON'
{
  "schema": "macpull.openclaw.prefetch.v1",
  "buildId": 12345,
  "definitionId": 67,
  "status": "prefetch_ok",
  "prefetchMs": 4200,
  "packages": {"npmExit":0,"composerExit":0},
  "logExcerpt": "last 80 lines here...",
  "openclawJobId": "ocw_01jq..."
}
JSON

for s in 2 4 8; do
  curl -fsS --max-time 25 -H "Content-Type: application/json" \
    -H "Authorization: Bearer $SUMMARY_TOKEN" \
    --data-binary "$PAYLOAD" "$SUMMARY_URL" && break
  sleep "$s"
done

Cap at three tries with 2s / 4s / 8s sleeps and respect downstream rate limits.

Azure DevOps + OpenClaw FAQ

Hook shows 200 but Mac is silent

Static 200 from CDN or nginx. Enforce Basic in the app, tail access logs, confirm upstream hits OpenClaw.

Missing commit hash

Use resource.sourceVersion when present; otherwise GET resource.url with a read PAT.

401 to dev.azure.com on summary POST

PAT scopes or expiry. Split read-only prefetch tokens from optional write tokens.

npm not found under launchd

Pin absolute node paths, set NODE_BINARY, rerun openclaw doctor.

Acceptance checklist

openclaw doctor clean, health curl from launchd, hook history shows Basic-authenticated 200, disposable clone works, summary POST succeeds twice, PAT scopes documented, secrets absent from Azure logs.

When you need a stable edge, rent a remote Mac for OpenClaw plus Azure traffic. Entry points: home, purchase, help, blog index (no login).

MacPull hosts Apple Silicon Mac Minis so OpenClaw gateways stay online for Azure DevOps service hooks, prefetch scripts, and bounded summary retries.

Keep your OpenClaw + Azure DevOps gateway always on

Rent a remote Mac Mini for a persistent OpenClaw listener, stable TLS for Microsoft service hooks, and monitored launchd jobs. Jump to home, purchase, help, or the blog index without signing in.