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.
- package/ARCHITECTURE.md +150 -0
- package/CONTRIBUTING.md +16 -10
- package/MIGRATION.md +94 -0
- package/PROOF.md +128 -54
- package/README.md +97 -115
- package/SECURITY.md +45 -22
- package/dist/audit.d.ts +15 -14
- package/dist/audit.js +1 -1
- package/dist/audit.js.map +1 -1
- package/dist/config.d.ts +8 -8
- package/dist/config.js +8 -103
- package/dist/config.js.map +1 -1
- package/dist/direct-broker.d.ts +71 -0
- package/dist/direct-broker.js +652 -0
- package/dist/direct-broker.js.map +1 -0
- package/dist/direct-service.d.ts +33 -0
- package/dist/direct-service.js +350 -0
- package/dist/direct-service.js.map +1 -0
- package/dist/lock.d.ts +1 -0
- package/dist/lock.js +32 -3
- package/dist/lock.js.map +1 -1
- package/dist/mcp-elicitation.d.ts +8 -0
- package/dist/mcp-elicitation.js +47 -0
- package/dist/mcp-elicitation.js.map +1 -0
- package/dist/mcp-server.js +43 -100
- package/dist/mcp-server.js.map +1 -1
- package/dist/system.d.ts +0 -1
- package/dist/system.js +12 -37
- package/dist/system.js.map +1 -1
- package/dist/tools.d.ts +84 -0
- package/dist/tools.js +262 -0
- package/dist/tools.js.map +1 -0
- package/docs/adr/0001-standalone-code-mode-mcp.md +45 -0
- package/integrations/pi/README.md +51 -27
- package/integrations/pi/index.ts +237 -125
- package/integrations/pi/mcp.json.example +3 -3
- package/npm-shrinkwrap.json +3275 -48
- package/package.json +41 -13
- package/dist/policy.d.ts +0 -42
- package/dist/policy.js +0 -428
- package/dist/policy.js.map +0 -1
- package/dist/prompt.d.ts +0 -62
- package/dist/prompt.js +0 -119
- package/dist/prompt.js.map +0 -1
- package/dist/runner.d.ts +0 -55
- package/dist/runner.js +0 -494
- package/dist/runner.js.map +0 -1
- package/dist/service.d.ts +0 -17
- package/dist/service.js +0 -382
- package/dist/service.js.map +0 -1
package/ARCHITECTURE.md
ADDED
|
@@ -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
|
|
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
|
|
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
|
|
19
|
-
- Do not add
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
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
|
-
|
|
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
|
-
#
|
|
1
|
+
# Direct architecture proof and acceptance record
|
|
2
2
|
|
|
3
|
-
This records evidence for the
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
18
|
+
## Architectural proof
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
### Negative raw-helper probe
|
|
16
21
|
|
|
17
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
-
|
|
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
|
-
|
|
90
|
+
## Fresh Pi unlocked real-app acceptance
|
|
41
91
|
|
|
42
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
-
|
|
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
|
-
|
|
120
|
+
## Pi 0.80.7 progressive-disclosure measurement
|
|
65
121
|
|
|
66
|
-
|
|
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
|
-
|
|
124
|
+
- `computer_use_list_apps`
|
|
125
|
+
- `computer_use_get_app_state`
|
|
69
126
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
5.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
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.
|