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.jsonor 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.
600.buildTypeId values with HTTP 401.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
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.
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.
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.