machine-bridge-mcp 2.0.0 → 3.0.0-beta.11

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.
Files changed (147) hide show
  1. package/CHANGELOG.md +120 -0
  2. package/CONTRIBUTING.md +20 -25
  3. package/README.md +21 -14
  4. package/SECURITY.md +147 -123
  5. package/browser-extension/manifest.json +3 -2
  6. package/browser-extension/service-worker.js +31 -12
  7. package/docs/ARCHITECTURE.md +28 -13
  8. package/docs/AUDIT.md +101 -2
  9. package/docs/CLIENTS.md +2 -2
  10. package/docs/ENGINEERING.md +9 -3
  11. package/docs/GETTING_STARTED.md +10 -9
  12. package/docs/LOCAL_AUTHORIZATION.md +115 -72
  13. package/docs/LOGGING.md +14 -3
  14. package/docs/MANAGED_JOBS.md +24 -29
  15. package/docs/MULTI_ACCOUNT.md +98 -37
  16. package/docs/OPERATIONS.md +34 -23
  17. package/docs/OVERVIEW.md +7 -7
  18. package/docs/PROJECT_STANDARDS.md +9 -5
  19. package/docs/RELEASING.md +171 -64
  20. package/docs/TESTING.md +21 -9
  21. package/docs/THREAT_MODEL.md +138 -67
  22. package/docs/TOOL_REFERENCE.md +2 -2
  23. package/docs/UPGRADING.md +102 -18
  24. package/native/macos/MachineBridgeTrustBroker.swift +233 -0
  25. package/package.json +37 -6
  26. package/scripts/candidate-runtime-store.mjs +38 -0
  27. package/scripts/check-plan.mjs +19 -0
  28. package/scripts/check-runner.mjs +4 -1
  29. package/scripts/commit-message-check.mjs +5 -2
  30. package/scripts/coverage-check.mjs +30 -2
  31. package/scripts/github-push.mjs +11 -0
  32. package/scripts/github-release.mjs +38 -7
  33. package/scripts/install-published-prerelease.mjs +167 -0
  34. package/scripts/local-release-acceptance.mjs +23 -12
  35. package/scripts/npm-publication-policy.mjs +16 -0
  36. package/scripts/prerelease-activation.mjs +79 -0
  37. package/scripts/privacy-check.mjs +7 -5
  38. package/scripts/promotion-digest.mjs +121 -0
  39. package/scripts/publish-npm.mjs +51 -0
  40. package/scripts/published-release.mjs +87 -0
  41. package/scripts/release-acceptance.mjs +30 -1
  42. package/scripts/release-candidate-manifest.mjs +40 -0
  43. package/scripts/release-channel.mjs +106 -0
  44. package/scripts/release-impact-check.mjs +12 -22
  45. package/scripts/release-soak.mjs +237 -0
  46. package/scripts/start-release-candidate.mjs +113 -7
  47. package/src/local/account-access.mjs +6 -0
  48. package/src/local/account-admin.mjs +34 -16
  49. package/src/local/agent-context.mjs +45 -42
  50. package/src/local/app-automation.mjs +9 -4
  51. package/src/local/authority-context.mjs +106 -0
  52. package/src/local/browser-bridge-http.mjs +4 -1
  53. package/src/local/browser-bridge.mjs +14 -9
  54. package/src/local/browser-broker-routes.mjs +4 -0
  55. package/src/local/browser-broker-server.mjs +5 -4
  56. package/src/local/browser-extension-identity.mjs +50 -0
  57. package/src/local/browser-extension-protocol.mjs +9 -4
  58. package/src/local/browser-operation-service.mjs +7 -0
  59. package/src/local/browser-pairing-http.mjs +36 -0
  60. package/src/local/browser-pairing-store.mjs +56 -47
  61. package/src/local/cli-account-admin.mjs +41 -7
  62. package/src/local/cli-activate.mjs +90 -0
  63. package/src/local/cli-approval.mjs +14 -58
  64. package/src/local/cli-local-admin.mjs +5 -15
  65. package/src/local/cli-options.mjs +11 -7
  66. package/src/local/cli-service.mjs +35 -5
  67. package/src/local/cli.mjs +119 -58
  68. package/src/local/daemon-process.mjs +6 -0
  69. package/src/local/delegated-process-sandbox.mjs +147 -0
  70. package/src/local/device-identity.mjs +157 -48
  71. package/src/local/device-root-provider.mjs +87 -0
  72. package/src/local/errors.mjs +25 -3
  73. package/src/local/git-service.mjs +16 -15
  74. package/src/local/job-runner.mjs +35 -27
  75. package/src/local/log.mjs +18 -44
  76. package/src/local/macos-trust-broker.mjs +320 -0
  77. package/src/local/managed-job-lock.mjs +18 -0
  78. package/src/local/managed-job-projection.mjs +9 -1
  79. package/src/local/managed-job-runner.mjs +13 -1
  80. package/src/local/managed-job-storage.mjs +2 -1
  81. package/src/local/managed-job-terminal.mjs +138 -0
  82. package/src/local/managed-jobs.mjs +88 -32
  83. package/src/local/operation-authorization.mjs +75 -239
  84. package/src/local/operation-risk.mjs +28 -0
  85. package/src/local/operation-state-lock.mjs +7 -86
  86. package/src/local/owner-state-lock.mjs +104 -0
  87. package/src/local/policy.mjs +19 -0
  88. package/src/local/process-execution.mjs +21 -9
  89. package/src/local/process-sessions.mjs +27 -17
  90. package/src/local/process-tracker.mjs +30 -6
  91. package/src/local/process-tree-ownership.mjs +59 -0
  92. package/src/local/process-tree.mjs +22 -18
  93. package/src/local/relay-connection.mjs +47 -35
  94. package/src/local/relay-diagnostics.mjs +65 -0
  95. package/src/local/remote-configuration.mjs +48 -0
  96. package/src/local/runtime-activation.mjs +141 -0
  97. package/src/local/runtime-diagnostics.mjs +21 -0
  98. package/src/local/runtime-relay.mjs +9 -8
  99. package/src/local/runtime-reporting.mjs +8 -3
  100. package/src/local/runtime-resource-service.mjs +77 -0
  101. package/src/local/runtime-tool-handlers.mjs +8 -8
  102. package/src/local/runtime.mjs +85 -95
  103. package/src/local/secure-file.mjs +5 -1
  104. package/src/local/security-audit-log.mjs +204 -0
  105. package/src/local/service-convergence.mjs +17 -1
  106. package/src/local/service-ownership.mjs +17 -0
  107. package/src/local/service-restart-handoff.mjs +50 -0
  108. package/src/local/service-restart-scheduler.mjs +49 -0
  109. package/src/local/service-status.mjs +47 -0
  110. package/src/local/service.mjs +142 -43
  111. package/src/local/state-inventory.mjs +21 -3
  112. package/src/local/state.mjs +155 -17
  113. package/src/local/stdio.mjs +5 -0
  114. package/src/local/tool-executor.mjs +39 -6
  115. package/src/local/tool-result-boundary.mjs +51 -0
  116. package/src/local/tools.mjs +1 -0
  117. package/src/local/trusted-executable.mjs +53 -0
  118. package/src/local/trusted-git-executable.mjs +34 -0
  119. package/src/local/trusted-github-cli.mjs +24 -0
  120. package/src/local/windows-service.mjs +20 -0
  121. package/src/local/worker-deployment.mjs +3 -4
  122. package/src/local/worker-secret-file.mjs +2 -2
  123. package/src/local/workspace-file-service.mjs +34 -31
  124. package/src/shared/admin-auth.d.mts +2 -1
  125. package/src/shared/admin-auth.mjs +3 -3
  126. package/src/shared/device-session-auth.d.mts +20 -0
  127. package/src/shared/device-session-auth.mjs +51 -0
  128. package/src/shared/log-redaction.d.mts +9 -0
  129. package/src/shared/log-redaction.mjs +51 -0
  130. package/src/shared/server-metadata.json +1 -1
  131. package/src/shared/tool-catalog.json +2 -2
  132. package/src/worker/account-admin.ts +23 -22
  133. package/src/worker/authority.ts +23 -4
  134. package/src/worker/daemon-auth.ts +45 -67
  135. package/src/worker/daemon-sockets.ts +12 -2
  136. package/src/worker/device-session-verifier.ts +129 -0
  137. package/src/worker/dpop.ts +151 -0
  138. package/src/worker/http.ts +47 -16
  139. package/src/worker/index.ts +53 -16
  140. package/src/worker/nonce-store.ts +1 -5
  141. package/src/worker/oauth-client-admin.ts +45 -0
  142. package/src/worker/oauth-controller.ts +55 -6
  143. package/src/worker/oauth-refresh-families.ts +21 -7
  144. package/src/worker/oauth-state.ts +6 -0
  145. package/src/worker/oauth-tokens.ts +28 -8
  146. package/src/worker/observability.ts +4 -2
  147. package/src/worker/websocket-protocol.ts +8 -2
@@ -1,111 +1,154 @@
1
- # Local transaction authorization
1
+ # Local authorization model
2
2
 
3
- Machine Bridge separates **available capability** from **current remote authority**.
3
+ Machine Bridge treats **capability**, **identity**, and **object ownership** as separate controls. A tool is executable only when every control permits it.
4
4
 
5
- The canonical `full` profile still exposes the complete tool catalog, unrestricted local-user paths, shell execution, browser and application automation, managed jobs, absolute paths, and the complete parent environment. It remains the default for a trusted owner. Version 2.0 does not redefine or narrow that profile.
5
+ For a remote request, effective authority is:
6
6
 
7
- An authenticated `owner` account activates the capabilities permitted by the daemon policy ceiling without a second terminal approval step. This preserves uninterrupted owner automation while retaining OAuth identity binding, account-version revocation, device authentication, and the daemon policy as hard boundaries.
8
-
9
- For delegated `reviewer`, `editor`, and `operator` accounts, the local daemon applies a final transaction gate after the Worker and local runtime have checked the account role and daemon policy. Ordinary project work remains automatic; an operation that crosses a consequential boundary requires a short-lived local capability lease.
10
-
11
- Local stdio calls are not affected by this remote transaction gate. They remain governed by the selected local policy and the MCP host's own approval model.
12
-
13
- ## What remains automatic
14
-
15
- Remote calls do not require a lease for:
7
+ ```text
8
+ daemon capability ceiling
9
+ authenticated account role
10
+ ∩ trusted OAuth client binding
11
+ current account version and refresh-token family
12
+ ∩ per-object ownership checks
13
+ ```
16
14
 
17
- - project discovery, status, diagnostics, ordinary metadata, and owner-configured Machine Bridge Agent guidance intended for MCP clients;
18
- - reads inside the selected workspace, except credential-sensitive paths;
19
- - ordinary source and configuration writes inside the selected workspace, excluding credential- and persistence-sensitive targets;
20
- - transactional patches whose source, destination, and move targets remain inside the selected workspace and outside sensitive targets;
21
- - Git inspection;
22
- - browser broker status without reading profile content;
23
- - installed-application discovery without inspecting an application UI;
24
- - registered-resource metadata inspection.
15
+ No approval record, token refresh, client reconnect, or local command can expand the account role. A narrower layer always wins.
25
16
 
26
- This is the normal delegated-account coding and review path. A trusted owner is not interrupted by local approval prompts. For non-owner browser work, one reusable profile-session lease covers the session rather than prompting per page read, field, or click.
17
+ Local stdio does not use remote OAuth accounts. It runs as the local owner under the selected local policy and remains subject to the MCP host and operating-system controls.
27
18
 
28
- ## What requires a lease
19
+ ## Account roles
29
20
 
30
- The daemon requests local authorization for these remote effects:
21
+ | Role | Effective purpose | Important limits |
22
+ |---|---|---|
23
+ | `reviewer` | Read-only inspection of the selected workspace | No mutation or process execution |
24
+ | `editor` | Workspace reads and deterministic file mutation | No process execution |
25
+ | `operator` | Workspace-confined editing and direct process execution | No unrestricted paths, credentials, browser/desktop control, or persistent job creation |
26
+ | `owner` | Complete bridge authority within the daemon policy ceiling | Generic path-based tools cannot target Machine Bridge control-plane state; owner shell remains OS-user authority |
31
27
 
32
- | Scope | Examples |
33
- |---|---|
34
- | `shell` | shell commands, direct process launch, process output continuation, interactive process input or termination, registered local commands |
35
- | `external-read` | reading, searching, imaging, or inspecting a path outside the selected workspace |
36
- | `sensitive-read` | reading credential-sensitive locations or names such as SSH/AWS/Keychain state, `.env`, tokens, secrets, or private keys |
37
- | `external-write` | writing, editing, patching, or moving a patch target outside the selected workspace |
38
- | `sensitive-write` | writing credentials, live `.env` files, SSH/privilege files, shell startup files, Git hooks, LaunchAgents/LaunchDaemons, or other persistence-sensitive paths even when they are inside the selected workspace |
39
- | `browser-session` | listing or reading tabs, source, screenshots, waits, navigation, form input, clicks, submission, tab management, or extension pairing in the existing browser profile |
40
- | `data-export` | uploading a file, inserting a registered local resource into a browser or desktop application, or filling an explicitly sensitive browser field |
41
- | `persistent-job` | staging, starting, listing, reading output from, or cancelling a managed job |
42
- | `application-control` | opening, inspecting, or operating a desktop application |
43
- | `credential-operation` | generating an SSH key resource |
44
- | `full` | all of the above for one explicit temporary automation window |
28
+ The daemon may advertise the complete catalog as its capability ceiling. The Worker filters `tools/list` by account role, and the local runtime independently recomputes and validates the same role boundary before dispatch.
45
29
 
