Skip to content

Raise macOS RLIMIT_NOFILE so GUI-spawned agents inherit more than 256 - #12289

Open
sanshengai wants to merge 1 commit into
manaflow-ai:mainfrom
sanshengai:raise-macos-nofile-soft-limit
Open

Raise macOS RLIMIT_NOFILE so GUI-spawned agents inherit more than 256#12289
sanshengai wants to merge 1 commit into
manaflow-ai:mainfrom
sanshengai:raise-macos-nofile-soft-limit

Conversation

@sanshengai

@sanshengai sanshengai commented Sep 11, 2026

Copy link
Copy Markdown

Summary

  • Raise the process RLIMIT_NOFILE soft limit at CmuxMain.main(), before worker re-exec or any child spawn, so login shells and coding agents inherit more than launchd's default 256.
  • macOS GUI apps inherit launchctl limit maxfiles soft=256. Ghostty's /usr/bin/login -flp … does not raise it. Codex then fans out skill-file reads (up to 8×64 concurrent opens) and fails with EMFILE (Too many open files (os error 24)), which it surfaces as Skipped loading N skill(s) due to invalid SKILL.md files even when the files are fine.
  • The helper never lowers an existing soft limit, never changes the hard limit, and ignores setrlimit failure. If Darwin rejects 65536 (OPEN_MAX is 10240 on some versions), it falls back to 10240 then 8192.

Testing

  • swift build of Packages/macOS/CmuxFoundation succeeds with the new FileDescriptorLimit type (Swift 6 / macOS 14).
  • Added table-driven tests for proposedSoftLimit (raise 256, clamp to hard, never lower, ignore unlimited). swift test could not run under Command Line Tools-only (TestingMacros plugin missing); please run swift test --filter FileDescriptorLimitTests with Xcode 26.
  • Did not rebuild the full .app in this environment (needs the Ghostty submodule / Xcode 26). Logic matches a live diagnosis on cmux 0.64.22: launchctl limit maxfiles was 256 unlimited, the cmux process sat at ~167 open files, and a Codex session started from that tree skipped 18 valid SKILL.md files with os error 24.
  • Suggested local check after a debug build: from a pane, python3 -c 'import resource; print(resource.getrlimit(resource.RLIMIT_NOFILE))' should show a soft limit well above 256.

Demo Video

Not a UI change.

Checklist

  • I tested the change locally (package compile + limit arithmetic; full app rebuild not run here)
  • I added or updated tests for behavior changes
  • I updated docs/changelog if needed
  • I requested bot reviews after my latest commit (copy/paste block above or equivalent)
  • All code review bot comments are resolved
  • All human review comments are resolved

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Note

Low Risk
Process-startup resource limit bump with conservative guards; no auth or data-path changes, and failures are ignored.

Overview
Raises the macOS RLIMIT_NOFILE soft limit at the very start of CmuxMain.main(), before worker re-exec or any child spawn, so login shells and coding agents inherit more than launchd’s default 256 open files.

Adds FileDescriptorLimit in CmuxFoundation: best-effort setrlimit toward 65,536, with 10,240 / 8,192 fallbacks if Darwin rejects the preferred value; it never lowers an existing soft limit, never changes the hard limit, and ignores failures. Unit tests cover proposedSoftLimit (raise from 256, clamp to hard, no lowering, unlimited soft).

Reviewed by Cursor Bugbot for commit 4c97503. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Raises the macOS RLIMIT_NOFILE soft limit at process startup so GUI-spawned agents inherit more than launchd's default 256, preventing EMFILE errors that made coding agents skip valid SKILL.md files.

  • Adds FileDescriptorLimit.raiseSoftLimitIfNeeded() in CmuxFoundation, called from CmuxMain.main() before worker re-exec or child spawn.
  • Never lowers an existing soft limit, never changes the hard limit, and ignores setrlimit failure.
  • Tries 65,536 first, then falls back to 10,240 and 8,192 for Darwin versions that reject higher values.
  • Adds table-driven tests for proposedSoftLimit.

Written for commit 4c97503. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Improved macOS process reliability by raising the available file-descriptor limit when needed.
    • Child processes, terminals, and agents can now inherit the increased limit.
  • Tests

    • Added coverage for preferred and fallback limits, hard-limit clamping, unlimited limits, and already-sufficient limits.

macOS GUI apps inherit launchd's soft maxfiles of 256. cmux login shells
and coding agents inherit that ceiling, so Codex hits EMFILE while
scanning SKILL.md files and misreports them as invalid.

Raise the soft limit at CmuxMain.main() before worker re-exec or child
spawn. Never lower an existing limit or change the hard limit.
@vercel

