Skip to content

Commit f842fdf

Browse files
committed
feat(codex): experimental Codex agent mode via the Agent Client Protocol (#378)
Add an opt-in Codex (OpenAI) agent mode that drives the chat panel over the Agent Client Protocol (ACP), the way Claude mode drives it today: streaming replies, tool-call cards with diffs, and per-tool approval. An NBI MCP tool is invoked end to end to prove the path. - ACP client backend (acp_agent.py) on a persistent worker thread, mapping ACP events onto NBI's chat surfaces, with single-flight turns and a hardened subprocess lifecycle. A small stdio MCP server (acp_mcp_server.py) exposes an NBI tool to the agent. - codex_settings + a codex_mode admin policy that defaults to force-off, plus OPENAI_API_KEY / OPENAI_BASE_URL / NBI_CODEX_CHAT_MODEL overrides, following the existing seven-place policy and settings-override conventions. - Frontend: a Codex settings tab (enable, model, key, base URL) mirroring the Claude tab, and chat-panel awareness so the input and routing follow Codex. - An in-chat agent picker (shown when more than one agent mode is enabled) that resolves a single active agent from the enabled modes and a persisted preference; with no preference the historical Claude-wins default holds. The picker is a custom icon dropdown, and the agent footer is unified (Ask/Agent and tools stay on the native model path; agent modes show only their badge). - Consistent branding: the OpenAI mark for the Codex participant and tab. - Admin gating parity with Claude: a codex_full_access policy (default force-off) pins Codex to approval_policy=untrusted so it asks before risky actions, clamped server-side; user-choice exposes a "Full access" toggle that flips the launch to approval_policy=never. README and admin-guide document the controls, the CODEX_HOME isolation, and the residual precedence caveat. Unit tests cover the ACP-to-NBI mapping, approval, the policy clamps, the active-agent resolution, the approval-arg mapping, and the credential scrub. The live path was verified in a running JupyterLab.
1 parent f8548db commit f842fdf

19 files changed

Lines changed: 1982 additions & 148 deletions

README.md

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ Bypass Permissions never persists: starting a **New chat session** (or `/clear`)
105105

106106
Choosing **Bypass Permissions** does not arm it immediately. It opens a confirmation step; only after you confirm does bypass take effect, and while it is active the shield turns into a red warning icon as a persistent indicator. Bypass must be re-armed each session: starting a new chat or restarting the Claude client drops back to Default. And because the server re-checks the requested mode on every message, an armed bypass can never outlive a policy that an administrator has since turned off.
107107

108-
**Admin gating.** Bypass Permissions is **off by default** and hidden from the selector unless an administrator enables it: it is governed by the `claude_bypass_permissions` policy (`NBI_CLAUDE_BYPASS_PERMISSIONS_POLICY`), the only admin policy whose default is `force-off` rather than `user-choice`. The requested mode is also clamped on the server for every message, so the gate can't be bypassed by a hand-crafted request. Independently, NBI honors Claude Code's enterprise [managed settings](https://code.claude.com/docs/en/settings): `permissions.disableBypassPermissionsMode` removes the option regardless of the NBI policy, and `permissions.defaultMode` sets the selector's starting mode (Bypass excepted, since it never auto-arms). See [Allowing Bypass Permissions](docs/admin-guide.md#allowing-bypass-permissions-in-the-claude-permission-mode-selector) in the admin guide.
108+
**Admin gating.** Bypass Permissions is **off by default** and hidden from the selector unless an administrator enables it: it is governed by the `claude_bypass_permissions` policy (`NBI_CLAUDE_BYPASS_PERMISSIONS_POLICY`), one of three admin policies that default to `force-off` rather than `user-choice` (the others gate the experimental Codex mode and Codex full access). The requested mode is also clamped on the server for every message, so the gate can't be bypassed by a hand-crafted request. Independently, NBI honors Claude Code's enterprise [managed settings](https://code.claude.com/docs/en/settings): `permissions.disableBypassPermissionsMode` removes the option regardless of the NBI policy, and `permissions.defaultMode` sets the selector's starting mode (Bypass excepted, since it never auto-arms). See [Allowing Bypass Permissions](docs/admin-guide.md#allowing-bypass-permissions-in-the-claude-permission-mode-selector) in the admin guide.
109109

110110
The `/enter-plan-mode` and `/exit-plan-mode` slash commands still work if typed but are no longer offered in autocomplete; the selector replaces them and will retire the commands in a future release.
111111

@@ -196,24 +196,26 @@ Most settings panel toggles can be locked by org administrators. Two shapes:
196196

197197
**Boolean policies** use the `*_POLICY` suffix and accept three values: `user-choice` (default — user toggles freely), `force-on` (locked enabled), `force-off` (locked disabled). When forced, the panel control is disabled with a "Locked by your administrator" tooltip and any client-side write is ignored.
198198

199-
| Env var | Locks the Settings panel control for |
200-
| ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
201-
| `NBI_EXPLAIN_ERROR_POLICY` | "Explain cell errors" |
202-
| `NBI_OUTPUT_FOLLOWUP_POLICY` | "Ask about cell outputs" |
203-
| `NBI_OUTPUT_TOOLBAR_POLICY` | "Show output toolbar" |
204-
| `NBI_CLAUDE_MODE_POLICY` | "Enable Claude mode" |
205-
| `NBI_CLAUDE_CONTINUE_CONVERSATION_POLICY` | "Remember conversation history" |
206-
| `NBI_CLAUDE_CODE_TOOLS_POLICY` | "Claude Code tools" |
207-
| `NBI_CLAUDE_JUPYTER_UI_TOOLS_POLICY` | "Jupyter UI tools" |
208-
| `NBI_CLAUDE_SETTING_SOURCE_USER_POLICY` | Setting source: User |
209-
| `NBI_CLAUDE_SETTING_SOURCE_PROJECT_POLICY` | Setting source: Project |
210-
| `NBI_STORE_GITHUB_ACCESS_TOKEN_POLICY` | "Remember my GitHub Copilot access token" |
211-
| `NBI_SKILLS_MANAGEMENT_POLICY` | The Skills tab (force-off hides it and 403s the API; also disables the managed-skills reconciler) |
212-
| `NBI_CLAUDE_MCP_MANAGEMENT_POLICY` | The Claude-mode MCP Servers tab (force-off hides it and 403s `/claude-mcp/*`; independent of the non-Claude MCP Servers tab) |
213-
| `NBI_CLAUDE_PLUGINS_MANAGEMENT_POLICY` | The Claude-mode Plugins tab (force-off hides it and 403s `/plugins/*`) |
214-
| `NBI_CLAUDE_BYPASS_PERMISSIONS_POLICY` | "Bypass Permissions" in the Claude permission-mode selector (defaults to `force-off`, the only policy that does; `user-choice` exposes the option, which the user still arms per session) |
215-
| `NBI_TERMINAL_DRAG_DROP_POLICY` | Terminal drag-drop file attach feature |
216-
| `NBI_REFRESH_OPEN_FILES_ON_DISK_CHANGE_POLICY` | "Refresh open files when changed on disk" |
199+
| Env var | Locks the Settings panel control for |
200+
| ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
201+
| `NBI_EXPLAIN_ERROR_POLICY` | "Explain cell errors" |
202+
| `NBI_OUTPUT_FOLLOWUP_POLICY` | "Ask about cell outputs" |
203+
| `NBI_OUTPUT_TOOLBAR_POLICY` | "Show output toolbar" |
204+
| `NBI_CLAUDE_MODE_POLICY` | "Enable Claude mode" |
205+
| `NBI_CODEX_MODE_POLICY` | "Enable Codex mode" (experimental ACP agent mode; defaults to `force-off`, set `user-choice` to allow it) |
206+
| `NBI_CODEX_FULL_ACCESS_POLICY` | "Full access" for Codex: run tools without asking (defaults to `force-off`, so Codex asks before anything beyond trusted read-only commands; `user-choice` lets users opt into unattended runs) |
207+
| `NBI_CLAUDE_CONTINUE_CONVERSATION_POLICY` | "Remember conversation history" |
208+
| `NBI_CLAUDE_CODE_TOOLS_POLICY` | "Claude Code tools" |
209+
| `NBI_CLAUDE_JUPYTER_UI_TOOLS_POLICY` | "Jupyter UI tools" |
210+
| `NBI_CLAUDE_SETTING_SOURCE_USER_POLICY` | Setting source: User |
211+
| `NBI_CLAUDE_SETTING_SOURCE_PROJECT_POLICY` | Setting source: Project |
212+
| `NBI_STORE_GITHUB_ACCESS_TOKEN_POLICY` | "Remember my GitHub Copilot access token" |
213+
| `NBI_SKILLS_MANAGEMENT_POLICY` | The Skills tab (force-off hides it and 403s the API; also disables the managed-skills reconciler) |
214+
| `NBI_CLAUDE_MCP_MANAGEMENT_POLICY` | The Claude-mode MCP Servers tab (force-off hides it and 403s `/claude-mcp/*`; independent of the non-Claude MCP Servers tab) |
215+
| `NBI_CLAUDE_PLUGINS_MANAGEMENT_POLICY` | The Claude-mode Plugins tab (force-off hides it and 403s `/plugins/*`) |
216+
| `NBI_CLAUDE_BYPASS_PERMISSIONS_POLICY` | "Bypass Permissions" in the Claude permission-mode selector (defaults to `force-off`, as do `NBI_CODEX_MODE_POLICY` and `NBI_CODEX_FULL_ACCESS_POLICY`; `user-choice` exposes the option, which the user still arms per session) |
217+
| `NBI_TERMINAL_DRAG_DROP_POLICY` | Terminal drag-drop file attach feature |
218+
| `NBI_REFRESH_OPEN_FILES_ON_DISK_CHANGE_POLICY` | "Refresh open files when changed on disk" |
217219

218220
The first three also have matching traitlets on `NotebookIntelligence` (`explain_error_policy`, `output_followup_policy`, `output_toolbar_policy`); add the others as needed in the same shape:
219221

0 commit comments

Comments
 (0)