46
- Classification uses canonicalized paths and bounded operation metadata. A single operation may require more than one scope: for example, a browser upload requires both `browser-session` and `data-export`, and an external credential read requires both `external-read` and `sensitive-read`. Existing leases may satisfy those scopes independently. A pending approval contains only the scopes still missing, and approving it creates one compound lease for those missing scopes. Pending records contain a SHA-256 target digest, not command text, file contents, form values, or uploaded bytes.
30
+ ## Trusted OAuth clients
47
31
 
48
- Write targets are canonicalized through their nearest existing ancestor even under `full`. A path that enters an in-workspace symbolic-link directory is classified by the real destination, while overwriting a final symbolic link is rejected. Patch `Move to` destinations are classified alongside add/update/delete paths. This preserves unrestricted-path capability without allowing path aliases to weaken the lease boundary.
32
+ Dynamic OAuth registration creates an untrusted client record. The first successful account authorization binds that client to:
49
33
 
50
- The browser boundary is intentionally session-granular. The packaged extension controls whichever Chromium profile the user loaded it into; Machine Bridge cannot prove that the profile is isolated. Requiring one `browser-session` lease protects tab metadata and authenticated page content without degrading into per-click prompts. Once granted, ordinary browser reads, navigation, filling, and clicks proceed continuously until expiry. Exporting registered local data remains separately gated.
34
+ - one account ID;
35
+ - the account version at authorization time;
36
+ - the account role;
37
+ - the OAuth client ID.
51
38
 
52
- ## Optional delegated-account approval flow
39
+ A client cannot silently switch to another account. Account disablement, role changes, password rotation, client revocation, token-version rotation, and refresh-token replay invalidate the relevant credentials.
53
40
 
54
- Owner requests never create pending approval IDs. When a lease is missing for a non-owner account, the tool call fails with `local_approval_required` and a command containing a random pending approval ID. List pending requests and active leases locally:
41
+ Inspect trusted clients locally:
55
42
 
56
43
  ```sh
57
- machine-mcp --workspace /path/to/project approval list
44
+ machine-mcp account clients --workspace /path/to/project
58
45
  ```
59
46
 
60
- Approve only the requested scope for one hour:
47
+ Revoke one client and all of its authorization codes, access tokens, and refresh tokens:
61
48
 
62
49
  ```sh
63
- machine-mcp --workspace /path/to/project approval approve APPROVAL_ID --duration 1h
50
+ machine-mcp account revoke-client CLIENT_ID --workspace /path/to/project
64
51
  ```
65
52
 
66
- Then retry the original task. Further matching operations from the same account and OAuth client run without interruption until the lease expires.
53
+ Account-management requests are signed by a root-certified ephemeral device session. Machine Bridge does not deploy or retain a long-lived account-administration bearer or HMAC secret.
67
54
 
68
- For a trusted, intensive automation session, convert the same pending request into an explicit temporary `full` window:
55
+ ## Automatic execution
69
56
 
70
- ```sh
71
- machine-mcp --workspace /path/to/project approval approve APPROVAL_ID --full
72
- ```
57
+ There is no per-operation approval prompt in the current runtime.
73
58
 
74
- `--full` defaults to eight hours and cannot exceed eight hours. It is local, account-bound, client-bound, time-bounded, and revocable. It does not change the saved policy profile or extend itself remotely.
59
+ Within the effective role and daemon ceiling, calls execute automatically. Outside that intersection, calls fail immediately with `authorization_denied`; the response does not contain an approval ID or a command to retry.
75
60
 
76
- A specific scope can also be granted in advance. Account and OAuth client IDs are available from `approval list --json` after the client has produced a pending request. Wildcards are supported only when entered explicitly:
61
+ Examples:
77
62
 
78
- ```sh
79
- machine-mcp --workspace /path/to/project approval grant shell \
80
- --account ACCOUNT_ID --client CLIENT_ID --duration 2h
81
- ```
63
+ - a reviewer may inspect files inside the selected workspace;
64
+ - an editor may update ordinary workspace files;
65
+ - an operator may run a workspace-confined process only when the delegated process sandbox is behaviorally verified;
66
+ - an owner may use shell, unrestricted paths, browser/application automation, resources, and managed jobs when enabled by the daemon policy.
82
67
 
83
- ## Revocation
68
+ Risk classification still runs for every consequential request. It supplies structured audit metadata and enforces hard boundaries; it is not a mechanism for temporary privilege escalation.
84
69
 
85
- Revoke one lease:
70
+ ## Hard boundaries
86
71
 
87
- ```sh
88
- machine-mcp --workspace /path/to/project approval revoke LEASE_ID
89
- ```
72
+ ### Machine Bridge control plane
90
73
 
91
- Revoke every active remote capability lease for the workspace:
74
+ Generic path-based file, image, search, and patch tools cannot target Machine Bridge state, device-root metadata, account-management state, audit-chain state, service metadata, or other protected roots. This applies to `owner` as well as delegated accounts.
92
75
 
93
- ```sh
94
- machine-mcp --workspace /path/to/project approval clear
95
- ```
76
+ This is an application-level path boundary, not an arbitrary-code sandbox. An authorized `owner` shell or interpreter has the daemon OS user's ambient filesystem authority. Control-plane administration uses local CLI interfaces; mutually untrusted owner execution requires external OS isolation.
77
+
78
+ ### Sensitive and persistent targets
79
+
80
+ Non-owner accounts cannot access credential- or persistence-sensitive targets, including live environment files, private keys, token stores, shell startup files, Git hooks, privilege configuration, LaunchAgents, LaunchDaemons, and equivalent persistence locations.
81
+
82
+ Final symbolic-link overwrites are rejected. Existing ancestors and patch move destinations are canonicalized before classification so a workspace alias cannot conceal an external or sensitive destination.
83
+
84
+ ### Browser, desktop, and data export
85
+
86
+ Only `owner` may control the existing browser profile or desktop applications, upload local files, or inject registered resources into an interactive session. Browser and application actions operate on the user's logged-in session and therefore are not delegated to lower roles.
87
+
88
+ ### Persistent jobs
96
89
 