vercel Bot commented Sep 11, 2026

Copy link
Copy Markdown

@sanshengai is attempting to deploy a commit to the Manaflow Team on Vercel.

A member of the Team first needs to authorize it.

@sanshengai

Copy link
Copy Markdown
Author

@codex review
@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 11, 2026

Copy link
Copy Markdown

@codex review
@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

@sanshengai cubic can't start this review because your workspace has reached its free monthly review limit. cubic has reviewed 339,945 of the 320,000 allowed lines of code this month. Reviews resume on 1 October 2026 (in 20 days). Paid plans include much higher monthly review limits. Upgrade now to resume reviews.

To help optimise your usage, you can tune cubic to get the most out of your usage limits:

Learn more →

@github-actions

Copy link
Copy Markdown


Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution. You can sign the CLA by just posting a Pull Request Comment same as the below format.


I have read the CLA Document v2.2 and I hereby sign the CLA


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: c7d7b1ea-83f1-4695-bd3a-ec5a51f3edf1

📥 Commits

Reviewing files that changed from the base of the PR and between 0862704 and 4c97503.

📒 Files selected for processing (3)
  • Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/Process/FileDescriptorLimit.swift
  • Packages/macOS/CmuxFoundation/Tests/CmuxFoundationTests/Process/FileDescriptorLimitTests.swift
  • Sources/cmuxApp.swift

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The change adds macOS file descriptor limit management. It calculates capped targets, tries preferred and fallback limits, tests the calculation behavior, and invokes the limit update before application startup and child process creation.

Changes

File descriptor limit initialization

Layer / File(s) Summary
Limit calculation and application
Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/Process/FileDescriptorLimit.swift, Packages/macOS/CmuxFoundation/Tests/CmuxFoundationTests/Process/FileDescriptorLimitTests.swift
FileDescriptorLimit calculates targets against the hard limit, applies preferred and fallback values with getrlimit and setrlimit, and tests the supported limit cases.
Startup integration
Sources/cmuxApp.swift
CmuxMain.main() raises the soft file descriptor limit before worker re-execution, child spawning, and application startup.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CmuxMain
  participant FileDescriptorLimit
  participant Kernel as RLIMIT_NOFILE
  participant ChildProcesses
  CmuxMain->>FileDescriptorLimit: raiseSoftLimitIfNeeded()
  FileDescriptorLimit->>Kernel: read current limits
  FileDescriptorLimit->>Kernel: try preferred or fallback soft limit
  Kernel-->>FileDescriptorLimit: apply result
  CmuxMain->>ChildProcesses: start workers and child processes
  ChildProcesses->>Kernel: inherit raised soft limit
Loading

Merge Risk: ⚪ Minimal · up to 4c975

