Skip to content

Run a row of read and command calls together, up to four at a time - #291

Merged
lydakis merged 23 commits into
mainfrom
claude/project-thread-dcbv64
Oct 28, 2026
Merged

lydakis merged 23 commits into
mainfrom
claude/project-thread-dcbv64

Conversation

@lydakis

@lydakis lydakis commented Oct 28, 2026

Copy link
Copy Markdown
Owner

Third PR from the tools-vs-Codex comparison, following #236, #247 and #254: parallel tool calls.

What changes

  • When a model asks for several calls in one response, a run of calls in a row that only read (read) or run ungated foreground commands (shell) now starts together. At most four run at once. Codex runs these calls in parallel too.
  • Each result is still recorded in call order, so history reads exactly as before.
  • Gated calls, client-answered (declared) tools, and anything that writes or edits still run one at a time, as now.
  • A sandboxed bot's commands all run in its single sandbox, built once for the batch. A command that asks to leave the sandbox (sandbox_permissions) still runs alone, so it can be gated or refused.
  • A steer moves every command that's still running to the background, the same way it does for a single command.

Memory and load

A batch holds at most four calls' output buffers at once, and each is capped as before. The process budget still limits concurrent commands across all bots, so a batch can't run past it.

Tests

  • tests/test_wait.py: two calls that each sleep finish in about the time of one, and results come back in call order.
  • tests/test_approvals.py: a sandboxed bot's two commands run together inside its sandbox, and a third that asks to escalate runs alone and is refused.
  • Local: test_approvals + test_wait pass (87 tests, with the sandbox tests on), and clippy is clean.

No visible UI change, so no screenshots.


Generated by Claude Code

claude added 20 commits October 28, 2026 06:48
The daemon gets apply_patch beside edit and write: Codex's patch format,
checked whole before any file is written, with Codex's lenient context
matching. On Responses it is a custom tool constrained by Codex's Lark
grammar, its call stored as sent and answered with a
custom_tool_call_output (tools.custom, schema 55); on Anthropic a function
taking the patch as input. New bots get apply_patch on a Responses model
and edit otherwise; the approver judges a patch by every file it names,
and Sonny draws one as a diff.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGFtCdGun1rPhhwTSrG
…patch paths kept

An insertion with no context goes at the end of the file, so a later
chunk can change an earlier line; replacements are applied in file order
and overlapping chunks fail instead of panicking. A moved file keeps the
source's permissions. The approver reads the paths recovered from a cut
patch preview.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGFtCdGun1rPhhwTSrG
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGFtCdGun1rPhhwTSrG
…ounded, matching off the runtime

A patch that changes one file twice is refused at parse, since the second
change would be computed from the file as it was. A move to the same file
(./f for f) is an ordinary update instead of a delete. The files a patch
stages hold at most 64 MiB together. Matching runs on the blocking pool,
normalizes each line once per pass and checks a place's last line first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGFtCdGun1rPhhwTSrG
…ept, a cut patch names all its files

An added or moved-to path that is a folder, or sits below a file, fails
before any file is written. A result of one empty line keeps its newline.
tool_started names every file a cut patch changes, and the approver uses
those over what the preview holds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGFtCdGun1rPhhwTSrG
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGFtCdGun1rPhhwTSrG
Past it the event says paths_cut, and a later call the approver judges is
marked unseen, as when a written file is too long to show. A patch read
from its cut preview alone counts the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGFtCdGun1rPhhwTSrG
A sandboxed bot's patch is confined like its writes: each file it
changes is checked against the bot's roots before any is written, and
the files are written through the sandbox's helper. A patch that
changes a file outside them escapes, and is gated as an escaping write.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGFtCdGun1rPhhwTSrG
… only regular files for a diff

A sandboxed patch is staged before it takes a process slot, and one that
only deletes takes none. Sonny's diff of an edit or a patch reads the
file as it is now only when it is a regular file within the daemon's
size limit, so a FIFO never blocks the screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGFtCdGun1rPhhwTSrG
…nes compared

