codex-computer-use-mcp 0.1.0 → 0.3.0

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 (50) hide show
  1. package/ARCHITECTURE.md +150 -0
  2. package/CONTRIBUTING.md +16 -10
  3. package/MIGRATION.md +94 -0
  4. package/PROOF.md +128 -54
  5. package/README.md +97 -115
  6. package/SECURITY.md +45 -22
  7. package/dist/audit.d.ts +15 -14
  8. package/dist/audit.js +1 -1
  9. package/dist/audit.js.map +1 -1
  10. package/dist/config.d.ts +8 -8
  11. package/dist/config.js +8 -103
  12. package/dist/config.js.map +1 -1
  13. package/dist/direct-broker.d.ts +71 -0
  14. package/dist/direct-broker.js +652 -0
  15. package/dist/direct-broker.js.map +1 -0
  16. package/dist/direct-service.d.ts +33 -0
  17. package/dist/direct-service.js +350 -0
  18. package/dist/direct-service.js.map +1 -0
  19. package/dist/lock.d.ts +1 -0
  20. package/dist/lock.js +32 -3
  21. package/dist/lock.js.map +1 -1
  22. package/dist/mcp-elicitation.d.ts +8 -0
  23. package/dist/mcp-elicitation.js +47 -0
  24. package/dist/mcp-elicitation.js.map +1 -0
  25. package/dist/mcp-server.js +43 -100
  26. package/dist/mcp-server.js.map +1 -1
  27. package/dist/system.d.ts +0 -1
  28. package/dist/system.js +12 -37
  29. package/dist/system.js.map +1 -1
  30. package/dist/tools.d.ts +84 -0
  31. package/dist/tools.js +262 -0
  32. package/dist/tools.js.map +1 -0
  33. package/docs/adr/0001-standalone-code-mode-mcp.md +45 -0
  34. package/integrations/pi/README.md +51 -27
  35. package/integrations/pi/index.ts +237 -125
  36. package/integrations/pi/mcp.json.example +3 -3
  37. package/npm-shrinkwrap.json +3275 -48
  38. package/package.json +41 -13
  39. package/dist/policy.d.ts +0 -42
  40. package/dist/policy.js +0 -428
  41. package/dist/policy.js.map +0 -1
  42. package/dist/prompt.d.ts +0 -62
  43. package/dist/prompt.js +0 -119
  44. package/dist/prompt.js.map +0 -1
  45. package/dist/runner.d.ts +0 -55
  46. package/dist/runner.js +0 -494
  47. package/dist/runner.js.map +0 -1
  48. package/dist/service.d.ts +0 -17
  49. package/dist/service.js +0 -382
  50. package/dist/service.js.map +0 -1