97
- Stopping the daemon prevents execution while it is offline, but leases remain in owner-only state until expiry or explicit revocation. Incident response should therefore stop the daemon, clear leases, revoke or rotate affected OAuth credentials, and inspect account/client state.
90
+ Only `owner` may create persistent execution plans with `start_job` or non-executing drafts with `stage_job`.
98
91
 
99
- ## Binding and storage
92
+ `stage_job` does not execute and is not an approval workflow. The removed `machine-mcp job approve` path cannot turn a draft into a running job. Execution requires a trusted owner request through `start_job`, or an explicit local `job submit` operation performed by the machine operator.
100
93
 
101
- Every lease binds:
94
+ ## Delegated process isolation
95
+
96
+ An `operator` process is not accepted merely because its current directory and environment are restricted. Machine Bridge requires a behaviorally verified OS sandbox that:
97
+
98
+ - exposes the selected workspace and an isolated runtime directory;
99
+ - blocks the real user home and Machine Bridge state;
100
+ - blocks Keychain and desktop automation access;
101
+ - preserves the minimum system runtime needed by ordinary tools.
102
+
103
+ The probe is fail-closed. The presence of a sandbox executable is not sufficient.
104
+
105
+ On platforms where the negative security boundary cannot be verified, delegated process execution is unavailable. Owner execution remains governed by the selected daemon policy. For mutually untrusted workloads, use a separate OS account, container, or VM.
106
+
107
+ Implementation-owned metadata probes are a separate boundary from delegated arbitrary execution. `project_overview` and the read-only Git tools use fixed argv selected by Machine Bridge, never a caller-provided executable or shell string. Those probes run with a minimal isolated environment, bounded output and deadlines, cancellation/process-tree tracking, and the request’s path-visibility rules. They do not grant `run_process`, registered-command, or shell authority to reviewer/editor accounts.
108
+
109
+ ## Object ownership
110
+
111
+ Long-lived runtime objects bind to the principal that created them:
102
112
 
103
113
  - account ID;
114
+ - account version;
104
115
  - OAuth client ID;
105
- - one or more explicitly approved scopes, or the standalone `full` scope;
106
- - creation and expiration times;
107
- - an optional source pending-approval ID.
116
+ - refresh-token family ID.
117
+
118
+ The binding applies to interactive processes, retained command-output sessions, and managed jobs. Another account, client, or refresh family cannot read, continue, send input to, cancel, or terminate those objects.
119
+
120
+ ## Device-root authorization
121
+
122
+ The default root on every platform is a portable owner-only P-256 key. It signs the 24-hour ephemeral session certificate without Keychain access or a user-presence prompt. On macOS, `MBM_MACOS_TRUST_BROKER` may explicitly select a separately provisioned app-like broker; only after its code signature, Team ID, canonical non-symlink path with no group/other write access, and real Secure Enclave key probe validate does a non-exportable root replace the portable provider. That provider requests user presence once when signing the daemon session certificate. The private session key remains in memory and handles WebSocket preflight, challenge authentication, reconnects, and local account administration for that daemon lifetime.
123
+
124
+ Expected interaction frequency:
125
+
126
+ - ordinary tool calls: no local prompt;
127
+ - portable-root daemon startup: no prompt;
128
+ - provisioned Secure Enclave daemon startup: one user-presence prompt;
129
+ - network reconnect: no prompt;
130
+ - an independent account-management command: no prompt with a portable root, or one prompt with a provisioned Secure Enclave root;
131
+ - root rotation: one explicit operation, with user presence only when the provisioned broker requires it.
132
+
133
+ Every platform uses the portable P-256 provider unless an explicitly configured non-exportable platform provider has been installed and validated. `server_info.security.device_root` reports the active provider and whether the root key is exportable.
134
+
135
+ ## DPoP
136
+
137
+ OAuth clients that support DPoP may bind access and refresh tokens to their own P-256 key. The Worker validates the proof method, URL, timestamp, nonce identifier, access-token hash, and key thumbprint. A copied token is insufficient without the client private key.
138
+
139
+ Bearer remains available for MCP hosts that do not implement DPoP. Client trust, account versioning, refresh-family rotation, and role ceilings still apply.
140
+
141
+ ## Audit and incident response
142
+
143
+ The local security audit is a bounded SHA-256 hash chain. It records operation class, outcome, duration, byte counts, target digest, and salted principal references. It does not record command text, file paths, file contents, form values, or tool output.
144
+
145
+ For incident response:
108
146
 
109
- Normal scopes may last at most twelve hours. `full` may last at most eight hours. Pending requests expire after ten minutes. Lease and pending files are size-bounded, owner-only, atomically replaced, schema-validated, and validated record by record. Daemon-created pending requests and separate CLI approval/revocation processes serialize mutations through an owner-only process-identity lock, preventing lost updates during concurrent use. Malformed state or lock metadata fails closed.
147
+ 1. stop the daemon;
148
+ 2. revoke the affected OAuth client or disable the account;
149
+ 3. rotate the account password or global token version when appropriate;
150
+ 4. rotate the device root when device identity may be compromised;
151
+ 5. inspect the audit-chain health and local endpoint logs;
152
+ 6. restart and reconnect only trusted clients.
110
153
 
111
- This is an application-level control, not an OS sandbox. A process already running as the same OS user can interfere with local files and memory. Use a separate OS account, VM, or container when the client, repository, or instructions are mutually untrusted.
154
+ Legacy capability-lease files from version 2 may still be listed, revoked, or cleared by the local CLI for migration cleanup. The version 3 runtime never consumes them and never creates pending approval IDs.
package/docs/LOGGING.md CHANGED
@@ -12,7 +12,7 @@ Logs should answer:
12
12
  4. Is an infrastructure, protocol, deployment, or local service problem requiring action?
13
13
  5. When debug logging is explicitly enabled, which bounded implementation event should be correlated?
14
14
 
15
- Logs are not a command history or content audit trail. Local capability-lease state provides authorization evidence without recording command text or content, but it is not a tamper-proof forensic ledger and is not a substitute for OS isolation.
15
+ Logs are not a command history or content transcript. The local security audit provides a bounded SHA-256 hash chain over coarse operation metadata without recording command text, paths, contents, form values, or output. It detects local alteration but is not a remote immutable ledger and is not a substitute for OS isolation.
16
16
 
17
17
  ## Levels
18
18
 
@@ -25,6 +25,7 @@ The CLI accepts:
25
25
  ```
26
26
 
27
27
  Foreground mode defaults to `info` and human-readable text. Platform autostart services use `warn` with newline-delimited JSON. Foreground operators can select JSON explicitly with `--log-format json`.
28
+ In JSON mode, every logger entry point—including direct level methods and the persistent daemon-ready transition—emits exactly one timestamped JSON object per line. No operational method may silently fall back to the human formatter.
28
29
 
29
30
  Human mode treats the message as the primary interface: it uses a natural-language explanation and includes only bounded diagnostic fields that add meaning. It does not repeat the machine event key. JSON mode retains the stable `event` field for ingestion and correlation. Event identifiers such as `relay.tool_result.discarded` are implementation contracts for structured logs, not text that should be shown as the warning itself.
30
31
 
@@ -93,7 +94,7 @@ The implementation omits:
93
94
  - stdin, stdout, and stderr;
94
95
  - file, patch, image, and temporary-file content;
95
96
  - OAuth request bodies;
96
- - account passwords, account-administration HMAC keys/signatures, daemon device private keys/signatures, authorization codes, access tokens, refresh tokens, and capability-lease target material;
97
+ - account passwords, root/session signatures, device private keys, authorization codes, access tokens, refresh tokens, DPoP proofs, and legacy-lease target material;
97
98
  - registered resource values and source paths;
98
99
  - browser pairing tokens, page URLs/source, DOM metadata, form values, uploaded file bytes, and screenshots;
99
100
  - application names, Accessibility trees, selectors, and entered values;
@@ -111,6 +112,8 @@ Application discovery and Accessibility operations follow the same rule: permiss
111
112
 
112
113
  Messages, strings, object depth, object key counts, array item counts, and serialized field payloads are bounded. Control characters and Unicode display controls are neutralized. Fields with secret-like names and path-like keys are recursively redacted. Free-form sanitization covers generic private-key headers, AWS/GitHub/GitLab/npm/Slack/Google/live-payment/API token forms, JWT-shaped values, URLs with embedded credentials, email addresses, and user-home paths.
113
114
 
115
+ Local and Worker free-form strings use the same portable value sanitizer. Worker fields are therefore inspected by content even when their key is not secret-shaped. Both structured loggers assign their authoritative metadata after sanitizing caller fields. Local `timestamp`, `level`, `component`, `message`, and `event`, plus Worker `timestamp`, `level`, `component`, and `event`, therefore cannot be forged or replaced by an event payload. Local-only recursive path-key redaction and environment-derived home aliases remain additional protections around the portable rules.
116
+
114
117
  The logger exposes two intentional plain-output boundaries. `safePlain` sanitizes operational guidance and diagnostic text. Raw `plain` output is reserved for explicitly requested credentials or local paths whose display is the command's purpose; callers must not pass external exception text or tool content to it.
115
118
 
116
119
  This is defense in depth, not content classification. Unknown, split, transformed, encrypted, or application-specific secret formats can evade pattern matching, which is why tool arguments and outputs are omitted rather than merely filtered.
@@ -136,9 +139,17 @@ The log format has an explicit schema marker. If the marker differs from the cur
136
139
 
137
140
  Each managed job has owner-only runner diagnostic logs. Child-step output is retained only in bounded, redacted job results according to `capture_output`; it is not copied into daemon or runner operational logs.
138
141
 
142
+ ## Relay outage records
143
+
144
+ `network_route` describes only Machine Bridge's application-level proxy decision. `system-network-stack` does **not** mean a direct physical path: an operating-system VPN, TUN, packet tunnel, DNS interceptor, or endpoint-security product may still carry the connection. `network_route_scope` therefore remains `application-proxy-selection-only`.
145
+
146
+ During an outage, `server_info.runtime.relay` and `diagnose_runtime` expose bounded operational fields: outage count/start/duration, last close category/code, coarse transport error class, last disconnect/ready time, prior ready duration, and next retry timing. `relay.outage.active` and `relay.outage.recovered` carry the same safe fields. Raw WebSocket close reasons, IP addresses, proxy endpoints/credentials, DNS answers, tool arguments, and results are not promoted to default logs.
147
+
148
+ Schema 4 is strict NDJSON. Before daemon startup, both active log files are opened as owner-only regular single-link files. A schema change clears both only after validation and commits the marker only after the transition succeeds. A symlink, multiple-hard-link inode, permission error, or marker-write failure blocks startup rather than mixing formats or repeatedly erasing evidence.
149
+
139
150
  ## MCP host boundary
140
151
 
141
- Canonical `full` does not remove tools based on filenames. For remote execution, the transaction classifier treats credential-sensitive path segments and basenames as a lease boundary while preserving the underlying capability. An MCP host, connector, model provider, desktop application, operating system, or endpoint-security layer may independently reject a request before it reaches Machine Bridge.
152
+ Canonical `full` does not remove tools based on filenames. For remote execution, the operation classifier treats credential-sensitive paths and persistence targets as hard authorization boundaries: delegated roles are denied, while owner requests remain risk-classified and audited. An MCP host, connector, model provider, desktop application, operating system, or endpoint-security layer may independently reject a request before it reaches Machine Bridge.
142
153
 
143
154
  Use `server_info`, `project_overview`, `machine-mcp status`, `machine-mcp doctor`, and `diagnose_runtime` to distinguish local policy from host-side enforcement. Capability-routing status is returned on demand rather than written as task logs; it stores a runtime-keyed task fingerprint, not raw task text. Changing the Machine Bridge profile cannot override another layer.
144
155
 
@@ -113,6 +113,14 @@ Environment injection is convenient but may expose a value to same-user process
113
113
 
114
114
  At job acceptance, referenced resources are reopened, bounded, hashed, and recorded in the owner-only active plan. The runner reopens and verifies the hash before copying. A changed resource causes the job to fail rather than silently using different content.
115
115
 
116
+ ## Terminal persistence and sensitive-plan cleanup
117
+
118
+ A job terminal transition is not a single best-effort write. The runner first attempts the bounded `result.json`, then persists a conservative terminal `status.json` with cleanup pending, then removes the private runtime directory, active plan, PID claim, cancellation marker, and transition/recovery artifacts, and finally confirms cleanup state. A result-write failure is visible as `result_persisted=false`; a status-write failure leaves every recovery artifact intact. Artifact removal failures remain visible as `artifact_cleanup_pending` and are retried by later read/list/prune operations.
119
+
120
+ If the runner writes a valid terminal result but exits before terminal status is committed, the manager reconstructs status from that result before considering recovery. This prevents a completed finally sequence from being replayed merely because the status write was interrupted. If no valid terminal result exists, recovery may still repeat finally work, so finally steps must remain idempotent.
121
+
122
+ Unexecuted staged plans can contain stdin, environment values, and temporary scripts. They expire after 24 hours and are converted to a non-executing terminal record; ordinary completed-job metadata may remain under the separate seven-day retention policy. A minimal-environment plan also launches its detached runner with a minimal control environment. Full parent-environment inheritance occurs only when the accepted plan explicitly captured that policy.
123
+
116
124
  ## Job-scoped temporary files
117
125
 
118
126
  Do not create ad hoc helpers in the workspace when the file exists only for one operation. Include it in the job:
@@ -191,35 +199,26 @@ Finally steps are attempted after success, failure, timeout, or cancellation. Ca
191
199
 
192
200
  Automatic dead-runner recovery is attempted at most three times; persistent failure becomes `recovery_exhausted` to avoid an endless restart loop. Cleanup is best effort, not mathematically guaranteed. Power loss, disk failure, permanent account loss, or a local security product that denies the cleanup executable can still prevent it. Finally steps should therefore be idempotent and safe to run more than once.
193
201
 
194
- ## Two-phase local approval
202
+ ## Non-executing staged drafts
195
203
 
196
- If the MCP host rejects execution-class tools but still allows state changes, use:
204
+ `stage_job` performs the same schema, cwd, resource, size, and permission validation as `start_job`, but records status `staged` and launches no process.
197
205
 
198
- ```text
199
- stage_job
200
- ```
206
+ A staged record is a review artifact, not an authorization request:
201
207
 
202
- This performs the same schema, cwd, resource, size, and permission validation as `start_job`, but records status `staged` and launches no process. The response includes the local approval command:
208
+ - it contains no executable approval token;
209
+ - it cannot be promoted by `machine-mcp job approve`;
210
+ - no main or finally step runs;
211
+ - no registered resource is copied into a runtime directory;
212
+ - cancellation produces `cancelled_before_start` and removes the plan.
203
213
 
204
- ```sh
205
- machine-mcp job inspect JOB_ID
206
- machine-mcp job approve JOB_ID
207
- # or after a separate review, non-interactively:
208
- machine-mcp job approve JOB_ID --yes
209
- ```
210
-
211
- `job inspect` displays the reviewable plan, including argv, ordinary environment overrides, stdin, temporary helper content, and finally steps, while omitting registered resource source paths and per-resource hashes. The overall `plan_sha256` is displayed for review and is revalidated atomically during approval and again by the runner before execution. A modified staged plan is rejected.
214
+ Use `machine-mcp job inspect JOB_ID` to review the stored plan. The projection includes argv, ordinary environment overrides, stdin, temporary helper content, and finally steps while omitting registered resource source paths and per-resource hashes. The overall `plan_sha256` is displayed and remains integrity-checked.
212
215
 
213
- Local approval is a new operator authorization. It intentionally does not depend on the current MCP execution profile: a plan staged under a write-capable profile can be reviewed and approved from the terminal even when the connector is not allowed to execute. The plan retains the filesystem scope and environment mode captured when it was staged.
216
+ Execution requires a separate authority-bearing action:
214
217
 
215
- Before approval:
218
+ - a trusted owner submits the plan through `start_job`; or
219
+ - the local machine operator submits a reviewed JSON plan with `machine-mcp job submit PLAN.json`.
216
220
 
217
- - no main step runs;
218
- - no finally step runs;
219
- - no resource is copied into a runtime directory;
220
- - cancelling produces `cancelled_before_start` and deletes the plan.
221
-
222
- Staged plans count toward the 50-item retention limit and expire with the seven-day job retention policy. They are not considered active processes and do not independently block uninstall after the normal uninstall confirmation.
221
+ The current runtime does not implement copy-an-ID, approve, and retry workflows. Staged drafts count toward the 50-item retention limit and expire with the seven-day retention policy. They are not active processes and do not independently block uninstall after normal confirmation.
223
222
 
224
223
  ## Submit and inspect
225
224
 
@@ -233,21 +232,17 @@ read_job
233
232
  cancel_job
234
233
  ```
235
234
 
236
- From the local terminal, including after an MCP host blocks further execution calls:
235
+ From the local terminal:
237
236
 
238
237
  ```sh
239
238
  machine-mcp job list
240
239
  machine-mcp job inspect JOB_ID
241
- machine-mcp job approve JOB_ID [--yes]
242
240
  machine-mcp job cancel JOB_ID
243
- ```
244
-
245
- A local JSON fallback is also available:
246
-
247
- ```sh
248
241
  machine-mcp job submit plan.json
249
242
  ```
250
243
 
244
+ `job submit` is an explicit local operator action; it does not consume or promote a staged MCP draft.
245
+
251
246
  The plan format is the same object accepted by `start_job`.
252
247
 
253
248
  ## Output and secret handling
@@ -2,30 +2,34 @@
2
2
 
3
3
  ## What isolation means
4
4
 
5
- Machine Bridge remote mode supports several named accounts on one workspace Worker. Each account has an independent password, role, active state, version, OAuth authorization codes, access tokens, and refresh tokens. Account changes revoke only that account's outstanding credentials.
5
+ Remote mode supports several named accounts on one workspace Worker. Each account has an independent password verifier, role, active state, version, authorization codes, access tokens, and refresh-token families.
6
6
 
7
- This is application-level authorization, not operating-system isolation. All accounts ultimately reach one local daemon running as one OS user. Roles limit which Machine Bridge tools can be listed and invoked; they do not create separate filesystems, browser profiles, process namespaces, keychains, network identities, or kernel security boundaries.
7
+ This is application-level authorization, not operating-system multi-tenancy. All accounts ultimately reach one daemon running as one OS user. Roles do not create separate filesystems, browser profiles, process namespaces, Keychains, network identities, or kernel boundaries.
8
8
 
9
- Use separate OS accounts, containers, VMs, state roots, Workers, and workspaces when users are mutually untrusted or require hard isolation.
9
+ Use separate OS accounts, containers, VMs, state roots, Workers, and workspaces when users are mutually untrusted or require hard tenant isolation.
10
10
 
11
11
  ## Roles
12
12
 
13
- | Role | Effective local profile | Typical use |
13
+ | Role | Effective local profile | Purpose |
14
14
  |---|---|---|
15
- | `reviewer` | `review` | Read-only workspace, Git, image, resource, and job inspection |
16
- | `editor` | `edit` | Reviewer access plus deterministic file mutation |
17
- | `operator` | `agent` | Editor access plus workspace-confined direct process execution and sessions |
18
- | `owner` | `full` | Complete capability ceiling; high-impact remote transactions additionally consume a local account/client-bound lease |
15
+ | `reviewer` | `review` | Read-only selected-workspace inspection |
16
+ | `editor` | `edit` | Reviewer access plus deterministic workspace file mutation |
17
+ | `operator` | `agent` | Editor access plus behaviorally sandboxed workspace-confined direct execution |
18
+ | `owner` | `full` | Complete bridge authority within the daemon capability ceiling |
19
19
 
20
- The effective tool set is the intersection of:
20
+ Effective authority is the intersection of:
21
21
 
22
- 1. the account role;
23
- 2. the policy advertised by the connected local daemon;
24
- 3. the tools actually available from that daemon.
22
+ 1. the daemon policy and available tools;
23
+ 2. the account role;
24
+ 3. the trusted OAuth client binding;
25
+ 4. the current account version and refresh-token family;
26
+ 5. ownership of any long-lived process, output session, or job.
25
27
 
26
- For execution, a fourth local layer distinguishes trusted owner automation from delegated access. An authenticated owner may use the daemon policy ceiling directly. A high-impact call from a reviewer, editor, or operator must also match an active capability lease bound to its `account_id` and OAuth `client_id`. This transaction layer does not remove tools from canonical `full`; it preserves least privilege for delegated credentials without interrupting the owner workflow. The Worker filters `tools/list` and rejects unauthorized calls before relay. Every accepted relay call carries `account_id`, `account_version`, `client_id`, and `role`; the local runtime validates them again before dispatch. See [LOCAL_AUTHORIZATION.md](LOCAL_AUTHORIZATION.md).
28
+ There is no temporary elevation path. A `reviewer`, `editor`, or `operator` cannot acquire `owner` capability through a local lease, approval ID, token refresh, or reconnect.
27
29
 
28
- Authenticated `server_info` deliberately reports both layers. `authorization.effective_policy` and `authorization.effective_tools` are authoritative for the current account. The nested `daemon.policy` and `daemon.tools` fields are only the local capability ceiling before account-role filtering; a `full` daemon does not make an `editor` account full. Remote `project_overview` uses the effective values at top-level `policy` and `tools` and preserves the daemon values as `daemonPolicy` and `daemonTools`.
30
+ The Worker filters `tools/list` and rejects unauthorized calls before relay. Every accepted call carries account ID, account version, OAuth client ID, refresh-family ID, and role. The local runtime validates those values again before dispatch.
31
+
32
+ Authenticated `server_info.authorization.effective_policy` and `effective_tools` describe the current account. `daemon.policy` and `daemon.tools` describe only the local capability ceiling; a `full` daemon does not make an `editor` account full.
29
33
 
30
34
  ## Account lifecycle
31
35
 
@@ -35,7 +39,7 @@ List accounts:
35
39
  machine-mcp account list
36
40
  ```
37
41
 
38
- Create an account. The generated password is displayed once and is not stored locally:
42
+ Create an account. The generated password is displayed once:
39
43
 
40
44
  ```sh
41
45
  machine-mcp account add alice reviewer
@@ -50,28 +54,50 @@ machine-mcp account disable build-bot
50
54
  machine-mcp account enable build-bot
51
55
  ```
52
56
 
53
- Rotate one account's password:
57
+ Rotate a password or remove an account:
54
58
 
55
59
  ```sh
56
60
  machine-mcp account rotate-password alice
61
+ machine-mcp account remove alice --yes
57
62
  ```
58
63
 
59
- Remove an account:
64
+ The final active owner cannot be disabled, demoted, or removed.
65
+
66
+ Account disablement, role changes, password rotation, and removal revoke that account's credentials by changing or deleting its account version.
67
+
68
+ ## Trusted OAuth clients
69
+
70
+ An OAuth `client_id` identifies client software and redirect URIs. Registration alone has no authority.
71
+
72
+ The first successful account authorization binds the client to:
73
+
74
+ - account ID;
75
+ - account version;
76
+ - role;
77
+ - authorization time.
78
+
79
+ A client cannot later authorize as a different account without first being revoked and registered again. This prevents one public client record from becoming a silent cross-account identity switch.
80
+
81
+ List clients:
60
82
 
61
83
  ```sh
