idlewatch
v0.1.9
Published
Host telemetry collector for IdleWatch
Readme
idlewatch
Telemetry collector for IdleWatch.
Install / Run
npm install -g idlewatch
idlewatch --helpOr run it directly with npx:
npx idlewatch --help
npx idlewatch quickstart
npx idlewatch --dry-runquickstart is the happy path: create an API key on idlewatch.com/api, run the wizard, pick a device name + metrics, and IdleWatch saves local config before sending a first sample. It prefers a bundled TUI binary when available, otherwise falls back to a local Cargo build only on developer machines that already have Cargo installed. Use idlewatch quickstart --no-tui to skip the TUI and stay on the plain text setup path.
CLI options
quickstart: run first-run enrollment wizard--help: show usage--dry-run: collect one sample and exit without remote writes--once: collect one sample, publish it using the active configured path, then exit
Reliability improvements
- Local NDJSON durability log at
~/.idlewatch/logs/<host>-metrics.ndjson(override viaIDLEWATCH_LOCAL_LOG_PATH) - Retry-once+ for transient publish failures (cloud ingest and Firebase paths)
- Non-overlapping scheduler loop (prevents concurrent sample overlap when host is busy)
- Non-blocking CPU sampling using per-tick CPU deltas (no
Atomics.waitstall) - Darwin GPU probing fallback chain (AGX/IOGPU
ioreg→powermetrics→topgrep) with provenance fields (gpuSource,gpuConfidence,gpuSampleWindowMs) - macOS memory pressure enrichment via
memory_pressure -Q(memPressurePct,memPressureClass,source.memPressureSource)
macOS GPU support matrix (observed)
The collector is tuned for these macOS probe paths by platform:
- Apple Silicon (AGX/iGPU): prefer
ioregperformance statistics (AGX) first for live GPU utilization. - Intel Macs: prefer
powermetricsif permission profile allows; fall back totopparser. - Unsupported hosts / older macOS: emit
gpuSource: "unavailable"withgpuConfidence: "none"and clear source metadata.
Use gpuSource + gpuConfidence in dashboards to decide whether to trust values:
high: authoritative per-command path for host classmedium: derived/proxied path with best-effort parsinglow: constrained probe pathnone: no usable sample for that sample window
Quickstart
Recommended: guided enrollment
npx idlewatch quickstartidlewatch is the primary package/command name. idlewatch-skill still works as a compatibility alias, but treat it as legacy in user-facing docs.
The wizard keeps setup small:
- asks for a device name
- asks for your API key from
idlewatch.com/api - lets you choose which metrics to collect
- saves local config to
~/.idlewatch/idlewatch.env - sends a first sample so the device can link right away
The saved config is auto-loaded on later runs, so you should not need to manually source the env file in normal use.
Then run a one-shot publish check any time with:
idlewatch --onceAdvanced Firebase wiring
Manual wiring
export FIREBASE_PROJECT_ID=your-project
export FIREBASE_SERVICE_ACCOUNT_FILE="$HOME/.idlewatch/credentials/your-project-service-account.json"Raw JSON and base64 are still supported for compatibility, but file-path credentials are preferred:
export FIREBASE_SERVICE_ACCOUNT_JSON='{"type":"service_account",...}'
# or
export FIREBASE_SERVICE_ACCOUNT_B64=$(base64 -i serviceAccount.json)Firestore emulator mode (no service-account JSON required):
export FIREBASE_PROJECT_ID=idlewatch-dev
export FIRESTORE_EMULATOR_HOST=127.0.0.1:8080Least-privilege guidance:
- Create a dedicated IdleWatch writer service account per environment/project.
- Grant only the Firestore write scope needed for
metricsingestion (avoid Owner/Editor roles). - Store credentials as a file with user-only permissions (
chmod 600) and reference viaFIREBASE_SERVICE_ACCOUNT_FILE.
If Firebase env vars are incomplete or invalid, the CLI exits with a clear configuration error.
If Firebase vars are omitted entirely, it runs in local-only mode and prints telemetry to stdout.
firebase-admin is loaded lazily only when Firebase publish mode is configured, so dry-run/local-only flows remain resilient in minimal packaged/runtime environments.
Set IDLEWATCH_REQUIRE_FIREBASE_WRITES=1 to fail fast when running --once without a working Firebase publish path.
Validation helpers:
npm run validate:onboardingvalidates non-interactive quickstart enrollment output (env + secure credential copy).npm run validate:firebase-emulator-modeverifies emulator-only config wiring in dry-run mode.npm run validate:firebase-write-onceperforms a single real write attempt (use with emulator or production credentials).npm run validate:firebase-write-required-onceis the strict variant and fails fast unless a Firebase write path is configured and successful.npm run validate:openclaw-usage-healthvalidates that dry-run telemetry stays onsource.usage=openclawwith healthy integration/ingestion in OpenClaw-required mode (mocked CLI probe path).npm run validate:openclaw-stats-ingestionvalidatesopenclaw stats --json-only payload ingestion (mocked CLI probe fallback path), coveringstatus.result.stats.current,status.current.stats.current, and adjacent legacy variants, including millisecond timestamp aliases (usage_ts_ms,usage_timestamp_ms,updated_at_ms,ts_ms).npm run validate:openclaw-release-gatesvalidates host OpenClaw checks (validate:openclaw-usage-health,validate:openclaw-stats-ingestion, andvalidate:openclaw-cache-recovery-e2e) in one gate.npm run validate:openclaw-release-gates:allruns host OpenClaw checks, and on macOS also appends packaged reuse checks (validate:packaged-openclaw-release-gates:reuse-artifact) before proceeding.npm run validate:packaged-artifactvalidates a reusabledist/IdleWatch.appbefore running any:reuse-artifactvalidator (metadata integrity, launcher executability, and matching source commit with currentHEADby default).- Disable commit matching for one-off local experiments by setting
IDLEWATCH_REQUIRE_SOURCE_COMMIT_MATCH=0. - If the artifact lacks
sourceGitCommit, validation fails fast in strict mode; setIDLEWATCH_ALLOW_LEGACY_SOURCE_GIT_COMMIT=1only as a temporary compatibility bridge while you repackage. - If the reuse gate requires bundled runtime, use
npm run validate:packaged-artifact:bundled-runtime.
- Disable commit matching for one-off local experiments by setting
npm run validate:packaged-openclaw-stats-ingestionvalidates packaged-app stats fallback ingestion under a mockedopenclawbinary (end-to-end packaged dry-run +stats --jsoncommand selection), includingstatus.result,status.current, and timestamp alias payload variants (usage_ts_ms,usage_timestamp_ms,usage_timestamp,usageTime,updated_at_ms,ts_ms,ts).npm run validate:packaged-openclaw-cache-recovery-e2evalidates packaged-app stale-cache recovery behavior with temporary probe failures and reprobe refresh logic.npm run validate:packaged-openclaw-release-gatesvalidatesvalidate:packaged-usage-health,validate:packaged-openclaw-stats-ingestion, andvalidate:packaged-openclaw-cache-recovery-e2etogether as one release gate.npm run validate:packaged-openclaw-release-gates:allruns both fresh-package and reuse-artifact OpenClaw packaged checks (for local validation when packaging cost is acceptable).npm run validate:packaged-openclaw-release-gates:reuse-artifactvalidates the same three checks against an already-packaged artifact (IDLEWATCH_SKIP_PACKAGE_MACOS=1) and is the command used in CI/release smoke for repeatable execution.npm run validate:packaged-openclaw-release-gates:reuse-artifactand all packaged:reuse-artifactvalidators now run throughvalidate:packaged-artifactfirst, so stale artifacts from older commits fail fast with a rebuild hint.
npm run validate:packaged-openclaw-robustnessruns the full packaged resilience slice in one command (packaged-usage-age-slo,packaged-usage-alert-rate-e2e,packaged-usage-probe-noise-e2e,packaged-openclaw-release-gates).npm run validate:packaged-openclaw-robustness:reuse-artifactruns the same resilience slice against an already-packaged artifact.
OpenClaw usage ingestion (best effort)
By default (IDLEWATCH_OPENCLAW_USAGE=auto), the agent attempts to read OpenClaw
session usage from local CLI JSON endpoints when available, then enriches samples with.
Binary resolution order for the OpenClaw probe:
IDLEWATCH_OPENCLAW_BIN(if set)IDLEWATCH_OPENCLAW_BIN_HINT(legacy packaged-launcher hint)/opt/homebrew/bin/openclaw/usr/local/bin/openclawopenclaw(PATH lookup)
Successful probe command/args are cached for the life of the process so subsequent samples and forced stale-threshold refreshes reuse the known-good command first before full probe sweep.
IDLEWATCH_OPENCLAW_BINoptionally pins the exact OpenClaw binary path for packaged/non-interactive runtimes.IDLEWATCH_OPENCLAW_BIN_STRICT=1(optional) limits probing to only the explicit bin above when set, useful for deterministic tests. IfIDLEWATCH_OPENCLAW_BINis unset,IDLEWATCH_OPENCLAW_BIN_HINTis used as the explicit fallback in strict mode for launcher compatibility.IDLEWATCH_OPENCLAW_BIN_HINTis also supported for launcher compatibility in existing packaged flows.IDLEWATCH_NODE_BINoptionally pins the Node binary used by packaged app launcher (IdleWatch.app).IDLEWATCH_NODE_RUNTIME_DIRoptionally bundles a portable Node runtime intoIdleWatch.app(<runtime>/bin/noderequired) so installed apps can run on hosts without a global Node install.OpenClaw probe command preference used by the agent (first successful parse wins):
status --jsonusage --jsonsession status --jsonsession_status --jsonstats --json(fallback compatibility for CLI variants) (default:max(IDLEWATCH_INTERVAL_MS*3, 60000)).
IDLEWATCH_USAGE_NEAR_STALE_MScontrols "aging" classification before stale (default:floor((IDLEWATCH_USAGE_STALE_MS + IDLEWATCH_USAGE_STALE_GRACE_MS)*0.85)).IDLEWATCH_USAGE_STALE_GRACE_MSadds a grace window beforeusageIntegrationStatusflips tostale(default:min(IDLEWATCH_INTERVAL_MS, 10000)).IDLEWATCH_OPENCLAW_MAX_OUTPUT_BYTEScaps OpenClaw probe output capture size for each command (default:2097152/ 2MB). Increasing helps on noisy terminals, reducing ENOBUFS-like parse failures.IDLEWATCH_OPENCLAW_MAX_OUTPUT_BYTES_HARD_CAPsets the upper ceiling for adaptive output-buffer retries when the command output exceeds the base cap (default:16777216/ 16MB). Keep this conservative in shared/legacy environments to avoid memory spikes from runaway process logs.Probe output parsing merges both stdout and stderr in the probe collector, so mixed-output CLIs that print progress in stdout but emit JSON in stderr still parse successfully in one sweep.
IDLEWATCH_OPENCLAW_PROBE_RETRIESretries full OpenClaw probe sweeps after the first pass to reduce transient command failures (default:1).IDLEWATCH_USAGE_REFRESH_REPROBEScontrols how many extra forced uncached reprobes run after crossing stale threshold (default:1, total attempts = reprobes + initial refresh).IDLEWATCH_USAGE_REFRESH_DELAY_MSwaits between forced stale-threshold reprobes (default:250).IDLEWATCH_USAGE_REFRESH_ON_NEAR_STALEtriggers proactive refresh when usage is near-stale to reduce stale flips in long packaging/QA loops (default:1).IDLEWATCH_USAGE_IDLE_AFTER_MSdowngrades stale activity alerts toactivity-idlestale usage after a failed freshness refresh now downgrades to
activity-no-new-usage(ingestion healthy, but no newer usage observed) notice state after prolonged inactivity (default:21600000= 6h).IDLEWATCH_OPENCLAW_LAST_GOOD_MAX_AGE_MSreuses the last successful OpenClaw usage snapshot after transient probe failures for up to this age (default:max(stale+grace, 120000)).IDLEWATCH_OPENCLAW_LAST_GOOD_CACHE_PATHpersists/reuses the last-good OpenClaw usage snapshot across process restarts (default: OS temp dir path keyed by host).tokensPerMin: explicit rate if available from OpenClaw, otherwise derived fromtotalTokens / ageMinutesfor the selected recent session.openclawModel: active model name (from the selected recent session or defaults).openclawTotalTokens: total tokens for the selected recent session.openclawSessionId,openclawAgentId,openclawUsageTs: stable identifiers + timestamp alignment fields.openclawUsageAgeMs: derived age of usage snapshot (sampleTs - openclawUsageTs) when available, wheresampleTsis the end-of-sample collector timestamp.tsand fleetcollectedAtMsare the same collection timestamp (end of the collect cycle), which is typically a few milliseconds after final probe completion.
Selection logic for openclaw status --json:
- Pick the most recently updated session among entries with non-null
totalTokensandtotalTokensFresh !== false. - Fallback to the most recently updated session among entries with non-null tokens.
- Fallback to the most recently updated session entry.
Source metadata fields:
source.usage:openclaw | disabled | unavailablesource.usageIntegrationStatus:ok | stale | disabled | unavailablesource.usageIngestionStatus:ok | disabled | unavailable(probe/path health independent of usage age).source.usageActivityStatus:fresh | aging | stale | unknown | disabled | unavailable(age-based activity state).source.usageAlertLevel:ok | notice | warning | critical | off(operator-facing alert severity derived from ingestion + activity semantics).source.usageAlertReason:healthy | activity-idle | activity-near-stale | activity-past-threshold | activity-stale | activity-no-new-usage | ingestion-unavailable | usage-disabled.source.usageFreshnessState:fresh | aging | stale | unknownsource.usageNearStale: boolean early warning signal when age crosses near-stale threshold.source.usagePastStaleThreshold: boolean showing age crossed stale threshold (before grace).source.usageRefreshAttempted: true when collector forced stale-threshold refresh logic.source.usageRefreshRecovered: true when forced refresh recovered below stale-threshold crossing.source.usageRefreshAttempts: number of forced refresh attempts actually executed.source.usageRefreshReprobes: configured extra forced reprobes (IDLEWATCH_USAGE_REFRESH_REPROBES).source.usageRefreshDelayMs: configured delay between reprobes (IDLEWATCH_USAGE_REFRESH_DELAY_MS).source.usageRefreshDurationMs: total elapsed ms spent in the stale-threshold/proactive refresh path when triggered.source.usageRefreshOnNearStale: whether near-stale proactive refresh is enabled (IDLEWATCH_USAGE_REFRESH_ON_NEAR_STALE).source.usageIdle: boolean indicating usage age crossed idle window (IDLEWATCH_USAGE_IDLE_AFTER_MS).source.usageCommand: command used (openclaw status --json, etc.)
OpenClaw parsing hardened in this release:
- stringified numeric fields (for example
"totalTokens": "12345"or"updatedAt": "1771278999999") are now accepted - mixed timestamp names, epoch-seconds variants (
1771278800), and alternate session container keys are supported - wrapped status payload shapes (
resultroot object,data.resultwrappers, top-levelsessionsarray, nested usage totals/totalsobject) are supported with precedence-aware session selection - timestamp aliases in both
snake_caseand millis variants are normalized (for exampleusage_ts,usage_ts_ms,usage_timestamp,usage_timestamp_ms,updated_at_ms,ts_ms) so parser keeps working across CLI serializers - direct session object payloads (
session,activeSession,currentSession) are now handled alongside array/map forms - sessions as arrays are supported (for example
status.stats.current.sessions) in addition to map/objectsessionscontainers - sessions maps keyed by session id are supported (
sessionsas object map) to avoid regressions on alternate OpenClaw serializers - metadata keys like
sessions.defaultsare ignored during session-map selection so tokenized sessions are not shadowed by defaults payloads - stale-token markers like
"totalTokensFresh": "false"are correctly interpreted as freshness metadata rather than causing parser failure source.usageProbeResult:ok | fallback-cache | disabled | command-missing | command-error | parse-error | unavailable.source.usageProbeAttempts: number of probe attempts in the current refresh window.source.usageProbeSweeps: number of probe sweeps performed in the current refresh window.source.usageProbeRetries: configured retry count (IDLEWATCH_OPENCLAW_PROBE_RETRIES).source.usageProbeError: compact failure reason when probing fails.source.usageUsedFallbackCache: boolean indicating whether last-good usage cache was used this sample.source.usageFallbackCacheAgeMs: age of fallback cache snapshot when used, otherwisenull.source.usageFallbackCacheSource:memory | disk | nullindicating fallback cache origin.source.usageStaleMsThreshold: threshold used for stale classification.source.usageNearStaleMsThreshold: threshold used for aging classification.source.usageStaleGraceMs: grace window before stale status activation.source.usageIdleAfterMsThreshold: threshold used to classify prolonged inactivity.source.memPressureSource:memory_pressure | unavailable | unsupported.
Memory field semantics:
memPctandmemUsedPct: host memory used percent ((total - free) / total) retained for backward compatibility.memPressurePct: macOS pressure estimate derived frommemory_pressure -Qoutput when available.memPressureClass:normal | warning | critical | unavailableusing thresholds<75,75-89.99,>=90.
Alerting guidance (recommended):
- Prefer
memPressureClassas the primary memory alert signal. - Suggested warning threshold: trigger when
memPressureClass=warningfor 3+ consecutive samples. - Suggested critical threshold: trigger immediately when
memPressureClass=critical, or whenmemPressurePct>=90for 2+ consecutive samples. - Keep
memPct/memUsedPctas informational context only (do not page solely on these). - For OpenClaw reliability alerts, page on
source.usageIngestionStatus=unavailable(or sustained probe failures), not onusageActivityStatus=stalealone. - If you want one-field routing in dashboards, use
source.usageAlertLevel: page oncritical, ticket on sustainedwarning, and keepnoticeinformational.
Usage field semantics:
openclawTotalTokens: session-level cumulative total tokens reported by OpenClaw.tokensPerMin: reported directly by OpenClaw when available; otherwise derived fromopenclawTotalTokens / session age minutes.- Additional parser compatibility covered for data-wrapper/session wrapper stats payloads (
payload,data.result,data.stats,result), directcurrentpayloads (current,data.current,result.current,status.current,payload.current) and snake_case session aliases under status-like envelopes (for examplecurrent_session,active_session,session_id,agent_id,default_model,usage_ts,recent_sessions) so common OpenClaw CLI variants map into a stable row shape. - Prompt/completion token fields and request/min are not currently exposed as first-class metrics in IdleWatch rows; keep
null/absent rather than synthesizing fake values.
If OpenClaw stats are unavailable, usage fields are emitted as null and collection continues.
Set IDLEWATCH_OPENCLAW_USAGE=off to disable lookup.
Packaging scaffold
DMG release scaffolding is included:
docs/onboarding-external.md(external-user quickstart + signed DMG rollout)docs/packaging/macos-dmg.mdscripts/package-macos.sh- Produces
dist/IdleWatch.app/Contents/Resources/packaging-metadata.jsonwith build provenance for QA/supportability.
- Produces
scripts/build-dmg.shnpm run validate:trusted-prereqs(local preflight for signing identity + notary profile)npm run validate:dmg-checksum(verifies SHA-256 checksum generated bypackage:dmg)npm run package:trusted(strict signed + notarized local path)npm run package:release(trusted packaging + checksum validation in one step).github/workflows/release-macos-trusted.yml(signed + notarized CI path)- CI dry-run schema gates via
npm run validate:dry-run-schemaandnpm run validate:packaged-dry-run-schema(packaged validator auto-rebuildsIdleWatch.appfirst to avoid stale-artifact mismatches) - Usage freshness transition gate via
npm run validate:usage-freshness-e2e(simulates long-window aging→stale transitions end-to-end) - Usage alert-rate quality gate via
npm run validate:usage-alert-rate-e2e(asserts typical low-traffic ages stayusageAlertLevel=ok, with deterministic boundary escalation) - Packaged usage alert-rate gate via
npm run validate:packaged-usage-alert-rate-e2e(verifies alert transitions in packaged launcher runtime path) - Packaged usage-age SLO gate via
npm run validate:packaged-usage-age-slo(requires OpenClaw usage and enforcesopenclawUsageAgeMs <= 300000on packaged dry-run) - Dry-run gate timeout via
IDLEWATCH_DRY_RUN_TIMEOUT_MS(default:15000)- Applied by
scripts/validate-dry-run-schema.mjsto all--dry-runschema checks (direct and packaged). - On timeout, validators keep the latest captured row and still validate it when possible, preventing hangs on non-terminating launcher output.
- Validation parsers now use a shared noise-tolerant JSON extractor (
scripts/lib/telemetry-row-parser.mjs) that ignores ANSI/control noise and selects the latest valid JSON candidate in mixed stdout/stderr logs. - Packaged runtime/DMG validators (
validate:packaged-bundled-runtime,validate:dmg-install) default this to90000while release-gate helpers (validate:openclaw-release-gatesandvalidate:packaged-openclaw-release-gates) default to60000for parity with host checks.
- Applied by
- Packaged stale-threshold recovery gate via
npm run validate:packaged-usage-recovery-e2e(asserts packaged launcher performs forced reprobe recovery when initial usage age is post-threshold) - OpenClaw fallback-cache recovery gate via
npm run validate:openclaw-cache-recovery-e2e(asserts fallback cache usage with stale age still attempts a forced reprobe and recovers to fresh state when the command comes back) - DMG install smoke gate via
npm run validate:dmg-install(mounts DMG, copies app, validates launcher dry-run schema) - Optional portable Node runtime bundling for packaged launcher (
IDLEWATCH_NODE_RUNTIME_DIR=/path/to/runtimewith<runtime>/bin/node), enabling resolution order:IDLEWATCH_NODE_BIN→ bundled runtime →PATH(node).- Runtime copy is now limited to
bin,lib, andincludedirectories (with symlink dereference) to keep runtime payloads portable and avoid noise from host-specific completion symlinks.
- Runtime copy is now limited to
- Bundled-runtime packaging gate via
npm run validate:packaged-bundled-runtime(repackages with a bundled runtime and verifies launcher dry-run succeeds withPATH=/usr/bin:/binwherenodeis absent). - Background execution lifecycle helpers:
scripts/install-macos-launch-agent.shscripts/uninstall-macos-launch-agent.sh- Install an auto-starting
LaunchAgentviaIDLEWATCH_APP_PATH,IDLEWATCH_LAUNCH_AGENT_LABEL,IDLEWATCH_LAUNCH_AGENT_PLIST_ROOT, andIDLEWATCH_LAUNCH_AGENT_LOG_DIR.
Strict packaging mode:
- Set
IDLEWATCH_REQUIRE_TRUSTED_DISTRIBUTION=1to hard-fail packaging unless trust prerequisites are configured. - In strict mode,
package-macos.shrequiresMACOS_CODESIGN_IDENTITY. - In strict mode,
build-dmg.shrequires bothMACOS_CODESIGN_IDENTITYandMACOS_NOTARY_PROFILE. npm run package:trustednow runsnpm run validate:trusted-prereqsfirst to fail fast when local keychain/notary setup is missing.- CI safety guard: tag builds (
refs/tags/*) now auto-enforce strict trusted requirements even ifIDLEWATCH_REQUIRE_TRUSTED_DISTRIBUTIONis unset. - Emergency bypass (explicit): set
IDLEWATCH_ALLOW_UNSIGNED_TAG_RELEASE=1to allow unsigned tag packaging in CI.
Trusted-release workflow required secrets:
MACOS_CODESIGN_IDENTITYAPPLE_DEVELOPER_ID_APP_P12_BASE64APPLE_DEVELOPER_ID_APP_P12_PASSWORDAPPLE_BUILD_KEYCHAIN_PASSWORDAPPLE_NOTARY_KEY_IDAPPLE_NOTARY_ISSUER_IDAPPLE_NOTARY_API_KEY_P8
Trusted release workflow policy:
- OpenClaw usage-health is enforced by default in
.github/workflows/release-macos-trusted.ymlvianpm run validate:packaged-usage-health:reuse-artifactbefore artifact upload. - The trusted pipeline now also runs
npm run validate:packaged-openclaw-release-gates:reuse-artifact, which validates:validate:packaged-usage-health:reuse-artifact,validate:packaged-openclaw-stats-ingestion:reuse-artifact, andvalidate:packaged-openclaw-cache-recovery-e2e:reuse-artifactagainst the signed artifact before upload (with the wrapper settingIDLEWATCH_SKIP_PACKAGE_MACOS=1so checks validate the already-built artifact directly). By default this gate enforces OpenClaw presence (IDLEWATCH_REQUIRE_OPENCLAW_USAGE=1) unless explicitly disabled (0|false|off|no); set1|true|on|yesto force on. - Trusted release gate also enforces
IDLEWATCH_MAX_OPENCLAW_USAGE_AGE_MS=300000to fail fast if packaged usage age is excessively stale.
Reusable OpenClaw release-gate helpers
For CI / script chaining, artifact-aware convenience helpers are available:
npm run validate:packaged-openclaw-release-gates:reuse-artifactnpm run validate:packaged-openclaw-cache-recovery-e2e:reuse-artifactnpm run validate:packaged-dry-run-schema:reuse-artifactnpm run validate:packaged-usage-health:reuse-artifactnpm run validate:packaged-usage-age-slo:reuse-artifactnpm run validate:packaged-openclaw-stats-ingestion:reuse-artifactnpm run validate:packaged-usage-recovery-e2e:reuse-artifactnpm run validate:packaged-usage-probe-noise-e2e:reuse-artifactnpm run validate:packaged-usage-alert-rate-e2e:reuse-artifact
Each wrapper sets IDLEWATCH_SKIP_PACKAGE_MACOS=1 so it reuses the already-built packaged artifact in a run.
Release validation helpers
validate:release-gate: host OpenClaw release checks plus packaged robustness checks in one command on macOS; on non-macOS it performs host checks only.validate:release-gate-all: full host OpenClaw checks + packaged release checks (validate:openclaw-release-gates:all) and packaged robustness checks (freshvalidate:packaged-openclaw-robustness) on macOS; host-only on non-macOS.validate:packaged-openclaw-robustnessis the fresh-packaging packaged resilience slice (usage-age-slo,usage-alert-rate-e2e,usage-probe-noise-e2e, andpackaged-openclaw-release-gates).