The limit initialization preserves existing and hard limits, applies before child creation, and no actionable merge-blocking risk remains.


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Cmux No Ambient Global State ❌ Error The PR adds a caseless public enum used as a static-only namespace in Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/Process/FileDescriptorLimit.swift:19. Its behavior is exposed as the static… Replace FileDescriptorLimit with a constructable owning type, such as FileDescriptorLimitController. Move the limit calculation and raising behavior onto instance methods. Inject the limit reader/writer or Darwin adapter and limit confi…
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (23 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed PASS. The production diff adds a stateless FileDescriptorLimit enum and calls it during process startup. It adds no service protocol, Sendable reference type, UI-bound store, actor, or explicit `@…
Cmux Swift Blocking Runtime ✅ Passed The production diff adds FileDescriptorLimit.raiseSoftLimitIfNeeded() and a finite loop over setrlimit targets. It adds no semaphore, blocking wait, sleep, delayed dispatch, polling loop, `Dispatc…
Cmux Browser Automation Off-Main ✅ Passed PASS. The authoritative PR range changes only FileDescriptorLimit.swift, its tests, and the startup call in Sources/cmuxApp.swift. The diff adds RLIMIT_NOFILE handling and does not add or modify any b…
Cmux Expensive Synchronous Load ✅ Passed The diff does not add or move an expensive synchronous agent-history load. The new FileDescriptorLimit.raiseSoftLimitIfNeeded() performs bounded getrlimit/setrlimit calls and constant-size arith…
Cmux Cache Substitution Correctness ✅ Passed PASS: The reviewed diff adds FileDescriptorLimit, which performs a fresh getrlimit read and applies configured limit targets with setrlimit; it does not substitute a cached value. The only app i…
Cmux No Hacky Sleeps ✅ Passed PASS: The pull request changes only Swift production code and Swift tests. The applicable rule scopes this check to TypeScript, JavaScript, shell, and non-Swift build/runtime scripts; Swift timing and…
Cmux Algorithmic Complexity ✅ Passed The production change does not introduce a scalable collection scan. FileDescriptorLimit.raiseSoftLimitIfNeeded() iterates only over [preferredSoftLimit] + fallbackSoftLimits, whose bound is three…
Cmux Swift Concurrency ✅ Passed PASS: The pull request adds only synchronous RLIMIT_NOFILE logic and one synchronous call from CmuxMain.main(). The new FileDescriptorLimit implementation uses getrlimit, setrlimit, and a sy…
Cmux Swift @Concurrent ✅ Passed PASS: The authoritative PR diff adds only synchronous Swift APIs and a synchronous call. FileDescriptorLimit.proposedSoftLimit and raiseSoftLimitIfNeeded are not async, nonisolated async, or `…
Cmux Swift Package Boundaries ✅ Passed PASS: The independently testable file-descriptor limit logic is introduced in the existing CmuxFoundation SwiftPM target at `Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/Process/FileDescript…
Cmux Swiftpm Lockfiles ✅ Passed PASS. The authoritative PR diff changes only two Swift source/test files under Packages/macOS/CmuxFoundation and Sources/cmuxApp.swift. It does not change Package.swift, any Package.resolved, …
Cmux Swift Logging ✅ Passed PASS: The PR adds no production logging. The new runtime helper only calls getrlimit/setrlimit, and CmuxMain.main() only invokes that helper. The added tests use #expect and do not write outpu…
Cmux User-Facing Error Privacy ✅ Passed PASS: The production diff adds only RLIMIT_NOFILE calculation and setrlimit logic, plus one call before startup. It does not add or change alerts, user-facing errors, command output, API error bodies,…
Cmux Full Internationalization ✅ Passed PASS: The diff adds no user-facing text, localization key, catalog entry, metadata, or web message. The new Swift file contains developer-only API comments and RLIMIT/protocol tokens, and `cmuxApp.swi…
Cmux Swiftui State Layout ✅ Passed PASS. The pull request adds Darwin file-descriptor limit handling and a call in CmuxMain.main(). The new files contain no SwiftUI state or layout constructs. The only change in `Sources/cmuxApp.swif…
Cmux Architecture Rethink ✅ Passed PASS. The diff adds a small process-start correctness fix with a clear owner: FileDescriptorLimit owns the RLIMIT_NOFILE invariant, and CmuxMain.main() invokes it once before worker routing and …
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PASS — The authoritative diff adds FileDescriptorLimit, its tests, and one call in CmuxMain.main(). It does not introduce or materially change an NSWindow, NSPanel, NSWindowController, Swift…
Cmux Source Artifacts ✅ Passed PASS: The diff adds two hand-written Swift source/test files under the existing CmuxFoundation Sources and Tests trees, plus a three-line call in the existing Sources/cmuxApp.swift file. All changed p…
Cmux No Test Or Debug Seam In Production Source ✅ Passed The changed production Swift files add no test-build guard, debug-named member, test hook, or test-only accessor. FileDescriptorLimit.raiseSoftLimitIfNeeded() is called from CmuxMain.main() in pro…
Title check ✅ Passed The title clearly and concisely describes the primary change: raising macOS RLIMIT_NOFILE so GUI-spawned agents inherit a higher soft limit.
Description check ✅ Passed The description includes the required Summary, Testing, Demo Video, and Checklist sections. It explains the change, motivation, test results, limitations, and remaining review items. The unchecked rev…
Full details: Cmux No Ambient Global State

Explanation

The PR adds a caseless public enum used as a static-only namespace in Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/Process/FileDescriptorLimit.swift:19. Its behavior is exposed as the static API proposedSoftLimit at line 29 and raiseSoftLimitIfNeeded at line 45, with only static limits at lines 21 and 25. The app calls this ambient static behavior from Sources/cmuxApp.swift:34. This matches the rule's explicit failure condition for a type whose API is mostly static functions. The existing @main entry point is an allowed platform boundary, but it does not make the new namespace type compliant.

Resolution

Replace FileDescriptorLimit with a constructable owning type, such as FileDescriptorLimitController. Move the limit calculation and raising behavior onto instance methods. Inject the limit reader/writer or Darwin adapter and limit configuration into its initializer so tests can provide fakes. Construct the controller at the CmuxMain.main() composition seam and invoke it before receipt writing, worker re-exec, or child creation. Keep immutable constants and local pure helpers private or fileprivate where possible, and update tests to exercise an instance of the controller.

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown

@sanshengai I will review pull request #12289.

⚠️ Action not completed

Already reviewed the last commit. Use @coderabbitai full review to rerun a review of the entire changeset.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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.

1 participant