machine-bridge-mcp 2.0.0 → 3.0.0-beta.102
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1142 -0
- package/CONTRIBUTING.md +23 -25
- package/GOVERNANCE.md +2 -2
- package/README.md +58 -20
- package/SECURITY.md +161 -120
- package/SUPPORT.md +1 -1
- package/browser-extension/broker-auth.js +83 -0
- package/browser-extension/broker-liveness.js +35 -0
- package/browser-extension/browser-error-boundary.js +96 -0
- package/browser-extension/browser-operations.js +1456 -101
- package/browser-extension/devtools-input.js +195 -34
- package/browser-extension/devtools-observation.js +429 -0
- package/browser-extension/devtools-session.js +48 -0
- package/browser-extension/manifest.json +4 -3
- package/browser-extension/page-automation.js +578 -118
- package/browser-extension/pairing-bootstrap.js +42 -0
- package/browser-extension/pairing.js +28 -12
- package/browser-extension/service-worker.js +126 -106
- package/docs/AGENT_CONTEXT.md +13 -10
- package/docs/ARCHITECTURE.md +159 -67
- package/docs/AUDIT.md +1302 -4
- package/docs/CLIENTS.md +19 -6
- package/docs/COMPUTER_USE.md +297 -0
- package/docs/ENGINEERING.md +72 -13
- package/docs/GETTING_STARTED.md +18 -20
- package/docs/LOCAL_AUTHORIZATION.md +115 -72
- package/docs/LOCAL_AUTOMATION.md +27 -21
- package/docs/LOGGING.md +40 -19
- package/docs/MANAGED_JOBS.md +37 -34
- package/docs/MULTI_ACCOUNT.md +98 -37
- package/docs/OPERATIONS.md +145 -51
- package/docs/OVERVIEW.md +14 -11
- package/docs/POLICY_REFERENCE.md +71 -3
- package/docs/PRIVACY.md +41 -2
- package/docs/PROJECT_STANDARDS.md +29 -6
- package/docs/RELEASING.md +238 -64
- package/docs/TESTING.md +150 -39
- package/docs/THREAT_MODEL.md +164 -67
- package/docs/TOOL_REFERENCE.md +653 -60
- package/docs/UPGRADING.md +78 -18
- package/native/macos/MachineBridgeBackgroundInput.swift +1051 -0
- package/native/macos/MachineBridgeBackgroundInputSmokeFixture.swift +295 -0
- package/native/macos/MachineBridgeTrustBroker.swift +233 -0
- package/package.json +94 -16
- package/scripts/accepted-candidate-tarball.mjs +77 -0
- package/scripts/candidate-runtime-store.mjs +93 -0
- package/scripts/check-plan.mjs +73 -3
- package/scripts/check-runner.mjs +129 -17
- package/scripts/commit-message-check.mjs +5 -2
- package/scripts/consumer-package-security.mjs +293 -0
- package/scripts/coverage-check.mjs +251 -15
- package/scripts/coverage-generation.mjs +41 -0
- package/scripts/coverage-range-merge.mjs +41 -0
- package/scripts/foreground-daemon-recovery.mjs +88 -0
- package/scripts/generate-policy-reference.mjs +28 -5
- package/scripts/generate-tool-reference.mjs +1 -1
- package/scripts/generate-worker-types.mjs +21 -11
- package/scripts/github-backlog.mjs +11 -10
- package/scripts/github-push.mjs +62 -16
- package/scripts/github-release-asset.mjs +58 -0
- package/scripts/github-release.mjs +241 -132
- package/scripts/global-package-installation.mjs +68 -0
- package/scripts/hardened-npm-session.mjs +42 -0
- package/scripts/install-published-prerelease.mjs +198 -0
- package/scripts/local-release-acceptance.mjs +103 -45
- package/scripts/macos-background-input-smoke.mjs +515 -0
- package/scripts/network-retry.mjs +8 -1
- package/scripts/npm-global-prefix.mjs +27 -0
- package/scripts/npm-publication-policy.mjs +17 -0
- package/scripts/official-mcp-conformance.mjs +267 -0
- package/scripts/persistent-activation-process.mjs +101 -0
- package/scripts/prepare-pinned-npm.mjs +12 -69
- package/scripts/prerelease-activation.mjs +160 -0
- package/scripts/privacy-check.mjs +14 -6
- package/scripts/promotion-digest.mjs +128 -0
- package/scripts/publish-npm.mjs +260 -0
- package/scripts/published-release.mjs +132 -0
- package/scripts/release-acceptance.mjs +62 -54
- package/scripts/release-browser-extension-store.mjs +172 -0
- package/scripts/release-candidate-manifest.mjs +52 -0
- package/scripts/release-channel.mjs +106 -0
- package/scripts/release-diagnostic.mjs +41 -0
- package/scripts/release-impact-check.mjs +12 -22
- package/scripts/release-oauth-canary-core.mjs +325 -0
- package/scripts/release-oauth-canary-evidence.mjs +100 -0
- package/scripts/release-oauth-canary.mjs +127 -0
- package/scripts/release-publication-guard.mjs +67 -0
- package/scripts/release-soak.mjs +284 -0
- package/scripts/release-state.mjs +1 -1
- package/scripts/run-checks.mjs +44 -7
- package/scripts/run-worker-dry-run.mjs +21 -0
- package/scripts/sarif-security-gate.mjs +2 -1
- package/scripts/sbom-check.mjs +106 -0
- package/scripts/start-release-candidate.mjs +267 -44
- package/scripts/syntax-check.mjs +36 -14
- package/scripts/verification-generation-guard.mjs +15 -0
- package/scripts/verification-idle-sleep-guard.mjs +37 -0
- package/scripts/verification-state.mjs +108 -0
- package/scripts/wrangler-command-lifecycle.mjs +115 -0
- package/src/local/account-access.mjs +13 -1
- package/src/local/account-admin-response.mjs +92 -0
- package/src/local/account-admin.mjs +52 -19
- package/src/local/agent-context-projection.mjs +26 -7
- package/src/local/agent-context.mjs +88 -49
- package/src/local/agent-skill-discovery.mjs +16 -5
- package/src/local/app-automation-macos-jxa.mjs +350 -0
- package/src/local/app-automation.mjs +873 -163
- package/src/local/application-capability-projection.mjs +24 -0
- package/src/local/authority-context.mjs +106 -0
- package/src/local/autostart-log-maintenance.mjs +36 -0
- package/src/local/browser-bridge-http.mjs +5 -3
- package/src/local/browser-bridge.mjs +109 -31
- package/src/local/browser-broker-auth-http.mjs +67 -0
- package/src/local/browser-broker-auth.mjs +98 -0
- package/src/local/browser-broker-routes.mjs +63 -20
- package/src/local/browser-broker-server.mjs +17 -7
- package/src/local/browser-command.mjs +79 -30
- package/src/local/browser-computer-observation-service.mjs +266 -0
- package/src/local/browser-extension-identity.mjs +50 -0
- package/src/local/browser-extension-path.mjs +22 -0
- package/src/local/browser-extension-protocol.mjs +50 -11
- package/src/local/browser-operation-service.mjs +147 -117
- package/src/local/browser-pairing-grant.mjs +109 -0
- package/src/local/browser-pairing-http.mjs +36 -0
- package/src/local/browser-pairing-launch.mjs +58 -0
- package/src/local/browser-pairing-store.mjs +85 -48
- package/src/local/browser-request-registry.mjs +40 -14
- package/src/local/browser-request-settlement.mjs +78 -0
- package/src/local/browser-resource-input.mjs +74 -0
- package/src/local/browser-trusted-input-health.mjs +63 -0
- package/src/local/call-authority.mjs +21 -0
- package/src/local/call-capacity.mjs +45 -0
- package/src/local/call-registry-drain.mjs +54 -0
- package/src/local/call-registry.mjs +30 -15
- package/src/local/capability-observer.mjs +5 -0
- package/src/local/capability-ranking.mjs +3 -2
- package/src/local/child-process-settlement.mjs +132 -0
- package/src/local/cli-account-admin.mjs +40 -6
- package/src/local/cli-activate.mjs +162 -0
- package/src/local/cli-local-admin.mjs +20 -45
- package/src/local/cli-options.mjs +12 -13
- package/src/local/cli-ready-output.mjs +52 -0
- package/src/local/cli-service.mjs +91 -11
- package/src/local/cli.mjs +232 -150
- package/src/local/computer-use-application-observation.mjs +224 -0
- package/src/local/computer-use-arguments.mjs +270 -0
- package/src/local/computer-use-deadline.mjs +50 -0
- package/src/local/computer-use-dispatch-settlement.mjs +40 -0
- package/src/local/computer-use-expectation.mjs +171 -0
- package/src/local/computer-use-observation.mjs +769 -0
- package/src/local/computer-use-recovery.mjs +82 -0
- package/src/local/computer-use-result-budget.mjs +145 -0
- package/src/local/computer-use-snapshot-store.mjs +67 -0
- package/src/local/computer-use.mjs +2255 -0
- package/src/local/daemon-http-relay-auth.mjs +26 -0
- package/src/local/daemon-http-relay-connection.mjs +298 -0
- package/src/local/daemon-http-relay-request.mjs +64 -0
- package/src/local/daemon-http-relay-sequence.mjs +49 -0
- package/src/local/daemon-process.mjs +40 -7
- package/src/local/delegated-process-sandbox.mjs +148 -0
- package/src/local/device-identity.mjs +156 -49
- package/src/local/device-root-provider.mjs +81 -0
- package/src/local/directory-metadata.mjs +47 -0
- package/src/local/doctor-reporting.mjs +23 -0
- package/src/local/durable-process-spec.mjs +80 -0
- package/src/local/errors.mjs +25 -15
- package/src/local/exclusive-file.mjs +74 -26
- package/src/local/execution-limits.mjs +9 -0
- package/src/local/execution-routing.mjs +276 -0
- package/src/local/execution-surface.mjs +23 -0
- package/src/local/file-mutation-coordinator.mjs +47 -0
- package/src/local/file-snapshot-preservation.mjs +24 -0
- package/src/local/filesystem-identity.mjs +54 -0
- package/src/local/fixed-process-environment.mjs +21 -0
- package/src/local/full-access-test.mjs +31 -13
- package/src/local/git-commit.mjs +69 -0
- package/src/local/git-config-safety.mjs +55 -0
- package/src/local/git-log-parser.mjs +41 -0
- package/src/local/git-metadata-boundary.mjs +77 -0
- package/src/local/git-metadata-tree-safety.mjs +59 -0
- package/src/local/git-operation-state.mjs +19 -0
- package/src/local/git-service.mjs +165 -30
- package/src/local/hardened-npm-download-timeout.mjs +46 -0
- package/src/local/hardened-npm-download.mjs +109 -0
- package/src/local/hardened-npm-extract.mjs +20 -0
- package/src/local/hardened-npm-verification.mjs +104 -0
- package/src/local/hardened-npm.mjs +199 -0
- package/src/local/job-runner.mjs +244 -89
- package/src/local/lifecycle.mjs +6 -0
- package/src/local/log.mjs +19 -45
- package/src/local/macos-background-input.mjs +398 -0
- package/src/local/macos-idle-sleep-assertion.mjs +65 -0
- package/src/local/macos-trust-broker.mjs +404 -0
- package/src/local/managed-job-cancellation.mjs +42 -0
- package/src/local/managed-job-capacity.mjs +16 -0
- package/src/local/managed-job-directory-generation.mjs +60 -0
- package/src/local/managed-job-directory.mjs +75 -0
- package/src/local/managed-job-durable-process.mjs +49 -0
- package/src/local/managed-job-lock.mjs +46 -14
- package/src/local/managed-job-plan.mjs +38 -14
- package/src/local/managed-job-projection.mjs +23 -15
- package/src/local/managed-job-retention.mjs +128 -0
- package/src/local/managed-job-runner-claim.mjs +70 -0
- package/src/local/managed-job-runner.mjs +35 -10
- package/src/local/managed-job-storage.mjs +22 -6
- package/src/local/managed-job-terminal-maintenance.mjs +40 -0
- package/src/local/managed-job-terminal.mjs +150 -0
- package/src/local/managed-jobs.mjs +424 -287
- package/src/local/npm-cli.mjs +42 -0
- package/src/local/npm-environment.mjs +37 -0
- package/src/local/operation-authorization.mjs +68 -324
- package/src/local/operation-risk.mjs +51 -4
- package/src/local/owner-state-lock.mjs +118 -0
- package/src/local/package-identity.mjs +9 -0
- package/src/local/patch.mjs +20 -18
- package/src/local/path-inspection.mjs +23 -0
- package/src/local/policy.mjs +19 -0
- package/src/local/private-toolchain-integrity.mjs +54 -0
- package/src/local/process-execution.mjs +87 -75
- package/src/local/process-foreground-timeout.mjs +50 -0
- package/src/local/process-identity.mjs +41 -7
- package/src/local/process-nonreplayable-settlement.mjs +50 -0
- package/src/local/process-result-projection.mjs +22 -0
- package/src/local/process-session-events.mjs +47 -0
- package/src/local/process-session-remote-activity.mjs +10 -0
- package/src/local/process-session-termination.mjs +73 -0
- package/src/local/process-sessions.mjs +144 -112
- package/src/local/process-tracker.mjs +140 -13
- package/src/local/process-tree-ownership-types.d.ts +37 -0
- package/src/local/process-tree-ownership.mjs +57 -0
- package/src/local/process-tree-signal.mjs +34 -0
- package/src/local/process-tree-snapshot.mjs +77 -0
- package/src/local/process-tree-supervisor.mjs +69 -0
- package/src/local/process-tree.mjs +11 -53
- package/src/local/project-metadata.mjs +19 -6
- package/src/local/relay-call-recovery.mjs +58 -38
- package/src/local/relay-connection-classification.mjs +131 -0
- package/src/local/relay-connection-support.mjs +91 -0
- package/src/local/relay-connection.mjs +179 -272
- package/src/local/relay-diagnostics.mjs +91 -0
- package/src/local/relay-heartbeat.mjs +119 -0
- package/src/local/relay-liveness.mjs +109 -0
- package/src/local/relay-peer-diagnostics.mjs +29 -0
- package/src/local/release-runtime-lock.mjs +18 -0
- package/src/local/remote-activity-idle-sleep-guard.mjs +77 -0
- package/src/local/remote-configuration.mjs +48 -0
- package/src/local/resilient-relay-connection.mjs +178 -0
- package/src/local/resource-admission-diagnostics.mjs +52 -0
- package/src/local/resource-admission-policy.mjs +115 -0
- package/src/local/resource-admission.mjs +339 -0
- package/src/local/resource-build-root.mjs +83 -0
- package/src/local/resource-cargo-concurrency.mjs +38 -0
- package/src/local/resource-cmake-concurrency.mjs +42 -0
- package/src/local/resource-command-concurrency.mjs +37 -0
- package/src/local/resource-command-profile.mjs +176 -0
- package/src/local/resource-coordinator-accounting.mjs +21 -0
- package/src/local/resource-cpu-window.mjs +20 -0
- package/src/local/resource-disk-headroom.mjs +13 -0
- package/src/local/resource-elastic-memory.mjs +19 -0
- package/src/local/resource-elastic-request.mjs +36 -0
- package/src/local/resource-foreground-wait.mjs +29 -0
- package/src/local/resource-go-concurrency.mjs +43 -0
- package/src/local/resource-gradle-concurrency.mjs +57 -0
- package/src/local/resource-host-cache.mjs +39 -0
- package/src/local/resource-host-darwin.mjs +54 -0
- package/src/local/resource-host-linux.mjs +35 -0
- package/src/local/resource-host-sample-file.mjs +23 -0
- package/src/local/resource-host-snapshot.mjs +99 -0
- package/src/local/resource-lease-accounting.mjs +119 -0
- package/src/local/resource-light-command.mjs +6 -0
- package/src/local/resource-make-concurrency.mjs +42 -0
- package/src/local/resource-maven-concurrency.mjs +38 -0
- package/src/local/resource-ninja-command-concurrency.mjs +20 -0
- package/src/local/resource-ninja-concurrency.mjs +28 -0
- package/src/local/resource-operations.mjs +26 -10
- package/src/local/resource-pressure.mjs +67 -0
- package/src/local/resource-probe-command.mjs +35 -0
- package/src/local/resource-process-admission.mjs +59 -0
- package/src/local/resource-process-ancestry-cache.mjs +43 -0
- package/src/local/resource-process-ancestry.mjs +32 -0
- package/src/local/resource-process-priority.mjs +15 -0
- package/src/local/resource-project-key.mjs +53 -0
- package/src/local/resource-pytest-concurrency.mjs +33 -0
- package/src/local/resource-release-control-classification.mjs +14 -0
- package/src/local/resource-release-control-executable.mjs +70 -0
- package/src/local/resource-release-control-workspace.mjs +41 -0
- package/src/local/resource-request-contract.mjs +30 -0
- package/src/local/resource-script-classification.mjs +44 -0
- package/src/local/resource-shell-analysis.mjs +58 -0
- package/src/local/resource-staging-recovery.mjs +97 -0
- package/src/local/resource-swift-concurrency.mjs +31 -0
- package/src/local/resource-transaction-lock.mjs +189 -0
- package/src/local/resource-wait.mjs +48 -0
- package/src/local/resource-waiters.mjs +139 -0
- package/src/local/resource-xcode-command.mjs +7 -0
- package/src/local/resource-xcode-concurrency.mjs +34 -0
- package/src/local/resource-xcode-non-build.mjs +19 -0
- package/src/local/runtime-activation.mjs +700 -0
- package/src/local/runtime-activity-projection.mjs +48 -0
- package/src/local/runtime-capabilities.mjs +48 -15
- package/src/local/runtime-diagnostic-state.mjs +14 -0
- package/src/local/runtime-diagnostics.mjs +40 -13
- package/src/local/runtime-info-projection.mjs +60 -0
- package/src/local/runtime-info-relay-projection.mjs +21 -0
- package/src/local/runtime-paths.mjs +2 -1
- package/src/local/runtime-process-routing.mjs +33 -0
- package/src/local/runtime-relay-connection-options.mjs +44 -0
- package/src/local/runtime-relay-control.mjs +98 -0
- package/src/local/runtime-relay.mjs +26 -50
- package/src/local/runtime-reporting.mjs +37 -21
- package/src/local/runtime-resource-service.mjs +77 -0
- package/src/local/runtime-tool-handlers.mjs +13 -10
- package/src/local/runtime.mjs +244 -208
- package/src/local/secure-file.mjs +73 -20
- package/src/local/security-audit-dispatch.mjs +35 -0
- package/src/local/security-audit-log.mjs +215 -0
- package/src/local/security-audit-state.mjs +139 -0
- package/src/local/security-audit-storage.mjs +135 -0
- package/src/local/security-audit-warning.mjs +31 -0
- package/src/local/security-audit-worker.mjs +87 -0
- package/src/local/service-convergence.mjs +42 -1
- package/src/local/service-definition.mjs +24 -0
- package/src/local/service-environment.mjs +18 -10
- package/src/local/service-owner.mjs +146 -0
- package/src/local/service-ownership.mjs +17 -0
- package/src/local/service-restart-handoff.mjs +64 -0
- package/src/local/service-restart-scheduler.mjs +49 -0
- package/src/local/service-runtime-convergence.mjs +52 -0
- package/src/local/service-runtime.mjs +105 -0
- package/src/local/service-status.mjs +60 -0
- package/src/local/service.mjs +385 -92
- package/src/local/shell.mjs +39 -19
- package/src/local/ssh-key.mjs +158 -42
- package/src/local/state-inventory.mjs +50 -24
- package/src/local/state-owner-lock-inventory.mjs +23 -0
- package/src/local/state-root-owned-namespaces.mjs +83 -0
- package/src/local/state-root-retirement.mjs +89 -0
- package/src/local/state.mjs +386 -96
- package/src/local/stdio.mjs +96 -66
- package/src/local/support-state-projection.mjs +30 -0
- package/src/local/system-network-route.mjs +76 -0
- package/src/local/systemd-removal.mjs +20 -0
- package/src/local/tool-executor.mjs +85 -20
- package/src/local/tool-result-boundary.mjs +51 -0
- package/src/local/toolchain-operation-lock.mjs +41 -0
- package/src/local/tools.mjs +7 -5
- package/src/local/trusted-executable.mjs +53 -0
- package/src/local/trusted-git-executable.mjs +34 -0
- package/src/local/trusted-github-cli.mjs +24 -0
- package/src/local/windows-service-convergence.mjs +49 -0
- package/src/local/windows-service.mjs +52 -45
- package/src/local/worker-deployment-fingerprint.mjs +102 -0
- package/src/local/worker-deployment.mjs +48 -60
- package/src/local/worker-health.mjs +12 -4
- package/src/local/worker-secret-file.mjs +37 -17
- package/src/local/workspace-file-service.mjs +156 -239
- package/src/local/workspace-file-transaction.mjs +189 -0
- package/src/local/workspace-search.mjs +55 -0
- package/src/local/wrangler-toolchain/package-lock.json +1505 -0
- package/src/local/wrangler-toolchain/package.json +23 -0
- package/src/local/wrangler-toolchain-verification.mjs +135 -0
- package/src/local/wrangler-toolchain.mjs +188 -0
- package/src/shared/access-contract.json +7 -1
- package/src/shared/activation-recovery.mjs +49 -0
- package/src/shared/admin-auth.d.mts +2 -1
- package/src/shared/admin-auth.mjs +3 -3
- package/src/shared/authority-revocation.d.mts +9 -0
- package/src/shared/authority-revocation.mjs +28 -0
- package/src/shared/daemon-auth.d.mts +11 -0
- package/src/shared/daemon-auth.mjs +17 -0
- package/src/shared/device-session-auth.d.mts +20 -0
- package/src/shared/device-session-auth.mjs +51 -0
- package/src/shared/foreground-timeout.d.mts +15 -0
- package/src/shared/foreground-timeout.mjs +70 -0
- package/src/shared/log-redaction.d.mts +9 -0
- package/src/shared/log-redaction.mjs +51 -0
- package/src/shared/mcp-protocol.d.mts +27 -0
- package/src/shared/mcp-protocol.mjs +275 -0
- package/src/shared/project-overview-projection.d.mts +4 -0
- package/src/shared/project-overview-projection.mjs +96 -0
- package/src/shared/relay-contract.json +28 -0
- package/src/shared/result-projection.d.mts +2 -1
- package/src/shared/result-projection.mjs +13 -2
- package/src/shared/server-metadata.json +15 -9
- package/src/shared/tool-argument-validation.d.mts +17 -0
- package/src/shared/tool-argument-validation.mjs +325 -0
- package/src/shared/tool-call-capacity.d.mts +41 -0
- package/src/shared/tool-call-capacity.mjs +59 -0
- package/src/shared/tool-catalog.json +626 -57
- package/src/worker/access.ts +12 -0
- package/src/worker/account-admin.ts +55 -33
- package/src/worker/authority-revocations.ts +174 -0
- package/src/worker/authority.ts +52 -6
- package/src/worker/daemon-auth.ts +49 -68
- package/src/worker/daemon-channel.ts +36 -0
- package/src/worker/daemon-http-auth.ts +63 -0
- package/src/worker/daemon-http-channel.ts +120 -0
- package/src/worker/daemon-http-controller.ts +163 -0
- package/src/worker/daemon-http-protocol.ts +62 -0
- package/src/worker/daemon-http-registry.ts +82 -0
- package/src/worker/daemon-last-observation.ts +30 -0
- package/src/worker/daemon-liveness.ts +8 -6
- package/src/worker/daemon-ready-dispatch.ts +17 -0
- package/src/worker/daemon-ready-messages.ts +73 -0
- package/src/worker/daemon-ready-waiters.ts +79 -0
- package/src/worker/daemon-recovery-budget.ts +13 -0
- package/src/worker/daemon-registry.ts +58 -0
- package/src/worker/daemon-relay-diagnostics.ts +127 -0
- package/src/worker/daemon-socket-attachment.ts +55 -0
- package/src/worker/daemon-sockets.ts +72 -62
- package/src/worker/daemon-status.ts +38 -0
- package/src/worker/device-session-verifier.ts +129 -0
- package/src/worker/dpop.ts +157 -0
- package/src/worker/durable-process-timeout.ts +29 -0
- package/src/worker/errors.ts +57 -0
- package/src/worker/http.ts +112 -26
- package/src/worker/index.ts +446 -440
- package/src/worker/mcp-access.ts +57 -0
- package/src/worker/mcp-controller.ts +188 -0
- package/src/worker/mcp-http-accept.ts +11 -0
- package/src/worker/mcp-http-contract.ts +322 -0
- package/src/worker/mcp-initialization-compat.ts +141 -0
- package/src/worker/mcp-jsonrpc.ts +11 -29
- package/src/worker/mcp-removed-protocol.ts +17 -0
- package/src/worker/mcp-response-proxy.ts +135 -0
- package/src/worker/mcp-response-stream.ts +65 -0
- package/src/worker/mcp-stale-schema-compat.ts +57 -0
- package/src/worker/mcp-stream-proxy-contract.ts +48 -0
- package/src/worker/mcp-tool-call-input.ts +23 -0
- package/src/worker/nonce-store.ts +33 -35
- package/src/worker/oauth-authorization-page.ts +21 -1
- package/src/worker/oauth-client-admin.ts +52 -0
- package/src/worker/oauth-client-contract.ts +38 -0
- package/src/worker/oauth-controller.ts +107 -47
- package/src/worker/oauth-field-contract.ts +31 -0
- package/src/worker/oauth-record-contract.ts +7 -0
- package/src/worker/oauth-refresh-authority.ts +27 -0
- package/src/worker/oauth-refresh-exchange.ts +162 -0
- package/src/worker/oauth-refresh-families.ts +130 -27
- package/src/worker/oauth-refresh-persistence.ts +116 -0
- package/src/worker/oauth-state.ts +33 -18
- package/src/worker/oauth-store-validation.ts +131 -0
- package/src/worker/oauth-token-derivation.ts +33 -0
- package/src/worker/oauth-token-issuance.ts +119 -0
- package/src/worker/oauth-tokens.ts +56 -190
- package/src/worker/observability.ts +38 -5
- package/src/worker/pending-admission.ts +15 -0
- package/src/worker/pending-call-capacity.ts +108 -0
- package/src/worker/pending-call-contract.ts +42 -5
- package/src/worker/pending-call-deadlines.ts +75 -0
- package/src/worker/pending-calls.ts +131 -125
- package/src/worker/runtime-alarm-storage.ts +37 -0
- package/src/worker/runtime-alarm.ts +136 -0
- package/src/worker/server-info-activity.ts +36 -0
- package/src/worker/server-info-tool-delivery.ts +15 -0
- package/src/worker/server-info.ts +168 -0
- package/src/worker/tool-catalog.ts +47 -1
- package/src/worker/tool-timeout.ts +75 -14
- package/src/worker/websocket-protocol.ts +26 -2
- package/src/worker/worker-edge-guard.ts +90 -0
- package/src/worker/worker-edge-log.ts +65 -0
- package/src/worker/worker-entry.ts +52 -0
- package/src/worker/worker-mcp-config.ts +23 -0
- package/src/worker/worker-metadata.ts +48 -0
- package/src/worker/worker-rate-limit-key.ts +30 -0
- package/src/worker/worker-runtime-config.ts +20 -0
- package/src/worker/worker-static-routes.ts +54 -0
- package/src/worker/worker-task-lifetime.ts +18 -0
- package/tsconfig.local.json +17 -1
- package/wrangler.jsonc +13 -0
- package/src/local/cli-approval.mjs +0 -117
- package/src/local/operation-state-lock.mjs +0 -92
- package/src/worker/mcp-session.ts +0 -72
package/docs/OPERATIONS.md
CHANGED
|
@@ -8,11 +8,19 @@ machine-mcp doctor
|
|
|
8
8
|
machine-mcp service status
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
`status` prints redacted profile state and verifies the deployed Worker version. Resource source paths remain redacted. `doctor` checks Node.js, the package-installed Wrangler binary, Cloudflare login, Worker health, and the same fixed local filesystem/process/shell/job-storage/resource probes exposed by `diagnose_runtime`. Public `/healthz` output contains only server identity and version; daemon details require an authenticated `server_info` call.
|
|
11
|
+
Routine remote checks should use authenticated `server_info` with `detail: "summary"`; request the default/full projection only when the caller's authority permits and exact effective-tool, OAuth/account, or detailed owner observability is actually needed. Non-owner full responses intentionally retain hidden markers/counts instead of cross-principal activity, resource aliases, stable device-key identity, or daemon-only tool names. Remote `diagnose_runtime` is owner-only because its fixed probes expose machine-wide control-plane activity; narrower roles use `server_info`/`project_overview` for authority-scoped readiness and workspace state. `status` prints redacted profile state and verifies the deployed Worker version. Resource source paths remain redacted. `doctor` checks Node.js, the package-installed Wrangler binary, Cloudflare login, Worker health, the configured policy, the automatic-without-per-operation-prompts authorization model, and the same fixed local filesystem/process/shell/job-storage/resource probes exposed to the remote owner by `diagnose_runtime`. It constructs an isolated local runtime: `diagnosticScope.running_service_process_inspected=false` and `remote_relay_inspected=false` are deliberate, so a green doctor result is not evidence that the launchd/systemd/Scheduled Task daemon retained its Worker WebSocket. Inspect authenticated `server_info.daemon.relay_transport` for the running service relay. Authenticated `server_info.authorization.execution_model` reports the authority contract and identifies whether the account has daemon-OS-user ambient authority. Public `/healthz` output contains only server identity and version; daemon details require an authenticated `server_info` call.
|
|
12
|
+
|
|
13
|
+
Repository-controlled release and publication commands emit terminal failures as one JSON object with exactly `event` and `error` fields. The event is a fixed validated identifier; the error is bounded and passes through portable credential, URL, email, home-path, and control-character redaction before JSON serialization. Treat the object as one log record. Do not replace it with raw subprocess output or interpolate the error into a prefix string when adding a new release path.
|
|
14
|
+
|
|
15
|
+
Process timeout cleanup is ownership-bound rather than parent-liveness-bound. On POSIX, Machine Bridge captures process-group identity before graceful termination, refreshes descendants within one shared bounded snapshot budget, and sends SIGKILL only when a captured identity is still current. If ownership cannot be proved, escalation fails closed instead of risking an unrelated process; a direct child exiting does not by itself cancel cleanup of an already captured surviving descendant.
|
|
12
16
|
|
|
13
17
|
### Worker deployment and health convergence
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
`/healthz` and `/` are answered by the outer Worker and do not consume Durable Object request volume. If MCP or daemon routes return `503 durable_object_quota_exceeded` (or Cloudflare 1101 with Durable Objects free-tier exhaustion in Worker tails), wait for the daily UTC free-tier reset or move the account off the free DO plan; do not treat that as a failed script deploy when `/healthz` still reports the expected version.
|
|
20
|
+
|
|
21
|
+
Wrangler upload and public health verification are two separate observations. Once Wrangler reports a successful deployment and supplies the `workers.dev` URL, Machine Bridge immediately records that URL together with the exact deployment fingerprint and package version. Beta.43 upgrades this fingerprint to length-framed v5 and therefore treats earlier hashes as stale once; it verifies or redeploys the same-name Worker rather than creating another Worker. Required Worker/shared/config inputs must be readable ordinary repository files or directories. Missing, inaccessible, symlinked, hard-linked, or special paths stop before upload. It then verifies `/healthz` through the standard `HTTPS_PROXY`/`HTTP_PROXY` and `NO_PROXY` environment route. If that secondary probe times out or encounters a proxy, TLS, network, or temporary HTTP 5xx failure, startup stops with an actionable error, but the successful deployment evidence remains. The next ordinary start verifies the same Worker and does not repeat the upload.
|
|
22
|
+
|
|
23
|
+
Interactive Wrangler login is deliberately unavailable in machine-readable Worker deployment. A normal non-JSON local startup may run login and then must re-run `whoami` before deployment; JSON mode returns `worker_authentication_required` instead. Persistent candidate activation adds an outer authentication preflight before the service handoff: detached managed-job activation requires an already authenticated Wrangler session and fails before live mutation otherwise, while an ordinary owner terminal may complete login before the old login service is stopped. This prevents a ten-minute interactive authentication flow from becoming part of a service-offline transaction or writing non-JSON text into the activation result channel.
|
|
16
24
|
|
|
17
25
|
Automatic redeployment is limited to bounded health evidence that the recorded endpoint is genuinely stale: a persistent package-version mismatch, an unexpected Machine Bridge identity, or a persistent `404`/`410`. Unreachability is not proof of absence. `--force-worker` remains the explicit override when an operator deliberately wants an upload despite matching state.
|
|
18
26
|
|
|
@@ -28,16 +36,24 @@ machine-mcp --verbose
|
|
|
28
36
|
|
|
29
37
|
Run these commands from the same environment used for startup so `HTTPS_PROXY`, `HTTP_PROXY`, and `NO_PROXY` are identical. After the foreground connection succeeds, run `machine-mcp service install` from that same PowerShell session. Installation stores only an allowlisted proxy/custom-CA environment snapshot in private local state so the logon task does not lose session-only `$env:` settings after reboot. A later start with no proxy variables does not erase the saved snapshot; set a variable explicitly to an empty value and reinstall to clear it. `machine-mcp service status` reports only the saved key names. Debug logs expose only the selected route and classified error; they never print a proxy endpoint or credentials.
|
|
30
38
|
|
|
39
|
+
### Worker quota controls
|
|
40
|
+
|
|
41
|
+
The standard public endpoint remains the automatically provisioned `workers.dev` URL printed by Machine Bridge; no personal domain is required. The outer Worker serves health, discovery metadata, CORS preflight, and unknown 404s without Durable Object state. Stateful routes pass a 120-per-minute Cloudflare Rate Limiting binding before DO dispatch. This guard is per Cloudflare location and executes after the Worker starts; it protects the Durable Object from ordinary bursts but is not an exact account-wide daily Workers quota. Configure Cloudflare account usage alerts when available. A binding outage fails open so quota protection cannot become an authentication outage.
|
|
42
|
+
|
|
43
|
+
In the full projection, `server_info.worker.observability.oauth_refresh` distinguishes normal rotation, bounded retry issuance, exhausted retry budget, post-grace family revocation, and rejected grants. `durable_budget` reports estimated stream-row writes plus alarm sets, deletes, and no-ops. These are process-lifetime logical counters for diagnosis, not Cloudflare billing records.
|
|
44
|
+
|
|
31
45
|
### Blocking-layer decision table
|
|
32
46
|
|
|
33
47
|
| Result | Interpretation |
|
|
34
48
|
|---|---|
|
|
35
49
|
| `authorization.effective_policy.profile` is `full` and the tool is in `authorization.effective_tools`, but the current session UI exposes fewer tools | Host/connector post-relay filtering; Machine Bridge cannot enumerate or override that subset |
|
|
36
50
|
| `daemon.policy.profile` is `full` but `authorization.effective_policy.profile` is `review`, `edit`, or `agent` | Expected account-role narrowing; the daemon field is only a capability ceiling and must not be reported as the account permission |
|
|
37
|
-
| `worker.sockets_live.authenticated` is nonzero but `worker.sockets_live.ready` is zero | Transport authentication exists, but the end-to-end result probe has not completed
|
|
38
|
-
| `capability_routing.bootstrap_observed` is false | The current local runtime has not received `session_bootstrap
|
|
39
|
-
| `task_resolution_observed` is false after a
|
|
40
|
-
|
|
|
51
|
+
| `worker.sockets_live.authenticated` is nonzero but `worker.sockets_live.ready` is zero | Transport authentication exists, but the end-to-end result probe has not completed. The stable account catalog remains discoverable, while `authorization.effective_tools` contains no executable daemon tool and calls fail retryably until readiness |
|
|
52
|
+
| `capability_routing.bootstrap_observed` is false | The current local runtime has not received `session_bootstrap`. This is normal after `server/discover` alone; investigate only when the workflow expected an explicit refresh. |
|
|
53
|
+
| `task_resolution_observed` is false after a task that required refreshed instructions, skill/command discovery, or application/browser routing | The host/model did not call `resolve_task_capabilities`; server-side discovery cannot force that host decision. Straightforward direct file/Git/shell work does not require this call. |
|
|
54
|
+
| `primary_route` is unexpected or `routing_ambiguity` is high | Inspect the returned competing routes and tool-description boundaries; routing is advisory, so use any tool allowed by the effective policy. Do not treat a fallback as permission to bypass a host or policy denial. |
|
|
55
|
+
| Capability responses repeat large unchanged instructions | Return the previous lowercase SHA-256 `refresh.fingerprint` as `known_refresh_fingerprint`; static context is omitted only when its identity still matches, while task routing is recomputed. |
|
|
56
|
+
| Task resolution ran but all match counts are zero | Check `application_discovery`: a nonzero warning count or `available=false` means the baseline read-only application scan was partial or unavailable; otherwise the resolver ran successfully but found no sufficiently relevant local skill, command, or application |
|
|
41
57
|
| No structured result because the host rejects the call | Host/connector approval or safety layer, or transport before daemon delivery |
|
|
42
58
|
| `mcp-host-to-daemon` passes but `local-filesystem` fails | Local state/runtime permissions, disk policy, sandbox, or endpoint security |
|
|
43
59
|
| Filesystem passes but `local-process-spawn` fails | Local executable policy, endpoint security, OS permissions, or damaged Node runtime |
|
|
@@ -49,19 +65,35 @@ A successful diagnostic result applies only to that probe. An MCP host can still
|
|
|
49
65
|
|
|
50
66
|
### Concurrent chat windows and pending calls
|
|
51
67
|
|
|
52
|
-
Machine Bridge supports concurrent calls: the Worker admits
|
|
68
|
+
Machine Bridge supports concurrent calls: the Worker admits at most 32 daemon-bound calls across already-dispatched pending calls and pre-dispatch daemon-recovery waiters (30 ordinary plus two reserved control calls), and the local runtime admits 16 active tool calls (14 ordinary plus two reserved control calls). The same `diagnose_runtime`/`list_roots` control set is enforced at both layers. These are capacity limits, not a single global execution queue. MCP `2026-07-28` HTTP requests are independent: JSON-RPC IDs are scoped to each request/response stream, so separate clients may reuse the same numeric ID even when they share one OAuth account and token. There is no token-wide or session-wide HTTP idempotency key. If a side-effecting request loses its response before settlement is known, inspect stable state rather than blindly replaying it; use a managed-job `idempotency_key` when durable submission retry semantics are required.
|
|
69
|
+
|
|
70
|
+
The compact projection reports the bounded fields needed for health: `active` remains the already-dispatched pending-call count, `pre_dispatch_waiters` reports calls waiting for a verified daemon, `capacity_active` plus its ordinary/reserved split reports their combined use of the 32-call Worker ceiling, and `detached`/`oldest_ms` describe dispatched continuity. The full `server_info.worker.pending_calls` additionally reports request-key and per-tool detail from the transient dispatched-call registry; waiter tool names are used internally for reserved-capacity accounting but are not added to the diagnostic per-tool map. `worker.sockets_live` separately reports `authenticated`, `probing`, `ready`, and `candidates`; only `ready` sockets contribute to `daemon.connected` and `authorization.effective_tools`. `daemon.relay_transport` is the bounded, daemon-supplied summary captured during the current connection handshake: it records the immediately preceding reconnect episode without endpoints, interface names, arguments, or results. A nonzero `active` count means work is in flight, not that the bridge is globally locked. `detached > 0` means the daemon WebSocket was lost and calls are inside the bounded same-daemon reconnect interval. This is relay execution continuity below MCP delivery, not client replay state.
|
|
71
|
+
|
|
72
|
+
The public HTTP response stream is the request owner: closing it cancels the transient pending call, and no client replay record exists. A verified same-daemon replacement may reclaim a detached relay call after readiness only while its initiating response still owns the request; a new daemon process cannot. Delayed results from the old socket are rejected. `detached > 0` materially beyond the reconnect grace or a pending call surviving response closure is a lifecycle defect.
|
|
73
|
+
|
|
74
|
+
A Worker-requested `daemon_transport_error` or `daemon_liveness_timeout` is a retryable connection invalidation. The local daemon must close only the affected socket, preserve pending-call detach semantics, and reconnect; it must not enter the fatal `relay_protocol_error` path or exit for launchd to restart. The Worker uses close code 1012 for these transient cases. The daemon also recognizes the bounded close reasons `daemon pong failed`, `daemon send failed`, and `daemon liveness timeout` if the preceding error frame is not delivered. Unknown error codes, authentication rejection, and server identity/version mismatch remain permanent failures and require operator action.
|
|
75
|
+
|
|
76
|
+
For MCP `2026-07-28`, every POST advertises both `application/json` and `text/event-stream` with valid positive HTTP quality values, carries protocol version and capabilities in request `_meta`, and mirrors the version/method/applicable name into validated HTTP headers. The actual `/mcp` Origin must be absent, same-origin, built-in, or explicitly allowlisted; CORS preflight accepts only fixed protocol headers plus exact catalog-declared `Mcp-Param-*` names. A JSON response completes immediately; a streamed `tools/call` receives a request-scoped SSE stream without event IDs. Closing that response stream is cancellation: the outer Worker observes request abort, response-body cancellation, or failed bounded keepalive delivery and sends one random internal capability without Authorization or DPoP headers. The Durable Object consumes it before OAuth only to remove the already-active matching pending call and send `cancel_call` when work has been dispatched; caller-supplied internal headers are stripped. `GET /mcp`, `Mcp-Session-Id`, and `Last-Event-ID` are not delivery mechanisms. Local Wrangler does not propagate a raw TCP close into Worker cancellation callbacks reliably, so deterministic proxy tests enforce this control path and live candidate verification must exercise it on the deployed edge.
|
|
77
|
+
|
|
78
|
+
The daemon-to-Worker terminal protocol is at-least-once until `tool_result_ack`. Queueing a WebSocket frame is not durable delivery: the runtime retains a bounded terminal envelope, replays it after same-daemon reconnect or heartbeat, and removes it only after acknowledgement or the authoritative `resume_calls` reconciliation excludes it. MCP itself has no replay surface. `server_info.worker.observability.terminal_results` separates the actual disposition of daemon result envelopes: `committed` reached the current request owner; `owner_missing_acknowledged` arrived after that owner had already settled or been removed and was safely acknowledged only to stop relay-layer replay; `stale_connection_rejected` came from a connection that no longer owned the call and was not acknowledged. Growth in `owner_missing_acknowledged` usually indicates acknowledgement loss, cancellation, timeout, or deployment/reconnect overlap; growth in `stale_connection_rejected`, especially with old pending calls or protocol errors, indicates a connection-identity or lifecycle defect. These counters contain no arguments or result data. If the local reconnect grace itself expires while work or completed results are still retained, the default warning event is `relay.calls.reconnect_expired`; it records only aggregate `cancelled_calls`, `discarded_results`, and `grace_ms` fields so incident tooling can distinguish execution cancellation from terminal-result loss without parsing free-form text.
|
|
79
|
+
|
|
80
|
+
### MCP host or connector internal-storage errors
|
|
53
81
|
|
|
54
|
-
|
|
82
|
+
An error naming an internal shard mapper, temporary keyspace, backfill store, connector database, or host-side cache is not automatically a Machine Bridge Worker or daemon error. Check whether the exact text appears in repository source, Worker events, daemon logs, or local process output, and whether Worker `requests.server_error` increased. If even `server_info` fails before reaching the Worker while local readiness remains healthy, preserve credentials and state; report the host/connector incident separately rather than rotating OAuth/device secrets or redeploying blindly.
|
|
55
83
|
|
|
56
|
-
|
|
84
|
+
The inverse distinction matters for nested commands. If `exec_command` or `run_process` returns a child exit code plus bounded stdout/stderr, Machine Bridge reached the local process boundary and spawned the child. An `ssh` forced-command usage screen, remote allowlist rejection, or other target-generated refusal in that output belongs to the downstream authorization layer. Do not weaken the bridge policy to repair a restriction demonstrably enforced by the remote target; change the target-side command contract only as narrowly as the required operation demands.
|
|
85
|
+
|
|
86
|
+
After the host path recovers, compare authenticated `server_info`, `machine-mcp doctor`, and `machine-mcp service status`: ready socket count, pending age, daemon PID/start time, `daemon.relay_transport`, and local logs. Treat doctor as local dependency/probe evidence only; it does not inspect the running service relay. A host-storage incident and a genuine stale pending call can coexist; investigate the latter independently if it exceeds its operation or reconnect deadline.
|
|
57
87
|
|
|
58
88
|
### Relay interruption messages
|
|
59
89
|
|
|
60
|
-
A
|
|
90
|
+
A reconnect warning proves a transport interruption, not a daemon crash. Compare daemon PID and process start time with `connected_at`, `last_seen_at`, `daemon.relay_transport.last_close_category`, `last_close_code`, `outage_count`, `outage_attempts`, `previous_ready_inbound_silence_ms`, and the coarse network-route class. While no daemon channel is ready, `server_info.daemon.previous_connection` retains only the last verified channel's transport, connected/last-seen/disconnected timestamps, and sanitized relay diagnostics; it excludes policy, tools, account identity, daemon instance/connection identity, call IDs, arguments, and results, and it never participates in routing or authorization. `outage_duration_ms` measures the close-to-ready recovery episode; `previous_ready_inbound_silence_ms` measures how long the preceding ready socket had stopped producing inbound transport proof before it actually closed. The second value is therefore the field that exposes a black-holed OPEN WebSocket whose visible reconnect later completes quickly. A VPN/TUN UI may remain “connected” while its upstream route is unusable. Local OS logs can be compared with the exact `last_disconnected_at` timestamp, but an interface-quality change or tunnel-process correlation is not by itself proof of which product, node, edge, or upstream failed. Machine Bridge reports only coarse route/proxy classes and never sends or logs interface names, addresses, DNS answers, proxy credentials, or Worker secrets.
|
|
91
|
+
|
|
92
|
+
Brief retryable outages recover automatically. On a verified current daemon channel, `server_info.daemon.relay_transport.outage_active=false`; retained fields describe the immediately preceding transport episode rather than claiming a current outage. WebSocket remains preferred and uses a five-second protocol-level probe with a ten-second inbound-silence timeout. The separate JSON application heartbeat remains twenty-five seconds with a seventy-five-second application-silence timeout, and the Worker keeps a wider ninety-second WebSocket liveness fallback. For a scheduling-responsive daemon, the WSS half-open detection horizon is at most fifteen seconds; that is a detection bound, not a guarantee that a degraded network can complete another WebSocket handshake inside the same interval. If verified WSS readiness is absent, the same root-certified ephemeral daemon identity starts the signed HTTPS fallback. Each fallback request has a seven-second deadline, ordinary one-second poll cadence, 750 ms minimum request-start interval, and twelve-second liveness window; a new daemon-backed call waits at most fifteen seconds for some verified daemon channel, and the measured wait is deducted from that call's original execution budget. After an established WSS disappears, the daemon explicitly marks its signed HTTP request as a same-instance takeover; once candidate preconditions pass, this allows HTTPS to retire a Worker-side zombie WSS that the Worker has not yet observed closing. Malformed, stale, or different-instance requests cannot preempt a healthy incumbent. During replacement, the daemon reconciles `resume_calls`, processes `ready_ack`, proves local readiness, and only then returns `resume_calls_ack.missing_ids`. A missing ID therefore proves both that the same daemon has no active/unacknowledged-result ownership for that call and that the replacement channel is ready. If the initiating MCP response is still open and at least one second remains in the original execution budget, the Worker transparently retransmits exactly that same call ID, arguments, authority, and a reduced timeout. If that safe redelivery cannot be accepted, the call falls back to retryable `unavailable` with `side_effects_started=false`. Calls that may have executed, retained terminal results, different-daemon calls, and ambiguous mutations are never automatically replayed. Compare outage intervals with sleep/wake records and `diagnose_runtime.runtime.relay.heartbeat` before classifying them as active network faults; local stdio `server_info.runtime.relay.heartbeat` exposes the same state. On macOS, an authorized, schema-valid remote tool call also enters a bounded idle-sleep guard with a fixed five-minute inactivity grace; the service does not depend on shell-only environment overrides that launchd would not persist as configuration. Authorized relay handlers hold one shared `/usr/bin/caffeinate -i -w <daemon-pid>` assertion for their full execution lifetime; concurrent handlers share the child, the five-minute default inactivity grace begins only after the last one settles, and a new handler cancels any pending release timer. A remote `start_process` extends the same assertion only after resource admission succeeds and keeps it until the session child settles, so a long process session is not reduced to the handler grace window. Remote account managed-job runners independently hold `/usr/bin/caffeinate -i -w <runner-pid>` after their ownership claim is confirmed and persisted ownership identifies an account-backed job, then retain it through admission, steps, cleanup, and terminal persistence; local managed jobs do not acquire this remote-continuity assertion, and daemon reconnect/replacement does not own the remote runner protection. `diagnose_runtime.runtime.idle_sleep_guard` reports only daemon-side supported/enabled/active/grace/error-class state; it intentionally does not enumerate process-session or job identities. Runtime shutdown terminates process sessions before releasing the daemon guard. None of these assertions claim to prevent explicit sleep or lid-close sleep. A nonzero `event_loop_stall_count` with a large `max_event_loop_lag_ms` means the local daemon was not scheduled promptly; a short stall enters recovery grace, sends a fresh transport probe, and deliberately postpones disconnect. A large stall that aligns with `pmset` Sleep/Wake is suspension evidence, while a large `previous_ready_inbound_silence_ms` without a matching local stall is stronger evidence of a half-open/network-path interruption before close. Use `--verbose` only when close codes, liveness deadlines, and retry delays are required.
|
|
61
93
|
|
|
62
|
-
|
|
94
|
+
A foreground MCP response is not durable delivery. Hosted synchronous calls reserve room for Worker and host settlement instead of occupying the complete interaction window: ordinary daemon-backed tools default to 20 seconds of remote execution plus a separate five-second Worker settlement margin; ordinary configurable browser/application foreground tools also default to 20 seconds, while compound `computer_observe` and `computer_act` default to 30 seconds; all configurable browser/application foreground tools retain their explicit 45-second maximum. Remote `exec_command`, `run_process`, and `run_local_command` no longer keep the child process inside that response lifetime. Each remote process request must carry a unique caller-held `idempotency_key` before dispatch; reuse that same key only when recovering an ambiguous acceptance response. The daemon commits the authorized operation as a principal-bound one-step managed job, launches it with interactive resource-admission priority, and returns a `job_id` plus `read_job` recovery metadata inside a 10-second acceptance budget; the Worker keeps a separate five-second settlement margin. If that acceptance response is lost to settlement timeout, HTTP response cancellation, or relay reconnect expiry after dispatch, the public error remains non-retryable for generic callers but carries the original key and the explicit recovery action `retry_same_tool_arguments_with_same_idempotency_key`; this reconciles against the retained job instead of authorizing a blind duplicate. The detached child may execute for up to 600 seconds after admission, but the managed runner can separately wait up to thirty minutes for cooperative machine-user resource admission before the child is spawned; the child execution deadline begins only after that admission succeeds. The shared ceiling is exposed machine-readably as `server_info.tool_delivery.managed_job_resource_admission_wait_max_ms`, because the same pre-spawn boundary applies to ordinary durable process jobs and owner `start_job` steps rather than to process tools alone. While the runner is in this pre-spawn state, `read_job.current_phase` is `resource_admission`; no command has started yet. An owner can correlate a long-running status at that phase with `diagnose_runtime.runtime.resource_admission` rather than interpreting it as a slow child process; a delegated non-owner should treat the phase itself as evidence that the child has not spawned, retain the same `job_id`, and avoid blind replay rather than attempting the owner-only machine-wide diagnostic. After admission, the phase returns to `steps`, `finally_steps`, or `recovery-cleanup` as appropriate. Completed step records preserve `duration_ms` as the total orchestration duration. Local/owner reads additionally expose `resource_admission_ms` as the pre-spawn portion so a delayed successful child can be distinguished from slow execution after the fact; delegated non-owner reads omit that machine-user scheduling timing rather than turning shared-host contention into a more precise cross-workload signal. The detached job survives MCP disconnect, relay reconnect, daemon restart, or service replacement. Non-owner process authority is unchanged: automatic durable execution still uses the delegated workspace sandbox and does not grant owner-only `start_job`. If a cached host schema omits the now-required key, the Worker rejects before daemon dispatch with a normal no-side-effect tool error and requests a `tools/list` refresh rather than surfacing a protocol-only validation failure. `start_process` remains the explicit daemon-lifetime path when interactive stdin or session-style incremental output is required, but hosted calls use a 10-second execution / 15-second settlement envelope and do not queue behind resource pressure: the first failed admission returns retryable `unavailable`; owner-local callers retain the cooperative wait. Use short `read_process` polls. A new hosted call waits at most fifteen seconds for daemon readiness, but that wait is charged against the call's existing execution budget; an in-flight disconnect likewise never pauses or extends the original absolute deadline. Owner-local stdio/CLI calls retain their synchronous local contract because they do not depend on a hosted response stream. Keep unrelated mutations and verification independently terminal, and never infer task success merely because a durable launch was accepted; read the job to a terminal state.
|
|
63
95
|
|
|
64
|
-
The daemon honors `HTTPS_PROXY`/`HTTP_PROXY` and `NO_PROXY` through standard environment-proxy resolution for remote Worker health and relay traffic. `wss:` targets use HTTPS proxy selection and `ws:` targets use HTTP proxy selection. Only HTTP and HTTPS proxy URLs are accepted. Invalid URLs or unsupported protocols fail startup with corrective guidance instead of entering the reconnect loop. `
|
|
96
|
+
The daemon honors `HTTPS_PROXY`/`HTTP_PROXY` and `NO_PROXY` through standard environment-proxy resolution for remote Worker health and relay traffic. `wss:` targets use HTTPS proxy selection and `ws:` targets use HTTP proxy selection. Only HTTP and HTTPS proxy URLs are accepted. Invalid URLs or unsupported protocols fail startup with corrective guidance instead of entering the reconnect loop. Remote-owner `diagnose_runtime.runtime.relay.network_route` reports this value, while local stdio `server_info.runtime.relay.network_route` reports `system-network-stack`, `application-http-proxy`, or `invalid-application-proxy-configuration`. This field describes only Machine Bridge application-level proxy selection: an operating-system VPN/TUN may still intercept `system-network-stack` traffic. `network_route_scope`, outage timestamps/durations, close category/code, transport error class, and next retry timing make that distinction explicit; proxy endpoints and credentials are never returned or logged. The browser-broker CLI health probe is a separate loopback-only path: it accepts only canonical `127.0.0.1`, uses direct Node HTTP with no proxy agent, and does not depend on `NO_PROXY`.
|
|
65
97
|
|
|
66
98
|
## Browser extension setup and diagnosis
|
|
67
99
|
|
|
@@ -72,7 +104,7 @@ machine-mcp browser setup
|
|
|
72
104
|
machine-mcp browser status
|
|
73
105
|
```
|
|
74
106
|
|
|
75
|
-
`browser setup` prints the unpacked-extension path and opens the local pairing page. Load that directory into the Chromium profile you actually use; it is not installed into Playwright or a separate automation profile. `browser status` prints the authenticated extension build/protocol and the existing-profile backend. The pairing page
|
|
107
|
+
`browser setup` prints the unpacked-extension path and opens the local pairing page. Load that directory into the Chromium profile you actually use; it is not installed into Playwright or a separate automation profile. `browser status` prints the authenticated extension build/protocol and the existing-profile backend. The public pairing URL and HTTP page contain no long-lived credential. An explicit setup/pair action first binds a one-shot random loopback listener owned by the current process and opens that temporary URL; its 30-second bootstrap is confined to the fragment; the packaged `document_start` content script removes the fragment before page scripts and authenticates the broker before the extension receives its long-lived token. The CLI/MCP result never prints the bootstrap or token. A first pairing is automatic. When local pairing state was reset or moved, click the extension icon on the active pairing page while a fresh explicit pair action is still providing bootstrap material to authorize replacing the extension's previous broker configuration.
|
|
76
108
|
|
|
77
109
|
Diagnosis:
|
|
78
110
|
|
|
@@ -97,7 +129,9 @@ Application UI inspection/actions require Accessibility permission for the Node/
|
|
|
97
129
|
|
|
98
130
|
A global npm install changes the CLI files on disk but does not replace an already running Node process. Startup and other state-changing CLI operations use a token/process-identity lock and wait up to 30 seconds for a normal concurrent startup to finish; duration limits use monotonic elapsed time, so NTP or manual wall-clock correction does not lengthen or shorten the wait; a short launchd/systemd overlap is therefore serialized rather than reported immediately as an error. On a normal foreground start, Machine Bridge unloads the platform service and then independently examines the workspace daemon lock. This second path handles a detached/orphan `--daemon-only` process that launchd, systemd, or Task Scheduler no longer tracks. Only current lock records containing service mode, version, PID, process start time, entrypoint, workspace, and state root are eligible for takeover. Before sending `SIGTERM`, Machine Bridge verifies PID and process start time plus the live command line, entrypoint, and daemon-only flag. Explicit `--workspace` and `--state-dir` must both match the active state when present; a recovery daemon started with only `--daemon-only` is accepted when the lock owner already records that workspace and state root. Partial path identity (only one of the two flags) is rejected. If the verified daemon ignores graceful termination, Machine Bridge waits for the grace period, then repeats process-instance and full daemon-identity verification before sending `SIGKILL`. PID reuse, identity drift, foreground mode, or any ambiguity blocks escalation. The total stop remains bounded at 15 seconds and stale lock reclamation still uses token-aware ownership. A foreground or unverifiable process is left untouched; stop a foreground instance with `Ctrl+C`.
|
|
99
131
|
|
|
100
|
-
|
|
132
|
+
Foreground shell, process-session, and managed-job timeouts terminate the complete process group rather than only the direct child. On macOS, ownership capture and revalidation use asynchronous `ps -g <PGID>` so unrelated system-wide process-table load cannot erase all identity evidence or block the daemon event loop. The identity snapshot begins before `SIGTERM`; post-signal refresh and pre-`SIGKILL` revalidation share one three-second monotonic inspection budget and compare exact PID, start time, and PGID. Empty or ambiguous ownership still fails closed; the operation may require manual cleanup rather than risk signaling a reused process.
|
|
133
|
+
|
|
134
|
+
`machine-mcp service status [WORKSPACE]` reports two independent layers: the platform service (`active`) and `workspace_daemon`, plus `effective_active` and `orphaned_workspace_daemon` summary flags. `active` and `effective_active` are tri-state: `true`/`false` mean verified provider evidence, while `null` means the provider query was unavailable or in a state that is unsafe to collapse into inactive. On macOS it is possible for launchd to report inactive while a prior Node process remains alive with parent PID 1; that is an orphan-daemon condition, not proof that the daemon stopped. `service stop` unloads the provider when present and then terminates only a verified service-style workspace daemon. `service uninstall` and full uninstall are ordered fail-closed operations: provider stop → verified daemon stop(s) → definition removal. Full uninstall also runs managed-job retirement maintenance while it holds the state-maintenance and machine-service locks. A generation-matching `retired_job_*` directory left by a crash between quarantine and deletion is reclaimed before the active-state check; a mismatched, wrong-type, or unreadable retired entry remains `unreadable` state and prevents removal of the state root. This internal namespace is not a public job ID and its encoded filesystem identity is not printed in the uninstall blocker. `machine-mcp job list` enters normal managed-job maintenance and may clear a valid retired generation; if uninstall still reports `retired-managed-job:unreadable`, inspect the owner-only state root rather than passing that internal state to `read_job` or deleting it blindly. Final state-root removal is also generation-bound: the validated root is renamed to a reserved sibling retirement name, the moved device/inode plus state marker/allowed-content contract are revalidated, and only that exact generation is recursively deleted. A crash-left valid retired state root is reclaimed on a later uninstall; malformed, wrong-type, mismatched, unreadable, or replaced retired state-root residue is retained and blocks destructive cleanup. Profile/job inventory and removal validation refuse symbolic-link directory traversal and treat only `ENOENT` as absence. A failed or ambiguous stop leaves definitions and state intact. If takeover reaches its deadline, run:
|
|
101
135
|
|
|
102
136
|
```sh
|
|
103
137
|
machine-mcp service stop
|
|
@@ -119,13 +153,47 @@ npm --version
|
|
|
119
153
|
machine-mcp --verbose
|
|
120
154
|
```
|
|
121
155
|
|
|
156
|
+
The published runtime package does not install Wrangler or Miniflare into its global dependency tree. On the first start or deployment, Machine Bridge first constructs a private hardened npm 12.0.1 from exact integrity-pinned npm, undici 6.28.0, and brace-expansion 5.0.9 registry tarballs, then uses that CLI to install the exact private Wrangler toolchain under its owner-only state root. It audits the resulting production tree and verifies registry signatures before contacting Cloudflare. This requires npm registry access and may add one bounded setup step; do not manually edit either private toolchain directory. Candidate installation, published global installation, GitHub Release publication checks, and npm publication also create temporary hardened/private staging sessions. Published installation preserves the global prefix selected by the owner's npm. GitHub and npm artifacts must match the accepted candidate digest/hash evidence before service mutation. Permission, I/O, quota, memory, retry, stale-handle, storage, read-only-filesystem, or timeout errors are not treated as an empty/corrupt tree and must be corrected without deleting the state root.
|
|
157
|
+
|
|
158
|
+
### Ambiguous publication outcome
|
|
159
|
+
|
|
160
|
+
GitHub Release and npm publication reconcile remote state after every irreversible command result. An exact matching remote object may be reported as already matched or recovered even when the client command returned an error. When the command reports an unresolved or ambiguous outcome, do not rerun it. First inspect the exact npm version, SHA-1, SRI, and dist-tag, or the GitHub tag, release metadata, and REST SHA-256 asset. A conflicting immutable object requires a new package version.
|
|
161
|
+
|
|
122
162
|
`Unknown cli config "--allow-scripts"` proves the package installation ran under npm 11 or older. `Invalid property "node"` or `Invalid property "devEngines.node"` means npm parsed an outdated `devEngines` object; inspect the npm debug log to identify its source rather than assuming it belongs to Machine Bridge. The published package declares both Node.js 26 and npm 12 in `engines`, and `machine-mcp doctor` checks both active versions. Keep `--omit=optional` in the install command. Without it npm may resolve optional `fsevents` and warn that its install script was not included in `allowScripts`; Machine Bridge does not require that development-time watcher at runtime.
|
|
123
163
|
|
|
124
164
|
After global installation, Windows users may open any `cmd.exe` window and run `machine-mcp`; they do not need to navigate to a project or package directory. On the first interactive start, the CLI asks for a workspace folder and displays `%USERPROFILE%\MachineBridge` as the default. Pressing Enter creates and remembers that folder. This avoids inheriting an arbitrary Command Prompt current directory such as `C:\Windows\System32`. Typing another folder in the prompt creates that folder when necessary. Explicit `--workspace PATH` remains a strict automation interface and requires an existing path.
|
|
125
165
|
|
|
126
|
-
|
|
166
|
+
### Start, restart, and cross-workspace ownership
|
|
167
|
+
|
|
168
|
+
`service install` writes a machine-global owner record before it touches launchd, systemd, or Task Scheduler. The record is `pending` during provider mutation and becomes `committed` only after the exact canonical workspace, state root, runtime entrypoint, and package version are installed. A partial or ambiguous provider failure remains pending; `service start` and `service restart` then refuse to run until installation is repeated successfully. A missing or malformed owner is reported by `service status` as `missing` or `invalid` rather than hiding the provider diagnostics.
|
|
169
|
+
|
|
170
|
+
`service start` is an idempotent ensure-running operation, but provider state is only an intermediate observation. It loads the committed owner, verifies that no foreground, unverifiable, or orphan service daemon conflicts with it, starts the provider, and waits for the exact service-mode daemon to publish its token-protected startup-readiness checkpoint. The daemon publishes that checkpoint once, only after device authentication, relay probe, and `ready_ack`; a stable launchd PID or a Windows task that briefly reports `Running` is not sufficient. Failed readiness triggers a bounded provider stop and reports whether cleanup itself was verified. A Windows task that completes and returns to `Ready` remains `completed_without_persistence`, even when its process exit code was zero.
|
|
171
|
+
|
|
172
|
+
`service restart` uses the same owner/readiness convergence after its detached service-manager handoff, but unlike idempotent `service start` it must invoke the provider. When the service was already active, success requires both explicit provider restart evidence and a ready replacement daemon PID; the old daemon remaining ready is `daemon_replacement_not_observed`, not success. Windows restart remains fail closed from inside the running task because Task Scheduler `/End` may terminate the helper with the daemon; use an independent terminal stop/start sequence until a behaviorally verified Windows handoff exists.
|
|
173
|
+
|
|
174
|
+
A workspace/state selector does not grant authority over the machine-global service label. All service mutations share one fixed per-user machine-service lock. Operations that also need a workspace startup lock acquire machine-service first; foreground startup releases the machine lock after service takeover and daemon-lock acquisition rather than holding it for the lifetime of the foreground runtime. Stop, restart, foreground takeover, secret rotation, and uninstall still require exact live ownership evidence. Service status returns only provider state, bounded owner metadata, verified daemon state, PID/run counters, readiness, and classified termination state; provider environment dumps and owner paths are never returned.
|
|
175
|
+
|
|
176
|
+
### Candidate activation authentication recovery
|
|
177
|
+
|
|
178
|
+
Exact candidate activation distinguishes ordinary health from device-authenticated relay readiness. The wrapper rejects missing Worker-deployment authorization before downloading or installing, captures the current global rollback package while hardened npm is still live, and allocates a persistent release-channel runtime only for an actual service activation. Install-only operation uses its disposable foreground prefix. Inactive-runtime pruning rejects symlinked or escaping state/release/runtime directories and completes before activation evidence is written. If a current-version candidate receives an explicit authentication rejection, activation redeploys the same Worker once with the unchanged selected device identity and then performs up to ten bounded fresh candidate starts with exponential delay. It does not rotate credentials, create another Worker, or repeat deployment for timeout, TLS, proxy, health, integrity, or policy failures.
|
|
179
|
+
|
|
180
|
+
If activation encounters a failure after remote preparation, compensation installs the compatible candidate definition, starts the platform provider, and separately checks the exact candidate service daemon plus Worker. If the foreground candidate had already completed `ready_ack`, complete candidate-service convergence returns a successful activation with a warning and structured recovery reason. If the foreground candidate never reached readiness, recovery remains diagnostic and the command stays nonzero. An inactive provider, unverified daemon, wrong version/entrypoint, Worker mismatch, or cleanup failure includes both the original cause and the precise recovery reason. Preserve the state root and logs, then inspect:
|
|
127
181
|
|
|
128
|
-
|
|
182
|
+
Persistent candidate activation deliberately uses a stricter ownership transaction than ordinary `service install`. Installing the candidate service definition leaves its machine-global `service_owner` record `pending`; activation passes that pending identity into provider start, verifies the exact service-mode daemon and Worker version, and commits ownership only after convergence while the machine-service lock is still held. A failed initial start may reuse the same pending transaction for compatible candidate recovery, but recovery also commits only after exact convergence. If the candidate remains active without converging, activation stops the uncommitted provider; if final owner commit itself fails after readiness, activation stops the verified provider and retains the pending owner for explicit recovery. It never rewrites the owner to the old committed version after the provider definition may already have changed, because that would create an old-owner/new-definition mismatch.
|
|
183
|
+
|
|
184
|
+
Stopping the previous service is itself a mutation with an ambiguous-settlement boundary. On macOS, `launchctl bootout` may return or become observable before launchd has fully removed the service. The stop helper therefore watches for a safely unloaded provider for up to roughly ten seconds. Once bootout has been dispatched against an initially active service, rollback remains required even if that observation window ends without a verified stop. Activation failure recovery does not make one best-effort `service start` call and leave: it retries the idempotent previous-provider start/bootstrap operation and verifies the exact prior service-mode daemon identity for a bounded 30 attempts. This prevents a late bootout from racing a one-shot rollback and leaving the login daemon offline. A successfully restored previous service does not convert the candidate failure into success; the original candidate error remains the terminal result, with restoration serving only to recover availability.
|
|
185
|
+
|
|
186
|
+
```sh
|
|
187
|
+
machine-mcp service status
|
|
188
|
+
machine-mcp status
|
|
189
|
+
machine-mcp doctor
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Do not use secret rotation, state deletion, manual version edits, or repeated forced deployment as a generic repair. The compatible service is forward recovery for an already advanced Worker; the reported primary error still requires diagnosis. A failed activation command, a missing activation record, or a service recovered by later manual intervention is not candidate acceptance evidence. Candidate activation checks foreground/unverifiable ownership before any service-manager mutation. If a foreground instance is reported, leave it running until the command prints a verified recovery sequence; only a recovery helper that revalidates the PID, daemon lock, command line, workspace, state root, package name, version, and real entrypoint may name the older CLI used to restore the previous login service. Never substitute the candidate CLI for that older runtime before remote transition; after the Worker has advanced, use only the exact compatible runtime identified by the failure diagnostics.
|
|
193
|
+
|
|
194
|
+
## Current upgrade convergence
|
|
195
|
+
|
|
196
|
+
The current release uses MCP `2026-07-28` as its native request-scoped protocol. Native clients send per-request metadata and the required Streamable HTTP headers and do not depend on an initialization-owned session, GET recovery stream, or `Last-Event-ID` replay. Remote HTTP additionally accepts the bounded stateless initialization compatibility dates `2025-06-18` and `2025-11-25` for `initialize`, `notifications/initialized`, `ping`, `tools/list`, and `tools/call`; those requests never mint `Mcp-Session-Id`, persist replay/session state, or restore the removed stateful adapter. Other removed session-protocol requests receive bounded upgrade guidance and cannot dispatch obsolete behavior. Version 3 also requires matching Worker, daemon, CLI, and browser-extension components and may perform a two-phase device-root migration. Preserve the state root and follow [UPGRADING.md](UPGRADING.md); do not delete state to force apparent convergence.
|
|
129
197
|
|
|
130
198
|
Use this sequence:
|
|
131
199
|
|
|
@@ -133,13 +201,13 @@ Use this sequence:
|
|
|
133
201
|
2. Run `machine-mcp --verbose` once. Startup verifies package/Worker versions, performs the ordinary authenticated Worker convergence when needed, stops only a verified service-style old daemon, waits for its lock, and starts the installed version.
|
|
134
202
|
3. Run `machine-mcp status` and `machine-mcp doctor`.
|
|
135
203
|
4. Reload the unpacked browser extension and revisit the pairing page. Exact package version and capability equality are required before browser readiness is reported.
|
|
136
|
-
5. Reconnect MCP clients
|
|
204
|
+
5. Reconnect MCP clients. Native clients rediscover the server and send fresh `2026-07-28` per-request metadata. Remote HTTP clients using the declared `2025-06-18` or `2025-11-25` stateless initialization compatibility may continue through that bounded adapter; clients that require session IDs, recovery GET, replay, or other removed session semantics must upgrade before they can execute those flows.
|
|
137
205
|
|
|
138
206
|
A failed state read, unverifiable process owner, active managed job, Worker authentication failure, or extension version mismatch remains fail closed. Preserve the state root and logs for diagnosis rather than deleting them to force apparent success.
|
|
139
207
|
|
|
140
208
|
## State-root safety and removal
|
|
141
209
|
|
|
142
|
-
The state root must be a dedicated directory and must not equal, contain, or be contained by the selected workspace. Do not point `--state-dir` at a project directory. On POSIX, every state, profile, job, service-log, browser-pairing, and temporary-secret directory is descriptor-opened without following the final symlink, restricted to `0700`, and revalidated; failure stops the operation. State/config and lock files are owner-only, bounded, and committed through flushed atomic primitives. A permission, type, symbolic-link, size, encoding, or I/O failure is reported; only successfully read invalid JSON is moved to a bounded `.corrupt-*` backup. Removal applies the same fail-closed rule to global config, every profile state, and daemon ownership records.
|
|
210
|
+
The state root must be a dedicated directory and must not equal, contain, or be contained by the selected workspace. Do not point `--state-dir` at a project directory. The default profile state is `~/.local/state/machine-bridge-mcp` on POSIX (or the application directory under XDG/APPDATA); the machine-global service lock and owner ledger use a separate sibling control directory ending in `-control`. Never use the control root as `--state-dir` or copy profile state into it. On POSIX, every state, profile, job, service-log, browser-pairing, and temporary-secret directory is descriptor-opened without following the final symlink, restricted to `0700`, and revalidated; failure stops the operation. State/config and lock files are owner-only, bounded, and committed through flushed atomic primitives. A permission, type, symbolic-link, size, encoding, or I/O failure is reported; only successfully read invalid JSON is moved to a bounded `.corrupt-*` backup. Removal applies the same fail-closed rule to global config, every profile state, and daemon ownership records.
|
|
143
211
|
|
|
144
212
|
Uninstall acquires a state-root `maintenance.lock` that blocks new profile/state operations and state-backed operations from already constructed managed-job/browser managers, then scans all known profiles, active managed jobs, daemon/startup locks, global workspace selection, profile state, daemon lock workspace metadata, the state marker, and directory shape. It rechecks jobs and locks after stopping services/daemons. An unreadable lock is treated as a blocker, not as inactivity. Do not manually delete a lock merely because it looks old; inspect the recorded PID and command first.
|
|
145
213
|
|
|
@@ -147,16 +215,16 @@ Uninstall acquires a state-root `maintenance.lock` that blocks new profile/state
|
|
|
147
215
|
|
|
148
216
|
### Lifecycle and pending-call diagnosis
|
|
149
217
|
|
|
150
|
-
`
|
|
218
|
+
Remote-owner `diagnose_runtime.runtime.lifecycle` reports `ready`, `starting`, `running`, `failed`, `stopping`, or `stopped`; `diagnose_runtime.observability.in_flight_calls` reports ordinary versus reserved local capacity; and `diagnose_runtime.runtime.processes` distinguishes active calls, draining calls whose protocol result already settled, currently terminating processes, and pending escalation checks. It also returns `runtime.execution_guardrails`, `runtime.security_audit`, and the privacy-bounded `runtime.idle_sleep_guard` state. Non-owner remote accounts intentionally do not receive these machine-wide activity diagnostics; their `server_info` retains authority-scoped health/capacity and explicit hidden markers instead. Local stdio `server_info` exposes the equivalent detailed fields under `server_info.runtime`, `server_info.observability`, and `server_info.security_audit`. A returned timeout therefore does not claim that all kernel or descendant work has already stopped. Worker `server_info.worker.pending_calls` reports the current in-memory pending-call count, in-flight response-stream request-key count, detached-call count, ordinary/control capacity, and current ordinary/control occupancy. `request_keys` is a transient correlation index, not a durable replay/session store. Terminal result, explicit cancellation, timeout, or reconnect-grace expiry must return the associated `active`, `detached`, and `request_keys` counts to zero. During a brief same-daemon relay interruption, an in-flight call may remain indexed while `detached` identifies the recoverable subset; after same-instance readiness and `resume_calls` reconciliation, `detached` returns to zero without replaying the tool. A nonzero request-key count after active calls reach zero indicates a lifecycle defect rather than normal load. Diagnose late results through `worker.observability.terminal_results`: `owner_missing_acknowledged` is a safely terminated owner-loss/race outcome, while `stale_connection_rejected` is an ownership mismatch. `worker.observability.calls.unmatched_results` is retained only as their aggregate.
|
|
151
219
|
|
|
152
220
|
Stable errors include `policy_denied`, `invalid_request`, `timeout`, `cancelled`, `network_error`, `unavailable`, `limit_exceeded`, and `integrity_error`, with retryability metadata. Diagnose by code first; free-form messages are guidance, not an API contract.
|
|
153
221
|
|
|
154
222
|
|
|
155
223
|
Windows Task Scheduler limits the `/TR` action text, so the platform adapter writes a short private `service-launcher.cmd` under the state root rather than embedding the full Node, package, workspace, state, and logging argv in the task action. The launcher uses CRT-compatible argument quoting, sends stdout/stderr to the normal service logs, exits on a successful daemon exit, and restarts a nonzero exit after five seconds. Task creation is accepted only after a separate state query observes the task. Start, stop, and removal likewise query the Task Scheduler state through fixed PowerShell object properties instead of parsing localized `schtasks` messages; an installed `Ready` task is not mislabeled as currently running.
|
|
156
224
|
|
|
157
|
-
The Windows trigger is current-user `ONLOGON` with `LIMITED` run level. After a reboot, signing in to that user is sufficient; no terminal command is required. Pre-login operation is intentionally not provided by the default design because it would require a different service-account/credential boundary. Remote autostart definitions prefer a stable PATH alias that resolves to the currently running Node executable and persist a sanitized absolute-only service `PATH` containing the Node/
|
|
225
|
+
The Windows trigger is current-user `ONLOGON` with `LIMITED` run level. After a reboot, signing in to that user is sufficient; no terminal command is required. Pre-login operation is intentionally not provided by the default design because it would require a different service-account/credential boundary. Remote autostart definitions prefer a stable PATH alias that resolves to the currently running Node executable and persist a sanitized absolute-only service `PATH` containing the current Node/package directories, the operator's inherited absolute PATH entries, and platform defaults. When installation runs through npm, all nested run-script prefixes through the final npm private `node-gyp-bin` marker are discarded; paths belonging to inactive candidate runtimes are also removed. This prevents prerelease activation from persisting source-repository shims or the prior runtime that activation subsequently prunes, while an ordinary user-supplied `node_modules/.bin` remains valid. A private allowlisted `service-environment.json` preserves `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`, matching lowercase forms, optional `ALL_PROXY`, Node proxy selection, and custom-CA path variables. Existing saved values survive an environment-free reinstall, while explicitly supplied values replace case-insensitive prior variants. Values may include proxy credentials, so the file stays in owner-only state and is never returned or logged; status exposes key names only. Re-run `machine-mcp service install` after changing Node installation families, PATH layout, proxy, or CA configuration. Custom Windows state paths used for autostart must also remain within the Task Scheduler path limit and must not contain a literal `%`.
|
|
158
226
|
|
|
159
|
-
A service-style `--daemon-only` start that finds the same workspace daemon already running is an idempotent no-op: it exits successfully without repeating warnings or readiness output; explicit policy/secret/change requests still report that changes were not applied. Autostart logs are stored under the state root in `logs/daemon.out.log` and `logs/daemon.err.log`. Installed services pass `--log-level warn --log-format json`, so each active line is a bounded JSON event suitable for ingestion. Files are owner-only where supported and tail-trimmed before daemon startup. If the log schema marker does not match the current format, the active files are cleared before startup and the current marker is written. Runtime code reads and maintains only the active filenames.
|
|
227
|
+
A service-style `--daemon-only` start that finds the same workspace daemon already running is an idempotent no-op: it exits successfully without repeating warnings or readiness output; explicit policy/secret/change requests still report that changes were not applied. Autostart logs are stored under the state root in `logs/daemon.out.log` and `logs/daemon.err.log`. Installed services pass `--log-level warn --log-format json`, so each active line is a bounded JSON event suitable for ingestion. Files are owner-only where supported and tail-trimmed before daemon startup and every 15 minutes while the background daemon remains active. Runtime maintenance reuses the same no-follow, regular-file, single-link, `0600`, schema, UTF-8, and line-boundary checks. If the log schema marker does not match the current format, the active files are cleared before startup and the current marker is written. Runtime code reads and maintains only the active filenames.
|
|
160
228
|
|
|
161
229
|
Logging is level-based:
|
|
162
230
|
|
|
@@ -208,21 +276,40 @@ Inspect detached jobs even when the MCP host no longer permits execution tools:
|
|
|
208
276
|
```sh
|
|
209
277
|
machine-mcp job list
|
|
210
278
|
machine-mcp job inspect JOB_ID
|
|
211
|
-
machine-mcp job approve JOB_ID [--yes]
|
|
212
279
|
machine-mcp job cancel JOB_ID
|
|
213
280
|
machine-mcp job submit plan.json
|
|
214
281
|
```
|
|
215
282
|
|
|
216
283
|
Registry changes apply to newly submitted jobs without restarting the daemon. Active jobs use the resource snapshot accepted with their plan.
|
|
217
284
|
|
|
218
|
-
Policy changes affect new
|
|
285
|
+
Policy changes affect new submissions. Cancel accepted running jobs explicitly when revoking execution authority. A staged plan is a non-running draft and has no terminal promotion path. A trusted owner uses `start_job`; an explicit local operator may submit a reviewed JSON plan with `job submit`. A managed job transitions through `queued`, `running`, `cleaning`, and a terminal status such as `succeeded`, `failed`, or `cancelled`. Cleanup-specific terminal variants report a failed finally phase. If a runner PID dies, the next daemon/job-CLI start marks the job interrupted, removes stale private runtime copies, and runs the finally phase in recovery mode. Recovery never replays ordinary business steps: a terminal `recovered` status means recovery/finally work completed after the original runner was interrupted, not that the main steps succeeded. The result compatibility field `recovered=true` only records that recovery mode produced the terminal result; `recovery_failed` and `recovery_exhausted` remain failures even when that field is true, so automation must branch on terminal `status`. Automatic recovery is capped at three attempts; persistent failure becomes `recovery_exhausted`.
|
|
219
286
|
|
|
220
287
|
Use job-scoped `temporary_files` for local helpers. For remote maintenance, prefer `ssh ... sh -s` with the remote script in step `stdin`; this avoids remote temporary scripts. Explicit remote cleanup belongs in idempotent `finally_steps`.
|
|
221
288
|
|
|
222
|
-
Uninstall refuses to remove local state while any managed job remains active. Active plans are needed for recovery and are owner-only. Terminal jobs delete their full plans.
|
|
289
|
+
Uninstall refuses to remove local state while any managed job remains active. Active plans are needed for recovery and are owner-only. Terminal jobs delete their full plans. At most 50 jobs are retained: terminal results normally remain for up to seven days but the oldest safely removable terminal record may be evicted earlier to reserve capacity for a new job, while staged drafts expire after 24 hours and active/staged/unreadable state is never evicted merely to make room. Step output is never copied to ordinary daemon logs.
|
|
223
290
|
|
|
224
291
|
See [MANAGED_JOBS.md](MANAGED_JOBS.md).
|
|
225
292
|
|
|
293
|
+
## Hosted OAuth failure diagnosis
|
|
294
|
+
|
|
295
|
+
Preserve credentials and state until evidence identifies the failing boundary. A hosted client's generic “connect your account” message does not distinguish registration, user authorization, token exchange, persistence, MCP scanning, or host-side failure.
|
|
296
|
+
|
|
297
|
+
Use the deployed Worker and account inventory to narrow the path:
|
|
298
|
+
|
|
299
|
+
| Observation | Classification / next action |
|
|
300
|
+
|---|---|
|
|
301
|
+
| `/oauth/register` fails before authorization | Dynamic-registration/metadata boundary; inspect status/error class and registered redirect contract. |
|
|
302
|
+
| `/oauth/authorize` returns 401/429 and no trusted binding is created | Account-credential or authorization-rate-limit boundary. Confirm the submitted account name/password locally; do not rotate them merely to test another theory. |
|
|
303
|
+
| `/oauth/authorize` succeeds, the client becomes trusted, but `/oauth/token` returns 500 and the client remains `access=0 refresh=0` | Token-exchange or token-persistence boundary. Preserve the client/account and use the bounded token-stage/error class. Password rotation, DPoP changes, state deletion, or client recreation cannot repair a failure proven to occur after successful authorization. |
|
|
304
|
+
| `/oauth/token` returns 200 and client inventory shows active access/refresh credentials, but no authenticated `/mcp` request succeeds | Leave OAuth unchanged and diagnose MCP protocol/catalog/host scanning. |
|
|
305
|
+
| Initial MCP succeeds but continuity fails after the access-token lifetime | Diagnose refresh rotation/retry/persistence and confirm the active refresh-family state; do not infer refresh success from initial authorization. |
|
|
306
|
+
|
|
307
|
+
For production tails, collect only what is needed to classify the request: method, route/URL, response outcome/status when available, content type, fixed header-presence booleans such as `has_dpop`, and Machine Bridge's bounded `error_class`. Never paste or log raw Authorization/DPoP headers, OAuth form bodies, authorization codes, PKCE verifiers, access/refresh tokens, account passwords, JWKs, or raw exception messages. `wrangler tail` output is sampled operational evidence; absence of a sampled event is not proof that the request did not occur.
|
|
308
|
+
|
|
309
|
+
When a token failure is ambiguous, fixed low-cardinality stages such as load/validate/issue/persist/response are preferred over speculative code changes. The deployed-edge result outranks a local emulator for deployed Durable Object behavior. A local Wrangler/workerd pass remains a required regression layer, but a hosted-runtime discrepancy must be retained as a separate finding rather than normalized away.
|
|
310
|
+
|
|
311
|
+
After an OAuth persistence repair, acceptance requires all of the following against the exact deployed candidate: authorization-code `/oauth/token` success, active access and refresh credentials in admin inventory, an authenticated MCP request that reaches the expected live daemon, and at least one successful refresh-token rotation. If token lifetime/long-running continuity is material to the change, verify the connection across that boundary as a separate soak observation. Do not record release acceptance from the connector UI alone.
|
|
312
|
+
|
|
226
313
|
## Hosted OAuth reconnection
|
|
227
314
|
|
|
228
315
|
Hosted clients may refresh access without asking the user to authorize again. Machine Bridge returns a replacement refresh token on every successful public-client refresh and invalidates the presented token. `invalid_grant` therefore means the token was already rotated, expired, or revoked by an account change or deployment-wide token-version rotation. Remove and reconnect the hosted connector; repeatedly retrying the stale token cannot recover it.
|
|
@@ -235,7 +322,7 @@ The daemon sends heartbeats and reconnects with bounded exponential backoff and
|
|
|
235
322
|
|
|
236
323
|
The Worker tracks inbound `lastSeenAt` and reclaims ready or probing sockets that go silent past their applicable liveness/readiness windows. Diagnose with `daemon.readiness_verified`, `worker.sockets_live.ready`, `worker.sockets_live.probing`, and `daemon.last_seen_at`; cumulative `worker.observability.sockets.authenticated` is an event counter, not current liveness. A state with no ready daemon is unavailable by construction rather than falsely online. Restart the daemon only after inspecting the classified timeout/protocol error; refreshing an MCP client does not repair the local transport.
|
|
237
324
|
|
|
238
|
-
Pending calls are bound to the socket that received them. Results from another socket are ignored. A lost or replaced socket rejects only its own pending calls and
|
|
325
|
+
Pending calls are bound to the socket that received them. Results from another socket are ignored. A lost or replaced socket rejects only its own pending calls and begins termination of locally tracked child process trees. The result/cancellation boundary and the operating-system drain boundary are separate: cleanup ownership remains visible until child close or bounded escalation settlement. Process sessions are in-memory and do not survive daemon restart or replacement.
|
|
239
326
|
|
|
240
327
|
## Limits
|
|
241
328
|
|
|
@@ -253,13 +340,14 @@ Defense-in-depth limits include:
|
|
|
253
340
|
- running or completed process-session retained output: 1 MiB per stream for up to 30 minutes, best effort subject to the eight-session capacity, with monotonic offsets and lossless base64 fallback for non-UTF-8 slices;
|
|
254
341
|
- process sessions: 8 retained per runtime;
|
|
255
342
|
- process stdin write: 64 KiB per call;
|
|
256
|
-
- local simultaneous tool calls: 16;
|
|
257
|
-
- Worker pending daemon calls: 32;
|
|
258
|
-
-
|
|
259
|
-
-
|
|
343
|
+
- local simultaneous tool calls: 16 total, with 14 ordinary slots and two reserved for bounded control-plane diagnosis/recovery;
|
|
344
|
+
- Worker pending daemon calls: 32 total, with 30 ordinary slots and two reserved for bounded control-plane diagnosis/recovery;
|
|
345
|
+
- synchronous remote timeout schema: ordinary daemon-backed tools default to 20 seconds, ordinary configurable browser/application operations default to 20 seconds, compound `computer_observe`/`computer_act` default to 30 seconds, all configurable browser/application operations retain their 45-second explicit maximum, and remote `exec_command`, `run_process`, and `run_local_command` use a 10-second durable-acceptance window while their detached execution timeout may be 1–600 seconds. The Worker still uses a separate five-second settlement margin. Hosted `start_process` has a 10-second execution / 15-second settlement envelope and performs resource admission without queueing; use short `read_process` polls for session work, and use the durable process tools or `start_job`/`read_job` when work must survive an MCP disconnect, daemon restart, or service replacement;
|
|
346
|
+
- tool-schema rollout is backward-compatible for lowered maximums: if a host has cached an older `tools/list` definition that still permits a configurable foreground timeout above 45 seconds or `read_process.wait_ms` above 5000, the Worker rejects that value before daemon dispatch as an MCP tool error (`invalid_request`, no side effects, schema refresh recommended) rather than a JSON-RPC protocol error. Durable process execution is a separate 1–600-second contract and is not subject to the removed 30-second foreground ceiling. Genuinely malformed argument types/fields and unrelated schema violations remain protocol errors;
|
|
347
|
+
- process-session read wait: local calls may wait at most 30 seconds; hosted remote projection caps each wait at 5 seconds. The process and retained output session are not shortened by that polling limit;
|
|
260
348
|
- direct directory result: 10,000 entries and 4 MiB of path metadata;
|
|
261
349
|
- recursive walk: 200,000 visited entries;
|
|
262
|
-
- managed jobs: 50 retained
|
|
350
|
+
- managed jobs: 50 retained; terminal results normally up to seven days with oldest-terminal capacity eviction, staged drafts 24 hours;
|
|
263
351
|
- managed-job steps: 16 main plus 16 finally;
|
|
264
352
|
- managed-job timeout: 1–3,600 seconds per step;
|
|
265
353
|
- managed-job output: 64 KiB per stream and 256 KiB total captured across one job;
|
|
@@ -269,7 +357,13 @@ Defense-in-depth limits include:
|
|
|
269
357
|
- application Accessibility inspection: 500 elements and depth 12; action text: 4,000 characters;
|
|
270
358
|
- job-scoped temporary files: 16 files, 512 KiB total content.
|
|
271
359
|
|
|
272
|
-
The list above describes bounded application resources, not OS quotas. CPU time shares, resident-memory ceilings, syscall sandboxes, and egress policy must be imposed by the account/container/VM that runs Machine Bridge.
|
|
360
|
+
The list above describes bounded application resources, not OS quotas. CPU time shares, resident-memory ceilings, syscall sandboxes, and egress policy must be imposed by the account/container/VM that runs Machine Bridge. A remote owner can check `diagnose_runtime.runtime.execution_guardrails.operating_system_enforcement`; local stdio exposes the same contract at `server_info.runtime.execution_guardrails.operating_system_enforcement`. Non-owner remote accounts do not receive machine-wide diagnostics. Current in-process values are intentionally `not-enforced` rather than inferred from timeouts or output limits.
|
|
361
|
+
|
|
362
|
+
Machine Bridge additionally uses cooperative machine-user resource admission for process roots. This does not change the OS-enforcement statement above. For a remote owner, `diagnose_runtime.runtime.resource_admission` reports the current Green/Yellow/Red pressure state, aggregate CPU/I/O/memory/disk reservations, waiter counts, the number of aged protected waiters, and `waiters.drain_active`; it does not expose command text or project paths. `pressure.state=green` means the sampled host/reservation pressure is within limits, not that fairness can admit every queued root immediately: `drain_active=true` means an aged feasible protected waiter currently outranks fitting backfill and is intentionally reserving a drain window until blocking coordinator-owned reservations clear. Non-owner accounts do not receive this machine-wide pressure/activity projection. Interactive MCP execution waits at most about two seconds for heavy/adaptive capacity and then returns a retryable `unavailable` error with `reason=resource_admission`; detached managed jobs wait inside their runner instead of occupying an MCP call slot. Light control/read operations remain available. Waiters use priority-aware bounded exponential backoff with jitter rather than synchronized fixed-cadence polling; an explicit lease release, stale-lease prune, owned waiter removal after cancellation/timeout, or stale/expired-waiter prune inside the same daemon interrupts that timer immediately so local capacity or fairness changes are reevaluated without waiting for the next poll, while cross-process changes retain the bounded retry path. Stale waiter removal revalidates ownership and filesystem identity and fails closed if the record changes before deletion. Host probes are single-flight per anonymous project scope inside one daemon; CPU/mixed/adaptive work uses the quick pressure path, while fresh blocking I/O probes are reserved for I/O-dominant or unbounded work. Quick host evidence is reused wholesale for at most 500ms so a completed CPU burst cannot consume most of the interactive admission-wait budget. CPU cumulative counters are machine-global, so a recent anchor may be reused across project scopes for at most two seconds to avoid a needless cold sample; older anchors force a fresh 50ms CPU window so a long idle interval cannot smear current pressure into a stale average. Disk headroom and cached I/O evidence remain project/filesystem scoped and never cross that boundary. Process ancestry is sampled only when a lease exists and nested-envelope accounting can use it.
|
|
363
|
+
|
|
364
|
+
Backfill remains work-conserving until an aged rank-zero request is both feasible in principle and blocked by current coordinator-owned project/CPU/I/O/memory/disk reservations; only that case stops admitting later fitting work long enough for capacity to drain. Nested heavy roots are accounted as a live process-ancestry forest rather than as an unconditional sum: an orchestration parent is an envelope, direct lease children may consume that envelope, and only excess child demand increases the reservation. Each child still owns a complete durable lease, so if the parent disappears while a detached child survives, the child's full request becomes independently chargeable on the next accounting pass. A nested request may ignore same-key contention only from its actual ancestor lease chain; same-key siblings still serialize. If process ancestry cannot be sampled, the coordinator intentionally falls back to full summation. CPU admission combines measured busy cores with only reservation that started after the measurement or is still provisional; reservation already visible in the host sample is not charged twice. When admission policy expands a request for safety—for example, mapping unknown/unbounded CPU fan-out to the current CPU admission limit—the same full reservation is materialized into the durable lease rather than reverting to the smaller profile hint after admission, so subsequent roots and surviving nested children see the capacity that was actually approved. Yellow pressure is dimension-scoped rather than a global tax: CPU busy/CPU PSI tightens CPU limits, disk throughput/I/O PSI/soft disk headroom tightens I/O limits, and memory/pageout/swap/memory PSI tightens memory limits. `heavy_root_count` remains visible as advisory density telemetry but does not, by itself, reduce unrelated resource limits; actual reservations and host bottleneck signals remain authoritative. On macOS, load average is treated as runnable-thread backlog and does not tighten admission without corroborating CPU/I/O pressure. Disk headroom uses proportional floors with bounded absolute caps rather than fixed minimum free-space requirements, so small volumes are not permanently classified as pressured while large volumes still retain a bounded safety reserve. On Linux, `MemAvailable` and optional PSI avg10 values supplement reservations: missing PSI stays unknown, 10% recent stalls tighten admission, and severe sustained memory-full pressure stops new heavy roots. These are scheduling signals, not cgroup limits or kill policy.
|
|
365
|
+
|
|
366
|
+
The default coordinator root is per-user (`~/.local/state/agent-resource-coordinator` on POSIX unless `XDG_STATE_HOME` applies; platform equivalents are used elsewhere). `AGENT_RESOURCE_COORDINATOR_ROOT` is an explicit override for compatible local controllers. Coordinator transactions use the same complete-before-visible owner-state file lock as other local ownership mutations; stale reclamation and release are bound to the published ownership token and filesystem generation rather than a separately populated directory claim. Same-project contention keys are derived from the canonical existing filesystem path, not the caller's lexical alias; compatible implementations must preserve that rule so symlinked roots and macOS `/var`/`/private/var` aliases coordinate as one project. Build caches default to a separate per-user cache root; `AGENT_BUILD_ROOT` overrides it. On macOS the default is `~/Library/Caches/AgentBuilds.noindex`. Do not point either override into a shared/untrusted directory: records are deliberately owner-only and malformed ownership fails closed. Explicit Cargo/Swift/Xcode build-path flags or environment are preserved rather than overwritten. When no explicit worker count is supplied, direct Cargo/Swift/Xcode and direct make/ninja/cmake/Gradle/Maven/Go builds treat the coordinator's default compiler fan-out as a ceiling. On every admission iteration the coordinator fits that ceiling to the smaller of measured CPU headroom and durable CPU-reservation headroom, atomically updates the same schema-1 waiter request before fairness selection, and preserves the waiter's ID, enqueue time, and aging rank. An implicit build can therefore shrink under pressure and re-expand when capacity recovers without requeueing; the eventual lease request is authoritative for argv/environment enforcement. The elasticity marker remains process-local and never enters the waiter/lease schema. Verification plans use the same rule through `MBM_CHECK_CONCURRENCY`; because their memory reservation is explicitly derived from fan-out, it contracts with the fitted worker count down to the plan's 2048 MiB floor instead of retaining a stale larger-worker reservation. An empty `MBM_CHECK_CONCURRENCY` has the runner's normal implicit/default meaning and may be replaced by the fitted worker count; a non-empty value outside the runner's `1..16` integer contract is preserved and classified unbounded rather than silently rewritten or charged as the default. Explicit worker counts and valid `CARGO_BUILD_JOBS`/`CMAKE_BUILD_PARALLEL_LEVEL` values are never shrunk; they are preserved and charged at their declared concurrency. Cargo's current jobs syntax is modeled exactly for explicit values: negative `--jobs`/`CARGO_BUILD_JOBS` values mean logical CPUs plus the negative offset, `default` means the logical-CPU default, CLI jobs override the environment, and arguments after Cargo's `--` separator do not alter build fan-out. Invalid, zero, nonpositive-after-offset, or out-of-contract values remain conservatively unbounded. When Cargo has no explicit jobs setting, Machine Bridge still keeps its own elastic ceiling rather than inheriting Cargo's unrestricted logical-CPU default. Maven thread settings include the 3.9+ `MAVEN_ARGS` environment layer as well as argv. Because Maven prepends `MAVEN_ARGS` before the user's CLI arguments and Commons CLI returns the first thread-option value, a thread option there is authoritative even if a later argv `-T` differs; Machine Bridge charges and preserves that first value instead of injecting a later ineffective cap. Core-multiplier forms such as `-T2.5C` are translated to Maven's current integer `multiplier × available processors` degree for admission accounting. Visible GNU make configuration in `GNUMAKEFLAGS`/`MAKEFLAGS` (including make's implicit leading dash, compact short-option clusters, and jobserver state) is likewise charged without injecting a higher-precedence replacement flag. Gradle fan-out follows its current configuration layers: `JAVA_OPTS` is applied before `GRADLE_OPTS` by the launcher, direct `-Dorg.gradle.workers.max=...`/`--system-prop=...` updates the system-property map after those JVM options, and `--max-workers` is the final build-option override. The last system-property value is charged when it is valid; a valid CLI `--max-workers` then supersedes that bound. Invalid final worker properties fail before the CLI build-option converter can recover them, while repeated or invalid `--max-workers` values also fail during command-line/build-option validation, so those forms use the lightweight pre-build validation profile rather than waiting for heavy capacity. Malformed JVM-option quoting and valid worker counts above Machine Bridge's modeled maximum remain fail-closed as unbounded. Go fan-out follows the current go command's own ordering and validation semantics: quoted `GOFLAGS` is applied first, direct `-p`/`--p` values then override it, and repeated numeric settings use the final effective value. `go test` build flags remain recognizable through its package-list parser but stop at `-args`/`--args`/`--` or once positional test arguments begin; ordinary `go build` stops flag parsing at its first package operand. A final nonpositive numeric `-p` is treated as lightweight pre-build validation because the go command rejects it before compiler fan-out, while malformed/non-numeric `GOFLAGS` is fatal before a later CLI value can recover it. If a direct `-p` could instead be the value of a preceding flag whose arity is not provable from the command shape, Machine Bridge fails closed as unbounded rather than using the validation fast path. SwiftPM fan-out now follows its scalar `UInt32` `@Option(.shortAndLong)` semantics: repeated `-j`/`--jobs` settings use the final value; `-j N`, `-j=N`, `--jobs N`, and `--jobs=N` are modeled, including `+N` values accepted by `UInt32`. A final zero remains unbounded because SwiftPM forwards zero to llbuild and llbuild substitutes hardware concurrency; a valid count above the modeled maximum is likewise unbounded unless a later scalar option replaces it. Direct missing, non-UInt32, or unsupported joined-short forms such as `-j8` use the lightweight pre-build validation profile, while shell-composed Swift is bounded only when the shell contains a single provable Swift segment; multi-segment or otherwise ambiguous compositions remain unbounded. Xcodebuild now distinguishes actual build/test invocations from its independent query, package-resolution, export/import, platform/component-maintenance, and other non-build modes before build-root handling, so commands such as `-help`, `-usage`, `-resolvePackageDependencies`, `-showBuildSettings`, and `-exportArchive` are never polluted by injected `-jobs` or `-derivedDataPath`. Non-build resource admission is workload-specific rather than the generic 0.5-CPU adaptive fallback: metadata/settings queries use a small adaptive profile; package resolution is a project-serialized mixed workload with a 4 GiB disk safety reservation; archive/localization/xcframework import-export is project-serialized I/O with an 8 GiB reservation; platform/component install/download/prepare operations are unbounded high-I/O with an 8 GiB minimum safety reservation; component deletion remains I/O-heavy but does not invent future disk consumption or receive the privileged disk-reclaim bypass. These disk figures are admission safety reservations, not claims that the native operation cannot consume more space. For build concurrency, current Xcode uses separated `-jobs NUMBER` for the native jobs option and accepts a leading `+` there. Lookalike `-jobs=...` tokens do not receive the same native jobs validation, so Machine Bridge never treats them as hard concurrency bounds. Canonical zero/negative separated values fail before building, and a second real `-jobs` option is rejected outright; those proven validation failures use the lightweight pre-build profile. Canonical positive separated values within the modeled range are charged exactly, while equals forms, noncanonical values that Xcode may parse by numeric prefix, and oversized values remain conservatively unbounded rather than being guessed into a hard ceiling. Xcode test/test-without-building remains overall unbounded even when build-phase `-jobs` is known, because the native command exposes independent destination concurrency and parallel-testing runner counts; a known/default build-phase cap is still enforced separately without pretending it bounds test execution. Direct Ninja `-j` now follows current getopt semantics rather than generic first-match parsing: repeated `-j` options use the final value, `-j0` is effectively infinite/unbounded, and negative/non-numeric jobs or the unsupported `--jobs` spelling use the lightweight pre-build validation path because Ninja exits before starting the build. Any valid positive direct `-jN` is an exact local worker bound and disables inherited jobserver participation. Ninja 1.13+ jobserver coordination is preserved when no direct `-j` is present and `MAKEFLAGS` contains a jobserver form Ninja actually supports: FIFO authentication on POSIX or semaphore authentication on Windows. A jobserver-aware Ninja root is treated as cooperative/unbounded for admission even when `MAKEFLAGS` also exposes `-jN`, because current Ninja can fail to initialize the inherited jobserver and then continue with its native local parallelism; Machine Bridge therefore does not claim that inherited token count is a hard execution ceiling or inject a local `-j`. The jobserver parser follows Ninja's current MAKEFLAGS rules: dry-run flag letters disable jobserver use, the last recognized auth/fds descriptor wins, negative descriptors disable the feature, POSIX pipe descriptors are rejected, and FIFO/semaphore modes are platform-specific. The preservation marker is process-local and never enters the schema-1 coordinator record. For pytest-xdist, explicit numeric `-n` is charged directly, `-n 0` is treated as single-process execution, and dynamic `-n auto`/`logical` remains unbounded unless an explicit `--maxprocesses=N` supplies a hard worker ceiling; environment auto-worker hints are not treated as hard limits because project hooks can override them. CMake build concurrency follows the current build-driver precedence rather than generic first-match parsing: repeated `-j`/`--parallel` options use the final CMake-level value, a positive CLI value overrides `CMAKE_BUILD_PARALLEL_LEVEL`, and invalid/zero/too-large pure CLI or environment values use the lightweight pre-build validation path because CMake rejects them before invoking the native build tool. A value-less `-j`/`--parallel` or defined-empty parallel environment remains unbounded because it delegates to the native tool. An uninspected `--preset` build or any native-tool arguments after CMake's `--` separator are also conservatively unbounded and are not rewritten with an injected worker cap: build presets can supply `jobs` and `nativeToolOptions`, while native options are generator-specific and can change fan-out independently of the CMake-level setting. Explicit concurrency forms that cannot be bounded safely (for example unlimited/value-less or out-of-contract fan-out) are treated conservatively as unbounded instead of being under-accounted. Shell-wrapped implicit Swift and generic builds that cannot be safely rewritten likewise remain unbounded; on POSIX, unbounded heavy work runs at a small positive nice increment to protect interactive responsiveness, while background heavy work uses the stronger background nice increment.
|
|
273
367
|
|
|
274
368
|
## Upgrade behavior
|
|
275
369
|
|
|
@@ -293,40 +387,40 @@ machine-mcp --workspace /path/to/project --profile agent
|
|
|
293
387
|
|
|
294
388
|
A remote policy change is saved locally, propagated in the daemon handshake, and loaded by autostart from owner-only state.
|
|
295
389
|
|
|
296
|
-
### Remote authority and
|
|
297
|
-
|
|
298
|
-
The saved profile defines the capability ceiling. An authenticated owner account may use that ceiling directly and is never required to approve a pending ID in a terminal. Delegated reviewer, editor, and operator accounts still require bounded leases for consequential remote effects. Inspect their pending requests and active leases with:
|
|
390
|
+
### Remote authority and client trust
|
|
299
391
|
|
|
300
|
-
|
|
301
|
-
machine-mcp --workspace /path/to/project approval list
|
|
302
|
-
```
|
|
392
|
+
The saved profile defines the daemon capability ceiling. Remote authority additionally requires the authenticated account role, trusted OAuth client binding, current account version and refresh family, and ownership of any long-lived object.
|
|
303
393
|
|
|
304
|
-
|
|
394
|
+
Inspect accounts and trusted clients with:
|
|
305
395
|
|
|
306
396
|
```sh
|
|
307
|
-
machine-mcp --workspace /path/to/project
|
|
308
|
-
machine-mcp --workspace /path/to/project
|
|
397
|
+
machine-mcp --workspace /path/to/project account list
|
|
398
|
+
machine-mcp --workspace /path/to/project account clients
|
|
309
399
|
```
|
|
310
400
|
|
|
311
|
-
Revoke
|
|
401
|
+
Revoke a compromised or stale client independently:
|
|
312
402
|
|
|
313
403
|
```sh
|
|
314
|
-
machine-mcp --workspace /path/to/project
|
|
315
|
-
machine-mcp --workspace /path/to/project approval clear
|
|
404
|
+
machine-mcp --workspace /path/to/project account revoke-client CLIENT_ID --yes
|
|
316
405
|
```
|
|
317
406
|
|
|
318
|
-
The
|
|
407
|
+
Delegated roles cannot be elevated by an approval ID or lease. The current runtime has no approval/lease command surface and never consumes operation leases. During state load, a known obsolete `operation-leases.json` from an older installation is removed as a one-time migration cleanup only after it is verified as an unchanged single-link regular file; aliases or replacement files fail closed. Full details are in [LOCAL_AUTHORIZATION.md](LOCAL_AUTHORIZATION.md).
|
|
319
408
|
|
|
320
409
|
## Incident response
|
|
321
410
|
|
|
322
|
-
After suspected credential or
|
|
411
|
+
After suspected credential, client, or device compromise:
|
|
323
412
|
|
|
324
413
|
1. stop foreground and autostart daemons;
|
|
325
|
-
2.
|
|
326
|
-
3.
|
|
327
|
-
4.
|
|
328
|
-
5.
|
|
329
|
-
6.
|
|
330
|
-
7.
|
|
414
|
+
2. revoke the affected OAuth client, or disable/rotate the affected account;
|
|
415
|
+
3. clear any verified obsolete version 2 leases that remain as one-time migration hygiene;
|
|
416
|
+
4. run `machine-mcp rotate-secrets` when device-root or deployment-wide token compromise is possible;
|
|
417
|
+
5. restart with the intended profile, deploy the matching Worker, and reconnect only trusted clients;
|
|
418
|
+
6. inspect Cloudflare access, Worker configuration, device-root provider, audit-chain health, local state/resource permissions, process-lock owners, managed-job results, and service logs;
|
|
419
|
+
7. cancel active managed jobs and remove compromised resource aliases;
|
|
420
|
+
8. remove the Worker and local state if continued remote access is unnecessary.
|
|
331
421
|
|
|
332
422
|
The detailed 0.12.0 audit record and residual operational limits are in [AUDIT.md](AUDIT.md).
|
|
423
|
+
|
|
424
|
+
### Worker pending-call budget
|
|
425
|
+
|
|
426
|
+
`server_info.worker.pending_calls` reports bounded aggregate in-memory dispatched ownership, pre-dispatch daemon waiters, and their shared capacity. MCP request bodies and terminal results are not written as a delivery/replay log, and there is no `durable_budget` MCP stream counter. Unexpected growth in active/detached pending calls or pre-dispatch waiters, repeated reconnect expiry, or sustained admission pressure should block release and be diagnosed against daemon readiness and relay health.
|