@@ -0,0 +1,150 @@
1
+ # Direct architecture and boundary inventory
2
+
3
+ Code Mode remains outside this package. See [ADR 0001: Keep Code Mode in a standalone MCP process](docs/adr/0001-standalone-code-mode-mcp.md).
4
+
5
+ ## Official API evidence
6
+
7
+ The architecture uses public source and the installed signed binaries; it does not speak a private Computer Use socket protocol.
8
+
9
+ At OpenAI Codex source commit [`5c19155cbd93bfa099016e7487259f61669823ff`](https://github.com/openai/codex/tree/5c19155cbd93bfa099016e7487259f61669823ff):
10
+
11
+ - the app-server documentation describes initialization, ephemeral threads, and the distinct `turn/start` operation that begins model work ([README lines 74–81](https://github.com/openai/codex/blob/5c19155cbd93bfa099016e7487259f61669823ff/codex-rs/app-server/README.md#L74-L81));
12
+ - it documents `mcpServer/tool/call` as a direct call to a configured MCP tool ([README line 238](https://github.com/openai/codex/blob/5c19155cbd93bfa099016e7487259f61669823ff/codex-rs/app-server/README.md#L238));
13
+ - the typed request contains `thread_id`, `server`, `tool`, and `arguments`—not a prompt or model request ([protocol lines 97–110](https://github.com/openai/codex/blob/5c19155cbd93bfa099016e7487259f61669823ff/codex-rs/app-server-protocol/src/protocol/v2/mcp.rs#L97-L110));
14
+ - the implementation loads the thread runtime and invokes `thread.call_mcp_tool(...)` directly ([processor lines 455–474](https://github.com/openai/codex/blob/5c19155cbd93bfa099016e7487259f61669823ff/codex-rs/app-server/src/request_processors/mcp_processor.rs#L455-L474));
15
+ - downstream structured elicitation is an explicit client capability rather than implicit approval ([README lines 89–94](https://github.com/openai/codex/blob/5c19155cbd93bfa099016e7487259f61669823ff/codex-rs/app-server/README.md#L89-L94)).
16
+
17
+ The Full access behavior is also public in the pinned Codex `rust-v0.144.2` source at commit [`a6645b6b8a656360fa16fb7e1c6721d0697d3d6a`](https://github.com/openai/codex/tree/a6645b6b8a656360fa16fb7e1c6721d0697d3d6a):
18
+
19
+ - legacy `danger-full-access` maps to `PermissionProfile::Disabled` ([models lines 289–297](https://github.com/openai/codex/blob/a6645b6b8a656360fa16fb7e1c6721d0697d3d6a/codex-rs/protocol/src/models.rs#L289-L297));
20
+ - MCP permission prompts are auto-approved when the approval policy is `Never` and the permission profile is disabled ([MCP policy lines 76–99](https://github.com/openai/codex/blob/a6645b6b8a656360fa16fb7e1c6721d0697d3d6a/codex-rs/codex-mcp/src/mcp/mod.rs#L76-L99));
21
+ - the elicitation manager applies that policy before client notification ([elicitation lines 196–221](https://github.com/openai/codex/blob/a6645b6b8a656360fa16fb7e1c6721d0697d3d6a/codex-rs/codex-mcp/src/elicitation.rs#L196-L221)), and limits the automatic response to empty-schema approval/confirmation forms ([lines 319–331](https://github.com/openai/codex/blob/a6645b6b8a656360fa16fb7e1c6721d0697d3d6a/codex-rs/codex-mcp/src/elicitation.rs#L319-L331)).
22
+
23
+ The installed CLI labels app-server experimental. This project therefore verifies the current method and upstream schemas on every call and fails closed on drift.
24
+
25
+ ## Live architecture probe
26
+
27
+ A raw stdio client can initialize the signed `SkyComputerUseClient` and list all ten tool schemas, but a real `list_apps` call from an ordinary Node parent returns:
28
+
29
+ ```text
30
+ Computer Use server error -10000: Sender process is not authenticated
31
+ ```
32
+
33
+ The same read-only call through signed app-server `mcpServer/tool/call` succeeded while app-server ran with an empty isolated `CODEX_HOME`:
34
+
35
+ - all ten exact tools discovered;
36
+ - one `mcpServer/tool/call`;
37
+ - 39 apps returned;
38
+ - ephemeral context explicitly attested `ephemeral: true`, `turns: []`, and `path: null`;
39
+ - no `turn/start`, `turn/*`, or `item/*` model activity;
40
+ - no account auth file or model API credential available to app-server;
41
+ - a dummy provider with `supports_websockets = false` and unreachable loopback base URL;
42
+ - plugin and remote-control features disabled;
43
+ - trace/network sampling showed no app-server Responses API connection or model request after those controls (the separate official Computer Use service may use its own network transport).
44
+
45
+ This is the narrow official boundary: direct calls require a loaded thread runtime ID in the current API, but do not require a conversation turn or model generation. Literal removal of the thread-shaped runtime object would require an upstream app-server API change.
46
+
47
+ ## Sender-authentication differential
48
+
49
+ A supported fake stdio MCP server was substituted only to observe the app-server's public downstream envelope shape. App-server used:
50
+
51
+ - MCP protocol `2025-06-18`;
52
+ - `clientInfo` name/title/version identifying `codex-mcp-client` / Codex / the installed CLI;
53
+ - standard `elicitation.form` and `elicitation.url` capability keys;
54
+ - standard progress metadata on `tools/list`;
55
+ - standard progress metadata plus public app-server-added `threadId` metadata on `tools/call`.
56
+
57
+ An ordinary MCP SDK client then repeated a read-only raw-helper call with the same client identity, capability shape, protocol behavior, and public `progressToken`/random `threadId` metadata shape. The helper still returned `-10000 Sender process is not authenticated`. Changing documented handshake fields therefore does not repair raw dispatch.
58
+
59
+ The relevant construction difference is the macOS responsible-process chain:
60
+
61
+ - unsupported: ad-hoc/no-Team-ID Node parent → signed helper;
62
+ - supported: Node/Pi → strict-valid OpenAI-signed app-bundled Codex (`2DC432GLL2`) → strict-valid OpenAI-signed helper (`2DC432GLL2`).
63
+
64
+ Process sampling confirmed the helper children were direct descendants of signed app-server; helper processes may create their own process groups. App-server and helper therefore share one private per-call cwd. Cleanup preserves partial ancestry results, recovers any reparented process by that unique cwd, freezes the owned set to stability, then kills and verifies every process rather than assuming one PGID. Enumeration, freeze, or exit uncertainty fails cleanup closed. The app-server has the expected sandbox/application-group entitlement keys; the helper has OpenAI application/team identifiers, application groups, and keychain-access-group entitlements. Ordinary Node has no Team ID or entitlement set. The service's peer audit token is not exposed through the supported MCP layer. No private socket inspection, identity spoofing, copied signing material, re-signing, injection, or TCC change was attempted. The remaining enforcement boundary is therefore OS peer/responsible-process identity, not a missing public JSON field.
65
+
66
+ Command, environment, cwd, and config differences were also isolated: both paths invoke the same signed helper with `mcp`; the accepted path gives it a signed parent plus a private fixed cwd/config environment. Matching public MCP fields did not alter the raw error, while the signed-parent path succeeds without model credentials.
67
+
68
+ ## Process path
69
+
70
+ ```text
71
+ Pi model
72
+ └─ chooses computer_use_<method> and typed arguments
73
+ └─ local direct service
74
+ └─ signed app-bundled `codex app-server --stdio`
75
+ ├─ empty ephemeral runtime context (zero turns; no transcript)
76
+ └─ `mcpServer/tool/call`
77
+ └─ signed SkyComputerUseClient `mcp`
78
+ └─ official Computer Use service
79
+ └─ target macOS app
80
+ ```
81
+
82
+ Forbidden primary-path methods are enforced by code and tests:
83
+
84
+ ```text
85
+ turn/start
86
+ turn/steer
87
+ turn/resume model work
88
+ codex exec
89
+ codex mcp-server model tools
90
+ nested prompts or result summaries
91
+ ```
92
+
93
+ ## Restriction inventory
94
+
95
+ | Released wrapper restriction | Classification | Direct design |
96
+ |---|---|---|
97
+ | Fixed ChatGPT/Codex/client paths | **official-required** | retained and verified |
98
+ | Strict signatures and OpenAI Team ID | **security-essential** | retained |
99
+ | Signed-parent/responsible-process chain | **official-required** | retained through signed app-server |
100
+ | Private Sky socket/native-pipe access | **unsupported/private** | prohibited |
101
+ | Nested Codex model and prompt | **compatibility-only** | removed |
102
+ | Model selection and reasoning effort | **compatibility-only** | removed; dummy unreachable provider prevents model transport |
103
+ | Responses websocket prewarm on empty thread | **accidental app-server behavior** | disabled with non-websocket dummy provider |
104
+ | Plugin/remote-control startup networking | **accidental app-server behavior** | corresponding features disabled |
105
+ | Model-written multi-step task plan | **compatibility-only** | removed |
106
+ | Model result schema/summary | **compatibility-only** | removed |
107
+ | Streamed model-event target/method validation | **compatibility-only** | replaced by pre-dispatch typed call validation |
108
+ | Per-operation tool allowlists and call budgets | **compatibility-only** | one typed method per direct request |
109
+ | Task text, cleanup instructions, required-capabilities fields | **compatibility-only** | removed |
110
+ | Dictionary-only special policy | **accidental** | removed |
111
+ | Wrapper app/intent allowlists in full mode | **accidental** | absent |
112
+ | Safe/full wrapper modes | **compatibility-only** | removed; one durable no-permissions interface exposes all ten methods |
113
+ | Wrapper approval prompts/configuration | **compatibility-only** | removed; no command, config, environment, or per-call selector remains |
114
+ | Official first-party app access | **official-required** | official Codex Full access auto-accepts normal empty-schema app approval elicitations; any elicitation app-server emits is forwarded unchanged |
115
+ | macOS TCC | **official-required** | retained; never modified |
116
+ | Exact ten-tool inventory/schema | **security-essential** | retained and checked before each call |
117
+ | Canonical bundle identity | **security-essential** | retained before targeted dispatch |
118
+ | Same-app kernel lock | **security-essential** | retained in one fixed per-user namespace shared across Pi/MCP state roots |
119
+ | Automatic background app launch | **accidental** | removed; the official tool owns app behavior |
120
+ | Global focus watcher and final sample | **security-essential detection** | retained |
121
+ | Timeout/cancellation process-tree termination | **security-essential** | retained with strict enumeration, freeze, kill, stdio-close, and exit verification |
122
+ | Per-call temporary worker cleanup | **security-essential** | retained with isolated `CODEX_HOME` |
123
+ | Codex token usage accounting | **compatibility-only** | removed; no model turn exists |
124
+ | Content-safe private audit | **security-essential** | retained with direct-call fields |
125
+ | Full-result spill files | **unsafe/accidental** | prohibited; truncation is in-memory only |
126
+ | Browser-host integration | **out of scope** | unchanged |
127
+
128
+ ## No-permissions and elicitation boundary
129
+
130
+ No-permissions is the sole interface and means unrestricted wrapper dispatch with no wrapper approval prompt. All ten methods are registered. No config file, environment value, slash command, CLI mode switch, or tool argument selects another route.
131
+
132
+ App-server is created with `approvalPolicy: "never"` and `sandbox: "danger-full-access"`. This is the official Codex Full access combination. The legacy sandbox field maps to `PermissionProfile::Disabled`; Codex then auto-accepts empty-schema MCP approval elicitations before client notification. Normal first-party Computer Use app approvals therefore do not prompt, and the bridge does not need to mutate the per-bundle approval store.
133
+
134
+ The broker still handles any `mcpServer/elicitation/request` that app-server emits. Pi advertises OpenAI-form support and renders emitted form, OpenAI-form, and URL requests. Generic stdio MCP forwards supported standard modes as `elicitation/create`. The response path preserves `accept`, `decline`, `cancel`, structured content, and response metadata; no callback or compatible UI yields `cancel`, never an invented decision.
135
+
136
+ ## Pi tool disclosure boundary
137
+
138
+ The Pi extension registers all ten official definitions. On `session_start` it preserves active tools owned by Pi and other extensions, keeps `computer_use_list_apps` and `computer_use_get_app_state` active, and removes only the eight Computer Use interaction definitions from the initial active set. After a successful `get_app_state` result, it additively activates those eight definitions without removing any currently active tool.
139
+
140
+ This is context disclosure, not a wrapper permission gate. The schemas, execution path, and no-permissions policy do not change. Loader and interaction definitions remain registered throughout the session. The interaction definitions omit `promptSnippet` and `promptGuidelines`, allowing Pi 0.80.7's native deferred-loading representation to add schemas at the tool-result position without changing the system-prompt prefix. Providers without native support use Pi's next-request fallback.
141
+
142
+ ## Output boundary
143
+
144
+ Only official `text` and `image` MCP blocks are accepted. They are returned to the invoking client because app state and screenshots are the requested capability. They are never copied to audit, logs, temp files, or structured metadata. Text is truncated in memory at Pi's standard 50KB/2000-line bound; the full text is not persisted.
145
+
146
+ ## Package name
147
+
148
+ Version 0.2.0 keeps the repository and npm package name `codex-computer-use-mcp` for continuity with version 0.1.0. Pi-owned typed tools are now the primary product path. OpenAI's signed Codex app-server remains an implementation boundary, not the planner.
149
+
150
+ Any future package or repository rename would be a separate distribution change and would require maintainer approval.
package/CONTRIBUTING.md CHANGED
@@ -1,26 +1,32 @@
1
1
  # Contributing
2
2
 
3
- Contributions are welcome, especially compatibility fixes, adversarial policy tests, and clearer host diagnostics.
3
+ Contributions are welcome, especially compatibility fixes, direct-protocol tests, adversarial boundary tests, and clearer host diagnostics.
4
4
 
5
5
  ## Setup
6
6
 
7
7
  ```bash
8
8
  npm ci
9
9
  npm run check
10
+ npm run check:pi
10
11
  npm test
11
12
  npm run build
12
13
  ```
13
14
 
14
- Development and live acceptance require macOS plus the official ChatGPT app. Tests that verify the bundled broker and compile disposable native harnesses are intentionally host integration tests.
15
+ Development and live acceptance require macOS and the official ChatGPT Computer Use component. Acceptance evidence must use benign real apps, not a disposable harness alone.
15
16
 
16
17
  ## Pull requests
17
18
 
18
- - Keep safe mode list-only; do not add targeted dispatch without a preventive mechanism that preserves official signed-parent authentication.
19
- - Do not add credential extraction, app injection, re-signing, private protocol bypasses, TCC automation, or automatic approval acceptance.
20
- - Add a regression test for every policy or cleanup fix.
21
- - Avoid logging task text, typed values, screenshots, app-state payloads, or model output.
22
- - Document any new fixed ChatGPT bundle path or CLI assumption.
23
- - Include `npm run check`, `npm test`, and `npm run build` results.
24
- - For targeted behavior changes, include a benign stopped-app acceptance and external focus evidence, and label post-dispatch checks honestly.
19
+ - Keep Pi-owned typed methods as the primary path.
20
+ - Do not add a nested model, action planner, prompt, subagent, or model-written result summary to direct dispatch.
21
+ - Do not use private pipes/sockets, credential extraction, app injection, re-signing, sender impersonation, TCC automation, or automatic approval acceptance.
22
+ - Keep app-server in a credential-free isolated `CODEX_HOME` with only official Computer Use configured.
23
+ - Add a regression test for every protocol, policy, focus, cleanup, or audit fix.
24
+ - Never log or persist arguments, typed values, screenshots, app-state/result content, elicitation contents, prompts, credentials, or tokens.
25
+ - Treat focus checks as post-action detection rather than preventive isolation.
26
+ - Document fixed ChatGPT bundle paths and upstream schema/API assumptions.
27
+ - Include strict core/Pi type checks, tests, build, audit, package inspection, and real-app acceptance evidence.
28
+ - Obtain independent exact-head review for security-boundary changes.
25
29
 
26
- Security-boundary changes should receive an independent exact-head review before merge. See `SECURITY.md` for private vulnerability reporting.
30
+ Repository/package renaming, merge, npm publication, and GitHub release require separate maintainer approval.
31
+
32
+ See `ARCHITECTURE.md`, `SECURITY.md`, and `MIGRATION.md`.
package/MIGRATION.md ADDED
@@ -0,0 +1,94 @@
1
+ # Migration and rollback
2
+
3
+ Version 0.2.0 was the breaking direct-tool architecture change from version 0.1.0. Version 0.3.0 keeps that exact ten-tool contract and adds Pi 0.80.7 progressive disclosure. Use the relevant section below.
4
+
5
+ ## What changes
6
+
7
+ | 0.1 released surface | 0.2 direct surface |
8
+ |---|---|
9
+ | `background_computer_use` aggregate task | ten `computer_use_<method>` Pi tools |
10
+ | `background_computer_use_status` | `/computer-use-status` and MCP `computer_use_status` |
11
+ | `/background-computer-use-mode` | removed; `/computer-use-status` is read-only |
12
+ | safe/full wrapper modes | one durable no-permissions interface: all ten methods, no wrapper prompts |
13
+ | nested model plans and summarizes | Pi calls one official typed method per tool call |
14
+ | separate Codex model usage | no nested model/token usage |
15
+ | state under wrapper-specific old path | isolated direct state under `~/.direct-computer-use` or Pi agent direct state |
16
+
17
+ ## Pre-migration checks
18
+
19
+ 1. Stop all current aggregate Computer Use calls.
20
+ 2. Record the installed package/extension version and permission mode.
21
+ 3. Back up the Pi package/config files without copying audit content into tickets or chat.
22
+ 4. Confirm no `pi-native-app-worker.*`, `SkyComputerUseClient mcp`, `codex app-server`, `lockf`, or focus-listener process from the old adapter is active. The direct adapter uses one fixed private `/tmp/codex-computer-use-mcp-<uid>` lock namespace across Pi and MCP state roots.
23
+ 5. Keep the old and new adapters from registering overlapping tools in one Pi process.
24
+
25
+ ## Source acceptance without installation
26
+
27
+ Use a fresh Pi process and the source extension explicitly:
28
+
29
+ ```bash
30
+ npm ci
31
+ npm run build
32
+ CODEX_COMPUTER_USE_HOME="$(mktemp -d)" \
33
+ pi -ne -e /absolute/path/to/integrations/pi/index.ts
34
+ ```
35
+
36
+ `-ne` suppresses auto-discovered extensions so the live 0.1 adapter is not loaded. This does not change live Pi configuration.
37
+
38
+ The source adapter starts only in no-permissions mode: all ten methods are available and the wrapper opens no permission UI of its own. The signed app-server runs with Codex Full access, so normal empty-schema app approval elicitations resolve without a prompt. Any elicitation app-server emits is still shown through Pi and answered only by the user. Use benign real apps for acceptance; do not use disposable harnesses as evidence.
39
+
40
+ ## Migrate to version 0.2.0
41
+
42
+ 1. Back up `~/.pi/agent/settings.json`, `~/.pi/agent/mcp.json`, and the installed 0.1 package or extension directory.
43
+ 2. Record the installed version and verify that npm resolves `codex-computer-use-mcp@0.2.0` exactly.
44
+ 3. Remove or disable the 0.1 aggregate adapter and generic MCP registration.
45
+ 4. Install `npm:codex-computer-use-mcp@0.2.0`.
46
+ 5. Remove any legacy direct `config.json`; the new build ignores it and has no mode selector.
47
+ 6. Start a fresh Pi process; do not rely on hot-reloading a security-boundary change.
48
+ 7. Verify `/computer-use-status` reports:
49
+ - `permissionMode: "no-permissions"`;
50
+ - `wrapperPermissionPrompts: false`;
51
+ - `officialApprovalPolicy: "full-access"`;
52
+ - `officialAppApprovalHandling: "auto-approved-by-codex-full-access"`;
53
+ - `officialElicitationHandling: "forwarded-if-emitted"`;
54
+ - all ten `availableMethods`;
55
+ - `brokerVerified: true`;
56
+ - `nestedModel: false`;
57
+ - `modelUsage: false`;
58
+ - `ephemeralZeroTurnRuntimeContextRequired: true`.
59
+ 8. Run `computer_use_list_apps` and `computer_use_get_app_state` against a benign real app with external focus sampling while the Mac is unlocked.
60
+ 9. Exercise mutating methods on benign disposable content, restore app state, then check audits and process cleanup.
61
+
62
+ Do not copy old safe/full configuration into the new state root. No-permissions is compiled as the sole unrestricted, no-wrapper-prompt interface.
63
+
64
+ Version 0.2.0 does not support targeted local Computer Use while the Mac is locked. OpenAI reserves locked use for active trusted turns started from a connected device. See the [locked-screen limitation](README.md#locked-screen-limitation).
65
+
66
+ ## Upgrade from version 0.2.0 to 0.3.0
67
+
68
+ The MCP contract and signed execution path do not change. The native Pi extension now registers all ten definitions but initially activates only `computer_use_list_apps` and `computer_use_get_app_state`.
69
+
70
+ 1. Upgrade Pi to version 0.80.7 or newer.
71
+ 2. Back up `~/.pi/agent/settings.json` and the installed 0.2 package directory.
72
+ 3. Verify that npm resolves `codex-computer-use-mcp@0.3.0` exactly, then install that exact package.
73
+ 4. Start a fresh Pi process.
74
+ 5. Verify that the two inspection tools are initially active and the eight interaction tools remain registered but inactive.
75
+ 6. Call `computer_use_get_app_state` against a benign app while the Mac is unlocked. A successful result should add all eight interaction tools without removing any active tool.
76
+ 7. Exercise a benign interaction, inspect the private content-safe audit, and verify process cleanup.
77
+
78
+ The change is context disclosure, not a permission mode. Codex Full access, emitted elicitation forwarding, schemas, and the no-permissions policy remain unchanged.
79
+
80
+ ## Rollback
81
+
82
+ 1. Stop the current Pi process.
83
+ 2. Confirm no direct app-server/client/focus/lock process remains.
84
+ 3. Remove or disable the current package registration.
85
+ 4. Restore the backed-up 0.1 package/config registration byte-for-byte.
86
+ 5. Start a fresh Pi process.
87
+ 6. Verify the old status command and installed hash.
88
+ 7. Preserve both private audit directories locally; never merge their content or publish it.
89
+
90
+ Direct state can be removed only after rollback evidence is captured and no process references it. The fixed per-user lock directory can likewise be removed only when no direct call or `lockf` process exists. These paths contain configuration/content-safe metadata and hashed lock ownership—not credentials.
91
+
92
+ ## Generic MCP gateway
93
+
94
+ If Pi uses `mcp.json`, retain `directTools: false`. Use the exact `0.3.0` package shown in `integrations/pi/mcp.json.example`. During source acceptance, use a distinct temporary server name and source path, then remove it. The direct Pi adapter is the primary live path; do not leave the version 0.1 aggregate server active after the switch.
package/PROOF.md CHANGED
@@ -1,81 +1,155 @@
1
- # Proof and acceptance record
1
+ # Direct architecture proof and acceptance record
2
2
 
3
- This records evidence for the standalone MCP extraction. It does not guarantee compatibility with future ChatGPT macOS versions.
3
+ This file records evidence for the 0.2 direct-tool branch. It is not a compatibility promise for future ChatGPT versions.
4
4
 
5
- ## Supported path
5
+ ## Supported direct path
6
6
 
7
7
  ```text
8
- MCP client → wrapper → app-bundled signed Codex CLI → signed SkyComputerUseClient → official Computer Use service
8
+ Pi chooses typed method/arguments
9
+ → local direct service
10
+ → signed app-bundled Codex app-server
11
+ → mcpServer/tool/call
12
+ → signed SkyComputerUseClient
13
+ → official Computer Use service
9
14
  ```
10
15
 
11
- Direct unsigned access was rejected by sender authentication. The wrapper does not bypass that boundary. It verifies the fixed app-bundled Codex and Computer Use client with `codesign --verify --strict` and OpenAI Team ID `2DC432GLL2` before each run.
16
+ No model turn, prompt, planner, result summarizer, subagent, shell, web tool, user plugin, or Codex auth credential exists on this path.
12
17
 
13
- ## Preventive-boundary finding
18
+ ## Architectural proof
14
19
 
15
- An independent `gpt-5.6-sol`/`xhigh` review of the first standalone candidate found that streamed target and argument checks occur after official-client dispatch. A model deviation could therefore reach a different already-approved app before the wrapper killed the worker.
20
+ ### Negative raw-helper probe
16
21
 
17
- A local MCP proxy was prototyped and proved capable of rejecting a wrong target before forwarding. It was not adopted: making the unsigned proxy the official client's parent breaks the signed-parent sender-authentication chain and caused live Computer Use to fail. Injection, re-signing, credential extraction, and authentication bypass were rejected as out of bounds.
22
+ The official helper's stdio MCP handshake succeeds and exposes all ten schemas. A real direct `list_apps` from an ordinary Node parent fails:
18
23
 
19
- The public authorization model was changed instead:
24
+ ```text
25
+ Computer Use server error -10000: Sender process is not authenticated
26
+ ```
27
+
28
+ Matching the app-server's observed public downstream MCP identity/capability/progress/`threadId` metadata shape in an ordinary raw MCP SDK client still produced the same sender-authentication rejection. Process and signing evidence identified the material difference as ad-hoc/no-Team-ID Node parent versus strict-valid OpenAI-signed app-server parent. The supported layer does not expose the service peer audit token. No attempt was made to forge sender identity, invoke a private pipe/socket, re-sign code, inject into a process, extract credentials, or alter TCC.
29
+
30
+ ### Positive official app-server probe
31
+
32
+ The same signed helper through official app-server `mcpServer/tool/call` succeeds. Repeated read-only probes established:
33
+
34
+ - exact ten-tool inventory;
35
+ - one direct `list_apps` call;
36
+ - empty ephemeral context explicitly attested `ephemeral: true`, `turns: []`, and `path: null`;
37
+ - no `turn/start`, `turn/*`, or `item/*` model activity;
38
+ - app-server `CODEX_HOME` isolated from the user's Codex home and containing no auth;
39
+ - model provider replaced by a non-websocket dummy bound to unreachable loopback;
40
+ - plugin and remote-control features disabled;
41
+ - trace/network sampling showed no app-server Responses API connection or model request after those controls;
42
+ - no nested model-token usage;
43
+ - 39 apps returned.
44
+
45
+ The public OpenAI source basis and permanent links are in `ARCHITECTURE.md`.
46
+
47
+ ## Automated evidence
48
+
49
+ Current branch tests cover:
50
+
51
+ - strict TypeScript for core and Pi adapter;
52
+ - fixed-path strict signature and Team ID checks;
53
+ - exact official ten-tool inventory/schema drift rejection before dispatch;
54
+ - direct JSONL request sequence with no `turn/start`;
55
+ - isolated credential-free `CODEX_HOME` even when the parent environment contains a model API key;
56
+ - production app-server arguments disable model transport, plugins, and remote control;
57
+ - durable no-permissions as the sole policy, with no config/environment/command/tool override;
58
+ - all ten methods available without wrapper prompts or mode gates;
59
+ - exact `thread/start` Full access parameters (`approvalPolicy: "never"`, `sandbox: "danger-full-access"`);
60
+ - fatal rejection of model-turn notifications, including a notification emitted during teardown;
61
+ - strict `ephemeral: true` / `path: null` / `turns: []` response attestation before dispatch;
62
+ - pre-buffer rejection of an oversized unterminated protocol line;
63
+ - partial-preserving ancestry enumeration plus private-cwd recovery, stable freeze/termination of separately grouped or reparented helpers, and stdio closure;
64
+ - unrestricted read and mutation dispatch under the single no-permissions policy;
65
+ - absence of wrapper app/intent/action gates and permission prompts;
66
+ - canonical bundle-ID dispatch;
67
+ - target focus violation fail-closed behavior;
68
+ - official error preservation;
69
+ - private metadata-only audits with no arguments/results and truthful separate broker/lease cleanup evidence;
70
+ - secure audit-directory/file no-follow and mode checks;
71
+ - global per-user same-app exclusion across different supported state roots, race behavior, crash release, private lock roots, and bounded lock filenames;
72
+ - focus-event ASN retry/drain behavior, including valid events at the start of a single large stdout chunk;
73
+ - stdio MCP all-ten inventory/status with no alternate mode route;
74
+ - signed app-server elicitation forwarding, exact user responses, headless cancellation, and cancellation while a UI callback is pending;
75
+ - standard form/URL forwarding across a real MCP SDK client/server transport;
76
+ - Pi source registration for every direct capability with no nested planner, permission command, or wrapper-generated approval UI;
77
+ - Pi session-start disclosure of only the two inspection definitions while preserving unrelated active tools;
78
+ - purely additive activation of all eight interaction definitions after successful `get_app_state`, with no lazy-tool prompt metadata;
79
+ - Pi form, opaque OpenAI-form, URL, decline, and headless-cancel elicitation handling.
20
80
 
21
- - safe mode is list-only;
22
- - all targeted modes are rejected and audited before worker launch;
23
- - full-permissions mode is explicitly acknowledged broad authorization;
24
- - streamed target/method/argument/focus/cleanup checks are documented as post-dispatch detection and completion criteria, not a preventive sandbox.
81
+ ## Official Full access approval probe
25
82
 
26
- ## Other review remediation
83
+ A live differential used Chess (`com.apple.Chess`), which was absent from the signed service's persistent per-bundle approval file before and after both calls:
27
84
 
28
- The same review found and prompted fixes for:
85
+ 1. `approvalPolicy: "never"` with `sandbox: "read-only"` returned `Computer Use approval denied`; app-server never emitted the service's empty-schema approval request to the bridge callback.
86
+ 2. Changing only the thread sandbox to `danger-full-access` made the same `get_app_state` call succeed. The bridge callback count and broker `elicitationRequests` were both zero, the runtime remained zero-turn and ephemeral, cleanup verified, and a before/after hash confirmed the persistent approval file was unchanged.
29
87
 
30
- - incomplete operations returning a non-error tool status;
31
- - policy-validation failures missing audits;
32
- - lease-release failure suppressing the audit attempt;
33
- - cancellation losing available runner metadata;
34
- - ASN lookup failures being permanently deduplicated;
35
- - final focus sampling not draining an in-flight sample;
36
- - caret-ranged published dependencies without a shrinkwrap;
37
- - status claiming a healthy boundary without verifying the signed broker;
38
- - insufficient release provenance guidance.
88
+ This matches the pinned Codex source: `danger-full-access` maps to a disabled permission profile, and `Never` plus that profile auto-accepts empty-schema MCP confirmation elicitations inside the official host. It proves prompt-free request authorization without editing persistent app approvals or inventing a bridge response.
39
89
 
40
- A second exact-tree review accepted the P1 architectural remediation and found two further P2 races: shutdown-only focus events could exhaust the single post-stop ASN lookup, and cancellation audits stored only a count rather than ordered methods. The watcher now performs a bounded awaited drain after listener closure and fails closed if any ASN remains unresolved. Cancellation now returns structured non-retryable error details and persists the ordered sanitized method list plus cleanup uncertainty. Combined regressions cover both cases.
90
+ ## Fresh Pi unlocked real-app acceptance
41
91
 
42
- ## Test and host evidence
92
+ A fresh `pi -ne -e <source adapter> --no-session` process using the branch build exercised all ten tools sequentially in an unlocked macOS session. The target was a real background TextEdit document with disposable local content:
43
93
 
44
- The original reviewed core demonstrated:
94
+ 1. `computer_use_list_apps`
95
+ 2. `computer_use_get_app_state`
96
+ 3. `computer_use_perform_secondary_action` (`Scroll Down`)
97
+ 4. `computer_use_scroll` (0.5 page)
98
+ 5. `computer_use_drag` (visible text selection)
99
+ 6. `computer_use_set_value`
100
+ 7. `computer_use_select_text`
101
+ 8. `computer_use_type_text`
102
+ 9. `computer_use_click`
103
+ 10. `computer_use_press_key` (`CMD+A` and `CMD+S`, normalized to official xdotool-style keys)
45
104
 
46
- - strict TypeScript compilation;
47
- - signed broker and ten-method schema verification;
48
- - crash-release and bounded hashed-lock tests;
49
- - streamed event, failed-status, call-budget, timeout, and cancellation tests;
50
- - focus watcher drain/final-query tests;
51
- - secure config/audit no-follow, mode, and fsync checks;
52
- - fresh stopped-Calculator background action with `2 + 2 = 4`, `AC → 0`, cleanup verified, and zero Calculator-frontmost samples;
53
- - all ten official methods, different-app concurrency, same-app exclusion, and cancellation cleanup in earlier benign harness acceptance.
105
+ Evidence:
54
106
 
55
- The standalone MCP server additionally demonstrated a real stdio client handshake and safe-mode `list` call:
107
+ - 19 strictly sequential direct calls including eight state reads;
108
+ - every call `outcome=ok`, `directCalls=1`, `modelTurnsStarted=0`, `ephemeralThread=true`, and `brokerCleanupVerified=true`;
109
+ - every targeted call `backgroundPreserved=true`;
110
+ - no first-party approval request appeared or was accepted;
111
+ - final saved document content exactly `DIRECT COMPUTER USE ACCEPTANCE CLEANUP COMPLETE`;
112
+ - 702 external 50ms frontmost samples, all Music, zero TextEdit samples;
113
+ - 37 sampled direct app-server process observations, all `app-server --stdio` with the disabled provider; zero `codex exec`/`mcp-server` nested commands;
114
+ - zero app-server TCP sockets observed after model/plugin/remote-control transport was disabled;
115
+ - zero leaked direct app-server/client/focus/lock processes; zero owner files;
116
+ - TextEdit was stopped and the disposable document removed after verification.
56
117
 
57
- - result `ok`;
58
- - 39 apps;
59
- - one successful `list_apps` method;
60
- - background preserved;
61
- - separate Codex usage reported;
62
- - private sanitized audit written.
118
+ Earlier exploratory attempts exposed and fixed two acceptance-quality issues rather than being counted as proof: common `CMD+A` needed normalization to the official `Meta_L+a` key form, and TextEdit state restoration had to be reset before a fresh run. The final evidence above is from the corrected direct path.
63
119
 
64
- After remediation, release validation must rerun the exact current test count, build, dependency audit, package inspection, read-only list acceptance, Pi adapter smoke, and independent exact-head review. The GitHub release should bind the final commit, tracked-tree aggregate hash, package integrity, host versions, and reviewer verdict.
120
+ ## Pi 0.80.7 progressive-disclosure measurement
65
121
 
66
- ## Release gate
122
+ A fresh Pi 0.80.7 process loaded only the source Computer Use extension plus a read-only observer. All ten definitions were registered. The initial active Computer Use set was exactly:
67
123
 
68
- Before publishing:
124
+ - `computer_use_list_apps`
125
+ - `computer_use_get_app_state`
69
126
 
70
- 1. Run `npm ci`, `npm run check`, `npm test`, `npm run build`, and `npm audit --omit=dev`.
71
- 2. Inspect `npm pack --dry-run`; verify `npm-shrinkwrap.json` and exact runtime dependency versions are included.
72
- 3. Verify ChatGPT/Codex/client signatures and Team ID on the acceptance host.
73
- 4. Run fresh stdio MCP `list` acceptance in safe mode.
74
- 5. Run one benign stopped-app action only after explicitly enabling full-permissions, with external focus sampling and cleanup verification.
75
- 6. Check for leaked workers, listeners, lock holders, owner records, and harness apps.
76
- 7. Independently review the exact release tree. Do not publish with unresolved P0/P1/P2 findings.
77
- 8. Record commit, aggregate hash, package integrity, host versions, test count, and review verdict in the release.
127
+ Serializing names, descriptions, schemas, and prompt guidelines measured 6,063 bytes for all ten definitions and 1,231 bytes for the initial two: 4,832 bytes removed from the initial request, a 79.7% reduction for this tool family.
128
+
129
+ A second fresh process exercised the exported activation path from inside a tool execution. Pi's tool result recorded the exact eight interaction names in `addedToolNames`; the before/after active sets retained both inspection tools and removed zero tools. The lazily activated definitions had no `promptSnippet` or `promptGuidelines`.
130
+
131
+ With `openai-codex/gpt-5.6-sol`, the first request reported 5,723 uncached input tokens. The immediately following request after additive activation reported 1,008 uncached input tokens and 5,632 cache-read tokens. This is live provider evidence that the initial prefix remained reusable while Pi inserted the eight definitions at the tool-result load point. The activation probe used the same `activateInteractionTools` function called after a successful production `get_app_state`; automated tests bind that successful-result branch and exact additive set.
132
+
133
+ ## Review and release status
134
+
135
+ The direct implementation at commit `98d26f8040f8035a294caa8581d218a33c076990`, tree `01dd30c899863d182bcb0ac3256bd0cc11efc42b`, passed the immutable exact-head review and rollback-safe activation gates. It became the basis for the version 0.2.0 release.
136
+
137
+ Validation recorded for the reviewed direct implementation:
138
+
139
+ - `npm ci`: pass;
140
+ - `npm run check`: pass;
141
+ - `npm run check:pi`: pass;
142
+ - `npm test`: 45/45 pass;
143
+ - `npm run build`: pass;
144
+ - `npm audit --omit=dev`: zero vulnerabilities;
145
+ - `npm pack --dry-run`: 36 intended files, shrinkwrap present, no removed nested-runner artifact;
146
+ - public-source scrub: no secrets, private absolute paths, or machine identifiers found;
147
+ - fresh-Pi real-app acceptance: pass as above.
148
+
149
+ Independent reviews of earlier revisions found cleanup and coordination gaps: fail-open or partial descendant enumeration, early-exit orphan recovery, state-root-scoped same-app locking, false-success lease-release audit, unverified focus-listener exit, pre-response direct-call accounting, and large-chunk focus-event loss. The reviewed implementation retains those fixes while removing wrapper-generated approval UI and safe or full configuration branches. The follow-up Full access change uses Codex's own policy to resolve normal empty-schema app approvals without prompts; any elicitation app-server emits remains a separate, faithfully forwarded user interaction.
150
+
151
+ Version 0.2.0 supports direct local calls only in an unlocked macOS session. Targeted calls failed with official error `-10005` during genuine locked-session acceptance. OpenAI limits locked Computer Use to active trusted turns started from a connected device, so locked local use remains follow-up work and is not part of this release.
78
152
 
79
153
  ## Non-goals
80
154
 
81
- This project does not provide a Sky protocol clone, browser-host integration, credential extraction, TCC automation, app injection, re-signing, sender-authentication bypass, or automatic approval acceptance.
155
+ No private Sky protocol clone, browser-host integration, credential extraction, TCC automation, app injection, re-signing, sender-auth bypass, wrapper-side approval fabrication, persistent approval-file mutation, nested model fallback, or tool-result persistence.