Skip to content

Commit 7380cba

Browse files
authored
feat(agent): relax agent guardrails (#288)
* feat(agent): relax agent guardrails * fix(agent): preserve agent tool invariants
1 parent 54a6253 commit 7380cba

16 files changed

Lines changed: 1189 additions & 336 deletions

almanac/architecture/agent/codex-app-server-workflow.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ sources:
2020
path: plugins/agent.hk
2121
---
2222

23-
The Codex app-server workflow is Red's direct integration with the installed Codex CLI. Red starts `codex app-server --stdio`, initializes the app-server protocol, verifies the Codex account, starts an app-server thread, and then drives turns through JSONL requests and events [@codex]. The workflow matters because Codex is never given native workspace mutation authority: Red starts threads and turns with read-only sandboxing, denied native approvals, disabled extension surfaces, and Red-owned dynamic tools that read, edit, and save through the editor [@workflow] [@codex]. The editor side owns the bridge, active-session state, and bounded editor-tool channel through `AgentManager`, so app-server events can be polled from the editor loop without making Codex a direct editor owner [@manager] [@editor].
23+
The Codex app-server workflow is Red's direct integration with the installed Codex CLI. Red starts `codex app-server --stdio`, initializes the app-server protocol, verifies the Codex account, starts an app-server thread, and then drives turns through JSONL requests and events [@codex]. Codex is never given native workspace mutation authority: Red starts threads and turns with read-only sandboxing, denied native approvals, explicitly granted extension surfaces, and Red-owned dynamic tools that read, edit, and save through the editor [@workflow] [@codex]. The editor side owns the bridge, active-session state, and bounded editor-tool channel through `AgentManager`, so app-server events can be polled from the editor loop without making Codex a direct editor owner [@manager] [@editor].
2424

2525
## Process And Session Ownership
2626

27-
`CodexProcessSpec` records the exact executable, literal extra arguments, environment overrides, and working directory used to launch one Codex app-server worker [@codex]. The worker command appends `app-server --stdio`, disables apps, connectors, plugins, and remote plugins through Codex config overrides, pipes stderr into a bounded sanitized diagnostic tail, and kills the child on drop [@codex]. After startup, Red sends `initialize`, `initialized`, and `account/read`; the worker refuses to continue if account information does not show an authenticated Codex session [@codex].
27+
`CodexProcessSpec` records the executable, literal arguments, environment, working directory, and explicit Agent capability policy for one app-server worker [@codex]. The worker disables ungranted apps, connectors, plugins, remote plugins, skill MCP dependency installation, and orchestrator MCP through Codex config overrides. Thread configuration enables only MCP server names and feature categories listed under `[agent]`; inline and commit-message threads do not receive those extension grants. The worker also captures a bounded sanitized stderr tail and kills the child on drop [@codex]. After startup, Red sends `initialize`, `initialized`, and `account/read`; the worker refuses to continue without an authenticated Codex session [@codex].
2828

2929
The user-visible lifecycle follows the workflow document: `Space A` or `:Agent` opens the prompt, Red lazily starts the app-server, creates a thread, submits a turn, streams assistant deltas, and sends `turn/interrupt` for cancellation [@workflow]. The implementation mirrors that flow through `CodexCommand::NewSession`, `Prompt`, `PromptWithContext`, `Cancel`, and `CloseSession`; responses from `thread/start` become `SessionCreated`, responses from `turn/start` set the active turn id, assistant deltas become `Update`, and `turn/completed` becomes `Completed` [@codex].
3030

@@ -42,7 +42,7 @@ This boundary connects the workflow to [Agent-Attributed Edits](../../concepts/a
4242

4343
Prompt dispatch begins in the editor. Before sending a turn, `dispatch_agent_prompt` verifies a running bridge, rejects concurrent prompts for the same active session, emits `agent:turn_started`, marks the session active, records the user message for conversation recovery, and sends either `Prompt` or `PromptWithContext` to the Codex bridge [@editor]. `PromptWithContext` appends bounded active-editor context to the user text before the worker sends `turn/start` [@codex].
4444

45-
The worker keeps app-server reading, command handling, response correlation, and dynamic-tool results in one async loop [@codex]. It reads stdout frames on a separate task, uses a pending-request table keyed by JSON-RPC id, tracks sessions by Codex thread id, and drops tool results if the referenced turn is no longer active or has been cancelled [@codex]. Tool arguments, tool responses, app-server frames, per-turn tool-call count, tool runtime, file listing, search matches, and search bytes are bounded [@codex] [@workflow].
45+
The worker keeps app-server reading, command handling, response correlation, and dynamic-tool results in one async loop [@codex]. It reads stdout frames on a separate task, uses a pending-request table keyed by JSON-RPC id, tracks sessions by Codex thread id, and drops tool results if the referenced turn is no longer active or has been cancelled [@codex]. Tool arguments, tool responses, app-server frames, tool runtime, file-list pages, workspace walks, search matches, and search bytes are bounded; there is no per-turn tool-call count ceiling [@codex] [@workflow].
4646

4747
The editor polls both directions from `service_background`. It follows and executes pending editor-tool requests through the owner task, then drains Codex events; inactive-session updates are ignored, stale permission requests are denied, terminal events mark sessions inactive, and all user-facing Codex events are translated to plugin notifications such as `agent:update`, `agent:activity`, `agent:completed`, `agent:cancelled`, and `agent:error` [@editor].
4848

almanac/architecture/agent/dynamic-tools-and-editor-tools.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ Dynamic tools and editor tools are Red's app-server capability layer for Codex.
2121

2222
## Tool Surface
2323

24-
The app-server worker publishes `list_files`, `search_files`, `read_file`, and `write_file` itself, then appends editor schemas for `get_editor_state`, `open_file`, `select_text`, `apply_edits`, `run_editor_action`, `create_directory`, `add_annotations`, and `dismiss_annotations` [@codex] [@tools]. `list_files` walks the workspace without following links, respects ignore files, sorts results, and stops at Red's file, entry, and time bounds [@codex]. On Unix, `search_files` reads through descriptor-relative, no-follow, nonblocking filesystem operations; the workflow states that content search is unavailable on platforms without that safe read boundary, so Codex must use `read_file` instead [@codex] [@workflow].
24+
The app-server worker publishes `list_files`, `search_files`, `read_file`, and `write_file` itself, then appends editor schemas for `get_editor_state`, `open_file`, `select_text`, `apply_edits`, `run_editor_action`, `create_directory`, `add_annotations`, and `dismiss_annotations` [@codex] [@tools]. `list_files` walks without following links, respects ignore and sensitive-path policy, sorts results, and returns pages plus truncation metadata within Red's entry and time bounds [@codex]. On Unix, `search_files` reads through descriptor-relative, no-follow, nonblocking filesystem operations and reports bounded-scan truncation; platforms without that safe read boundary must use `read_file` [@codex] [@workflow].
2525

26-
`read_file` and `write_file` are editor-tool-host operations. `read_file` opens the safe workspace file through Red when needed and returns editor-visible contents, the current revision, and whether the file exists [@editor]. `write_file` requires that revision, replaces the complete buffer through an agent-origin editor transaction, and saves through Red [@tools] [@editor].
26+
`read_file` and `write_file` are editor-tool-host operations. `read_file` opens the safe workspace file through Red when needed and returns a bounded editor-visible page, current revision, existence, line range, and continuation metadata. Continuations must carry the first page's revision and fail if the buffer changes; an individual source line beyond the byte limit fails explicitly rather than returning an unrecoverable prefix [@codex] [@editor]. `write_file` requires the first page's revision, replaces the complete buffer through an agent-origin editor transaction, and saves through Red [@tools] [@editor].
2727

2828
The workflow documentation describes the same twelve-tool contract and its expected behavior, including bounded file listing, bounded search, Red-mediated reads, revision-checked writes, directory creation, editor state snapshots, file opening, UTF-16 selections, revision-checked edits, source annotations, and allow-listed navigation or LSP actions [@workflow].
2929

@@ -49,8 +49,8 @@ The editor applies that boundary consistently. `open_file` passes `LocationColum
4949

5050
## Followed Mutation And Activity
5151

52-
Mutating editor tools are followed before they apply. `prepare_agent_follow_step` resolves the target path, opens the file, moves the cursor to the first edit range when available, renders, and delays edit execution so the user can see the target [@editor]. `apply_agent_contents` then checks the expected revision, starts an `EditOrigin::Agent` transaction, replaces the buffer, commits, notifies change consumers, renders, and saves [@editor].
52+
Mutating editor tools are serialized before they apply. When `agent.follow_tool_calls` is enabled, `prepare_agent_follow_step` resolves the target, opens the file, moves the cursor to the first edit range when available, renders, and delays execution so the user can see it. The default skips those deliberate playback pauses and restores the active buffer after incidental file tools; explicit navigation tools retain their focus-changing behavior [@editor]. `apply_agent_contents` still checks the expected revision, starts an `EditOrigin::Agent` transaction, replaces the buffer, commits, notifies change consumers, renders, and saves [@editor].
5353

54-
The editor dispatcher checks more than schema validity before executing a tool. It requires an active session, requires an active workspace root, resolves relative or absolute tool paths through the workspace, rejects sensitive filenames, rejects ignored workspace paths, and rejects stale revisions before text changes apply [@editor]. Editor-tool requests travel over a bounded channel and time out if the dispatcher is backpressured or stops [@tools].
54+
The editor dispatcher checks more than schema validity before executing a tool. It requires an active session and workspace root, resolves paths through the workspace, rejects ignored paths, requires explicit consent for secret-like filenames, and rejects stale revisions before text changes apply [@editor]. Editor-tool requests travel over a bounded channel and time out if the dispatcher is backpressured or stops [@tools].
5555

5656
Tool calls also shape user-facing state. `EditorToolCall::activity_title` defines concise labels for operations such as opening a file, writing a file, or editing a path, while the editor event bridge forwards app-server activity updates as `agent:activity` [@tools] [@editor]. Use [Followed Editing](followed-editing) for the write-and-save path built on top of this tool layer.

almanac/architecture/agent/followed-editing.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: "Followed Editing"
3-
summary: "Followed editing is Red's full-agent mutation path: Codex can only change files through Red-owned dynamic tools that reveal the target, check revisions, apply an attributed editor transaction, and save through the editor."
3+
summary: "Followed editing is Red's full-agent mutation path: Codex can only change files through Red-owned dynamic tools that check revisions, apply an attributed editor transaction, and save through the editor."
44
topics: [architecture, agent, codex, agent-edits, safety]
55
sources:
66
- id: workflow
@@ -17,19 +17,19 @@ sources:
1717
path: src/agent_tools.rs
1818
---
1919

20-
Followed editing is Red's current safety boundary for full Codex agent writes. The Codex process runs with a read-only sandbox and denied native approvals, but Red exposes dynamic tools whose mutating calls are executed by the editor owner task, not by Codex writing the workspace directly [@workflow] [@codex]. Before a mutating tool takes effect, Red opens the file, reveals the affected location, waits briefly, then applies the change as an `EditOrigin::Agent` transaction and saves through the editor [@workflow] [@editor].
20+
Followed editing is Red's current safety boundary for full Codex agent writes. The Codex process runs with a read-only sandbox and denied native approvals, but Red exposes dynamic tools whose mutating calls are executed by the editor owner task, not by Codex writing the workspace directly [@workflow] [@codex]. Mutating tools apply as `EditOrigin::Agent` transactions and save through the editor. Tool calls are serialized but run without deliberate delays by default; users can enable target-revealing playback with `agent.follow_tool_calls` [@workflow] [@editor].
2121

2222
## Tool Entry Points
2323

24-
The full agent receives `list_files`, `search_files`, `read_file`, `write_file`, `get_editor_state`, `open_file`, `select_text`, `apply_edits`, and `run_editor_action` [@workflow]. `read_file` returns the current editor-visible contents and revision for a workspace file, including unsaved buffer contents, and both `write_file` and `apply_edits` require that revision before mutating text [@codex] [@tools].
24+
The full agent receives `list_files`, `search_files`, `read_file`, `write_file`, `create_directory`, `get_editor_state`, `open_file`, `select_text`, `apply_edits`, `add_annotations`, `dismiss_annotations`, and `run_editor_action` [@workflow]. `list_files` and `read_file` are paged and report continuation or truncation metadata. `read_file` returns current editor-visible contents and revision, including unsaved buffer contents; later pages must present the first page's revision, and `write_file`, `apply_edits`, and `add_annotations` reuse that same revision [@codex] [@tools].
2525

26-
The tool host is a bounded channel from the Codex worker into the editor loop. `EditorToolHost` packages each read, write, navigation, selection, or editor action as an `EditorToolRequest`, waits for the editor owner to answer, and times out if the dispatcher stalls [@tools]. The Codex worker rejects tool calls for unknown sessions, inactive turns, cancelled turns, commit-message sessions, oversized arguments, and turns that exceed the tool-call limit before it forwards a request [@codex].
26+
The tool host is a bounded channel from the Codex worker into the editor loop. `EditorToolHost` packages each read, write, navigation, selection, or editor action as an `EditorToolRequest`, waits for the editor owner to answer, and times out if the dispatcher stalls [@tools]. The Codex worker rejects tool calls for unknown sessions, inactive turns, cancelled turns, commit-message sessions, and oversized arguments before it forwards a request [@codex].
2727

28-
## Follow Before Apply
28+
## Serialized And Optional Follow Playback
2929

30-
The editor serializes tool playback through `service_background`. It first prepares the follow step by resolving the workspace path, opening the target file when relevant, moving the cursor to the first affected range for `apply_edits`, rendering the view, and delaying edit tools for the configured dwell period [@editor]. Only after that delay does the editor dispatch the tool request, which keeps the user-facing buffer in sync with the file Codex is about to read or modify [@workflow] [@editor].
30+
The editor serializes tool execution through `service_background`. By default, it dispatches the next tool immediately and restores the user's active buffer after incidental file tools. Explicit navigation tools still change focus. With `agent.follow_tool_calls = true`, it first resolves and opens the target when relevant, moves the cursor to the first affected range for `apply_edits`, renders, and uses the configured dwell period before dispatch [@workflow] [@editor].
3131

32-
Path resolution stays fail-closed. Agent tool paths must be non-empty, remain under the active workspace root after lexical normalization, avoid symlink components, avoid sensitive filenames, and avoid ignored workspace paths [@editor]. `list_files` and `search_files` also avoid symlink-following workspace walks and use bounded safe reads for content search on Unix [@codex] [@workflow].
32+
Path resolution stays fail-closed. Agent tool paths must be non-empty, remain under the active workspace root after lexical normalization, avoid symlink components, and avoid ignored workspace paths. Secret-like filenames require the explicit `agent.allow_sensitive_paths` grant [@editor]. `list_files` and `search_files` apply the same policy, avoid symlink-following workspace walks, and use bounded safe reads for content search on Unix [@codex] [@workflow].
3333

3434
## Mutation And Saving
3535

@@ -39,6 +39,6 @@ The save step is part of the full-agent contract. On Unix, Red writes through th
3939

4040
## Inline Assist Boundary
4141

42-
Inline assist is intentionally narrower. `Space i` starts an ephemeral Codex thread with only `submit_replacement`; Codex cannot choose a file, read additional files, or call the full editor-tool surface [@workflow] [@codex]. Red verifies the active buffer, window, revision, and original target text before applying the replacement as an agent-origin transaction, and the workflow explicitly leaves the inline result unsaved so the user can keep, undo, refine, or promote it to the full Agent workflow [@workflow] [@editor].
42+
Inline assist is intentionally narrower. `Space i` starts an ephemeral Codex thread with bounded read-only project tools and one result-submission call; Codex cannot choose a mutation target or call the full editor-tool surface [@workflow] [@codex]. Red verifies the active buffer, window, revision, and original target text before applying a replacement as an agent-origin transaction. Exact-scope foreground edits auto-apply by default, while background, stale, and expanded-scope results wait for review. Inline edits remain unsaved and undoable [@workflow] [@editor].
4343

4444
Use [Agent-attributed edits](../../concepts/agent-attributed-edits) for the user-facing edit model and [Inspect agent history](../../guides/agent/inspect-agent-history) for the operational path after full-agent or inline edits have entered undo history.

default_config.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,19 @@ icon_style = "nerd_font"
7373
# Override `command` only when Codex is installed outside PATH.
7474
[agent]
7575
# command = "/path/to/codex"
76+
# Run file tools immediately by default. Set this to true to reveal each target
77+
# and retain the deliberate playback pauses used by followed editing.
78+
follow_tool_calls = false
79+
# Apply edits confined to the exact inline target immediately. These edits stay
80+
# unsaved and undoable. Wider same-file proposals always require review.
81+
auto_apply_inline_edits = true
82+
# Explicitly opt in before secret-like filenames can enter Agent context.
83+
allow_sensitive_paths = false
84+
# Opt in to configured Codex capabilities by exact server name or category.
85+
enabled_mcp_servers = []
86+
# Supported values: apps, connectors, plugins, remote_plugin,
87+
# skill_mcp_dependency_install, orchestrator_mcp.
88+
enabled_codex_features = []
7689

7790
[search]
7891
# Preview the next match while typing / or ?.

0 commit comments

Comments
 (0)