Only the punctuation pass makes new strings, once for the whole file
rather than for each chunk, and one update compares at most 50 million
lines before it fails with invalid_patch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGFtCdGun1rPhhwTSrG
…cked in one sort

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGFtCdGun1rPhhwTSrG
…one placing budget

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGFtCdGun1rPhhwTSrG
…r at a time

As Codex runs them: an ungated foreground command or a read starts beside
the others in one commit, and each result is recorded in call order. A
sandboxed bot's commands all run in its one sandbox; one that asks to
leave it still runs alone, to be gated or refused. A steer moves every
command still running to the background.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGFtCdGun1rPhhwTSrG
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-28T10:23:39.479951Z 008da79 New commits
🔒 Security Review ✅ Completed 2026-10-28T10:32:23.484786Z 008da79 New commits

Security findings

Advisory findings (1)

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 78c5a4d995

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/server/turn.rs Outdated
Comment thread src/server/turn.rs Outdated
Comment thread src/server/turn.rs
@lydakis lydakis mentioned this pull request Oct 28, 2026
… the screen

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGFtCdGun1rPhhwTSrG

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e32bf35f74

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/server/turn.rs Outdated
Comment thread src/server/turn.rs Outdated
…t for store room beside the running calls

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGFtCdGun1rPhhwTSrG

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0c490427dd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/server/turn.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛡️ Codex Security Review · Automatically triggered

Here are some automated security review suggestions for this pull request.

Reviewed commit: 008da79e4b

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

Comment thread src/server/turn.rs
.iter()
.any(|(_, prepared)| matches!(prepared, Prepared::Shell { .. }));
let sandbox = match shells && record.sandboxed() {
true => self.sandbox(record, workspace).await,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛡️ Codex Security Review · Automatically triggered

P1 Badge Security: Rebuild the sandbox policy before every shell spawn

With workspace-write enabled on Linux, a sandboxed bot can create inherited helpers rooted at /tmp and /tmp/x and replace /tmp/x with a symlink between calls. This batch constructs Policy once and clones it, so a later shell skips root()’s symlink recheck; the stale path reaches bwrap --bind, making an arbitrary host directory writable without escalation approval. The restricted socket permits children in caller-writable /tmp, and process-slot saturation can delay the later spawn until after the swap. Rebuild and revalidate the policy immediately before every shell spawn.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not fixing this in this PR. It needs a hostile bot to swap a root for a symlink in the window between the batch's policy check and a later spawn, and the project's stance is to log sandbox edges like this rather than hold a release for them. It's logged in #96. The fix is small: build the policy per shell call, the way the lone path does.


Generated by Claude Code

@lydakis
lydakis merged commit b0869f7 into main Oct 28, 2026
4 checks passed
lydakis pushed a commit that referenced this pull request Oct 29, 2026
…rent tool calls are built

The README still said Agent provides no sandbox, and docs/EVIDENCE.md still
listed concurrent tool calls as a design. Both now match main: bots made with
a sandbox run confined (bubblewrap, Seatbelt), and calls in a row run
together since #291, with no fleet measurement yet. Sonny's /usage is
described as token usage from retained history.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGEK7HMibaxgHFDtGXA
lydakis pushed a commit that referenced this pull request Oct 29, 2026
…rent tool calls are built

The README still said Agent provides no sandbox, and docs/EVIDENCE.md still
listed concurrent tool calls as a design. Both now match main: bots made with
a sandbox run confined (bubblewrap, Seatbelt), and calls in a row run
together since #291, with no fleet measurement yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGEK7HMibaxgHFDtGXA
lydakis added a commit that referenced this pull request Oct 29, 2026
…rent tool calls are built (#360)

The README still said Agent provides no sandbox, and docs/EVIDENCE.md still
listed concurrent tool calls as a design. Both now match main: bots made with
a sandbox run confined (bubblewrap, Seatbelt), and calls in a row run
together since #291, with no fleet measurement yet.


Claude-Session: https://claude.ai/code/session_013jkdGEK7HMibaxgHFDtGXA

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants