Audience: teams routing TeamCity webhooks to OpenClaw on a remote Mac for preflight, lockfile drift, and summary JSON before heavy agents run. 2026 baseline from docs.openclaw.ai: Node 22+, openclaw onboard (add --install-daemon when you want supervision), loopback gateway plus TLS, launchd health probes. See Jenkins webhook preflight, GitHub lockfile scan, build node guide, help.
  • Controller noise: full TeamCity agents burn minutes downloading mirrors while the real failure was a stale package-lock.json or composer constraint.
  • Webhook forgery: a public URL without header checks lets anyone enqueue expensive clones on your Mac.
  • Sleeping laptops: a developer machine drops TLS mid-flight; a rented remote Mac keeps the OpenClaw listener and logs stable.

Environment and minimal privilege preparation

Install Node 22 LTS (or Node 24 after clean openclaw doctor), install OpenClaw, run openclaw onboard, add --install-daemon if you need a supervised gateway, then clear every doctor warning.

Store TeamCity webhook secrets under ~/.config/openclaw/ at mode 600. Use a dedicated macOS user, bind admin HTTP to 127.0.0.1, terminate TLS on nginx or Caddy.

Control Why it matters Minimal pattern
Node major Doctor checks assume the same runtime as onboarding Pin NODE_BINARY in the launchd plist; avoid nvm-only paths
Health route Detect crashes before TeamCity retries flood operators curl -fsS from LaunchAgent every minute; restart on non-zero
Secrets Leaked tokens let anyone trigger expensive clones One random webhook secret per build chain; rotate after any paste into chat

Least privilege. The Mac account receives webhooks, clones, runs dry-runs, and posts summaries. TeamCity PATs used for REST callbacks should be project scoped with read-only build permissions unless you intentionally write comments.

TeamCity Webhooks, payload fields, and verification checklist

Add the Webhooks feature to the build configuration, point it at your HTTPS URL, trigger on build finished, and send buildId, buildTypeId, branchName, buildStatus, buildStatusUrl.

Send X-Webhook-Secret matching the Mac file. Optional HMAC must hash the raw body bytes. Keep JSON compact—no pretty print.

1
Create the HTTPS endpoint with a random path segment and allow list TeamCity server egress IPs on your reverse proxy.
2
Attach the Webhook feature to the build configuration, not only the template, then run a personal build to capture a sample payload.
3
Map parameters into the JSON body so OpenClaw never guesses branch names from free text.
4
Store the shared secret beside other OpenClaw automation files at mode 600.
5
Verify headers before JSON.parse; reject unknown buildTypeId values with HTTP 401.
6
Replay using curl from the TeamCity host with the same headers to prove DNS, TLS, and MTU paths.
# Pseudocode: const secret = process.env.TC_WEBHOOK_SECRET;
# if (req.headers['x-webhook-secret'] !== secret) return res.sendStatus(401);
# const payload = JSON.parse(req.body); // only after the check

OpenClaw handler: lockfile drift, composer, and npm preflight templates

After auth, mktemp -d under /var/tmp/tc-openclaw, shallow clone the TeamCity commit, run validators, delete the tree each time.

# Lockfile drift (example: compare branch vs main)
git fetch origin main --depth=1
git diff origin/main -- package-lock.json || true

# PHP / Composer (absolute paths for launchd)
composer validate --no-check-publish --no-interaction
composer install --dry-run --no-interaction --no-ansi

# Node / npm
npm ci --dry-run 2>/dev/null || npm install --dry-run --ignore-scripts

Return JSON with ok, buildId, lockfileDrift, logExcerpt. See GitHub Checks lockfile scan for richer patterns.

Build summary feedback, TeamCity REST notes, and retry policy

POST compact JSON to REST, Slack-style webhooks, or internal notifiers with preflightStatus, durationMs, buildId. Scope TeamCity PATs to the smallest project that may read builds or post comments.

Retry three times with two, four, eight second sleeps; curl --max-time 25; log status, retry count, correlation id.

Common error FAQ

TeamCity shows HTTP 401 from OpenClaw

Whitespace in the header value, mismatched header names, or a proxy stripping custom headers. Log header keys only, trim secrets in TeamCity, mirror values in the plist EnvironmentVariables block.

Webhook never fires after successful builds

Feature attached to the wrong configuration, outbound proxy on the TeamCity server, or DNS failures from that host. Replay with curl from the TeamCity machine using identical JSON.

OpenClaw logs 502 while local curl works

TLS mismatch, expired certificate, or the gateway process exited. Run openclaw doctor, confirm launchctl list shows your plist, tail reverse-proxy error logs during one delivery.

npm: command not found under launchd

Interactive shells source nvm or Homebrew paths that launchd ignores. Pin absolute paths to node and npm, set NODE_BINARY, rerun doctor after upgrades.

Summary

Stable order: align Node with openclaw doctor, lock webhook secrets, validate TeamCity headers before parsing JSON, isolate clones, run lockfile plus dry-run gates, then POST summaries with bounded retries.

Rent a remote Mac when you need a 24/7 OpenClaw edge for TeamCity—Apple Silicon stays awake, disks are NVMe friendly, and TLS endpoints stop flapping. Public entry points: home, purchase, help, and the OpenClaw field practice collection on the blog (no login).

MacPull supplies hosted Mac Mini nodes so OpenClaw plus TeamCity webhooks stay dependable for CI preflight and human readable summaries.

Keep your OpenClaw + TeamCity gateway always on

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