62
- machine-mcp account remove alice
63
- machine-mcp account remove alice --yes
84
+ machine-mcp account clients
64
85
  ```
65
86
 
66
- The final active owner cannot be disabled, demoted, or removed. This prevents an accidental administrative lockout.
87
+ Revoke one client and all of its codes, access tokens, and refresh tokens:
88
+
89
+ ```sh
90
+ machine-mcp account revoke-client CLIENT_ID
91
+ machine-mcp account revoke-client CLIENT_ID --yes
92
+ ```
67
93
 
68
- ## OAuth model
94
+ One account may still authorize several distinct client records. Each record is independently visible and revocable.
69
95
 
70
- An OAuth `client_id` identifies client software and its registered redirect URIs. It is not an account. One OAuth client may be authorized by several Machine Bridge accounts, and one account may authorize several OAuth clients.
96
+ ## OAuth tokens
71
97
 
72
- An authorization code records:
98
+ Authorization codes bind:
73
99
 
74
- - OAuth client ID;
100
+ - client ID;
75
101
  - account ID and account version;
76
102
  - role;
77
103
  - redirect URI;
@@ -79,33 +105,68 @@ An authorization code records:
79
105
  - scope and protected resource;
80
106
  - expiration.
81
107
 
82
- An access-token record contains the same account binding plus the deployment-wide token version and refresh-family identity. Token values are stored only as SHA-256 lookup keys. Access tokens last fifteen minutes. Refresh tokens rotate on every use, have a fourteen-day idle limit and thirty-day family limit, and leave a bounded consumed-token marker; replay of a consumed token revokes every remaining refresh and access token in that family. Account passwords are CLI-generated 256-bit tokens. The Worker stores independent salted HMAC-SHA-256 verifiers and rejects arbitrary human-chosen passwords; the token entropy, rather than a CPU-intensive dictionary-hardening loop, provides offline-guessing resistance within the Worker CPU budget.
108
+ Access and refresh tokens additionally bind to the deployment token version and refresh-family ID. Token values are stored as SHA-256 lookup keys.
109
+
110
+ Access tokens last fifteen minutes. Refresh tokens rotate on every use, have a fourteen-day idle limit and thirty-day family limit, and leave bounded replay markers. Reuse of a consumed refresh token revokes the complete family, including active access tokens.
83
111
 
84
- At each authenticated request, the Worker verifies that the account still exists, is active, and has the same version and role recorded in the token. A password rotation, role change, suspension, or removal increments or removes that account state and invalidates only its codes and tokens.
112
+ A refresh request also verifies that the client remains bound to the current account version and role.
85
113
 
86
- `machine-mcp rotate-secrets` is intentionally broader. It rotates the account-administration HMAC key, daemon device identity, and deployment-wide token version, invalidating every account token, requiring all clients to authorize again, and requiring the matching Worker/daemon deployment to converge.
114
+ ### DPoP
115
+
116
+ A capable client may bind the token family to a P-256 DPoP key. The Worker verifies the proof and requires the same key thumbprint for refresh. A copied token cannot be used without the client private key.
117
+
118
+ Bearer remains available for hosts that do not implement DPoP.
119
+
120
+ ## Object ownership
121
+
122
+ Interactive processes, retained output sessions, and managed jobs bind to:
123
+
124
+ - account ID;
125
+ - account version;
126
+ - OAuth client ID;
127
+ - refresh-token family ID.
128
+
129
+ A different account, client, or token family cannot inspect, continue, send input to, cancel, or terminate the object.
130
+
131
+ This binding prevents horizontal control between two clients authorized for the same account as well as between different accounts.
87
132
 
88
133
  ## Administrative boundary
89
134
 
90
- Account administration is not exposed as an MCP tool. It uses an owner-only local HMAC key to sign each CLI request over method, path, body SHA-256, timestamp, and random nonce. The key is stored only in owner-protected local state and Cloudflare Worker secrets and is never transmitted as a network bearer. The Worker consumes each nonce once through bounded Durable Object transaction state and rejects replay or malformed state. The key is never printed by `status`, sent through MCP, or used as an account password.
135
+ Account and client administration is not exposed as an MCP tool and does not use a long-lived administration secret.
91
136
 
92
- The first start of a new deployment creates an `owner` account automatically and prints its generated password once. Subsequent starts do not display account passwords.
137
+ The local CLI creates a root-certified ephemeral P-256 session. Each request signs the Worker origin, HTTP method, path, body hash, session key ID, timestamp, and nonce. The Worker verifies the root certificate, session signature, body, timestamp, and nonce replay state.
138
+
139
+ The default root is portable owner-only P-256 material, including on macOS, so independent account commands do not normally prompt. When a separately provisioned broker has explicitly enrolled a Secure Enclave root, an independent account command may request user presence once. During normal daemon startup, the same in-memory session is reused for initial owner creation and relay authentication.
140
+
141
+ The first start of a new deployment creates an owner account automatically and prints its generated password once. Subsequent starts do not display passwords.
142
+
143
+ ## Delegated execution
144
+
145
+ `operator` direct execution requires a behaviorally verified OS sandbox. The sandbox must expose the selected workspace while denying the real user home, Machine Bridge state, Keychain, and desktop automation.
146
+
147
+ When the platform cannot prove that boundary, operator process execution is unavailable. The runtime does not fall back to a path blacklist that only appears isolated.
148
+
149
+ Browser/application control, local data export, credential operations, persistent job creation, sensitive targets, and unrestricted paths remain owner-only.
93
150
 
94
151
  ## Concurrency and revocation
95
152
 
96
- Pending calls remain bound to the OAuth access token and JSON-RPC request ID. Duplicate in-flight IDs under one token are rejected. Account revocation blocks new requests immediately; calls already relayed remain subject to ordinary cancellation, deadlines, local role validation, and the bounded same-daemon reconnect state machine. A replacement process cannot inherit a detached call.
153
+ MCP sessions provide a request-ID namespace and cancellation boundary. Pending calls are bound to the authenticated token and session.
97
154
 
98
- A relay interruption keeps ordinary relay-owned calls alive only inside the bounded same-daemon reconnect window. Reconciliation or grace expiry cancels calls that no longer have a remote receiver and terminates their child process trees. Process promises settle on cancellation even when a child does not emit `close`; process ownership remains tracked until actual exit.
155
+ A brief relay interruption preserves an ordinary call only within the same-daemon reconnect grace period. Reconciliation or expiry cancels calls without a receiver and terminates their child process trees. A replacement daemon process cannot claim a detached call.
156
+
157
+ Revoking an account, client, or refresh family blocks new requests immediately. Already-relayed work remains subject to local ownership, cancellation, timeout, daemon lifecycle, and process cleanup.
99
158
 
100
159
  ## Audit and privacy
101
160
 
102
- Operational metrics identify tools and stable error classes, not account passwords, bearer tokens, arguments, command text, file content, or results. `server_info` may return the authenticated account ID, role, and version to that account so the client can verify its authorization context.
161
+ Operational logs and the local security audit do not contain account passwords, tokens, command text, file content, form values, or results.
162
+
163
+ The audit chain records salted principal references, so repeated activity can be correlated locally without storing raw account/client identifiers in each entry. `server_info` may return the current authenticated account ID, role, and version to that account.
103
164
 
104
- Account names and display names are operator-selected metadata. Do not use secrets, email addresses, customer identifiers, or other unnecessary personal data in account names.
165
+ Do not use secrets, email addresses, customer identifiers, or unnecessary personal data in account names and display names.
105
166
 
106
167
  ## Deployment topology
107
168
 
108
- One workspace normally maps to one Worker name, one Durable Object instance, one local state profile, and one active daemon. Multiple accounts share this topology and its OS trust boundary.
169
+ One workspace normally maps to one Worker, one Durable Object instance, one local profile, and one active daemon. Accounts share that topology and OS trust boundary.
109
170
 
110
171
  Use a separate deployment when any of these differ:
111
172
 
@@ -116,10 +177,10 @@ Use a separate deployment when any of these differ:
116
177
  - billing or incident-response boundary;
117
178
  - requirement for hard tenant isolation.
118
179
 
119
- Do not place several unrelated machines or mutually untrusted teams behind one broad owner deployment merely to reduce administration.
180
+ Do not place unrelated machines or mutually untrusted teams behind one broad owner deployment merely to reduce administration.
120
181
 
121
182
  ## Security limits
122
183
 
123
- A `reviewer` cannot invoke mutation or process tools through Machine Bridge, but data readable by the local OS user may still be exposed by a bug, compromised dependency, or incorrectly broad workspace. An `operator` can run interpreters, package managers, compilers, and repository scripts; direct argv execution therefore remains powerful even without a shell. An `owner` has effectively the authority of the local OS user and any browser or Accessibility permissions granted to the runtime.
184
+ A reviewer is restricted by Machine Bridge, but a bug or compromised dependency remains possible. An operator can execute interpreters and repository code inside the verified sandbox and can still damage the selected workspace. An owner has effectively the authority of the local OS user and granted browser or Accessibility permissions.
124
185
 
125
- Roles are useful defense in depth and targeted revocation. They are not substitutes for least-privilege OS design, sandboxing, endpoint security, Cloudflare account protection, or careful review of untrusted repositories and instructions.
186
+ Roles, client binding, DPoP, object ownership, and targeted revocation are defense in depth. They do not replace least-privilege OS design, endpoint security, Cloudflare account protection, and careful review of untrusted repositories and instructions.