Skip to content

Codify modular-refactor rules into CLAUDE.md - #5111

Merged
azooz2003-bit merged 3 commits into
mainfrom
feat-claudemd-refactor-rules
Jun 1, 2026
Merged

azooz2003-bit merged 3 commits into
mainfrom
feat-claudemd-refactor-rules

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Jun 1, 2026 •

Copy link
Copy Markdown
Collaborator

Docs-only. Codifies the rules and architecture patterns we enforced across the wave 1-2 package extractions (CmuxFoundation, CmuxSocketControl, CmuxProcess) into the binding cmux CLAUDE.md, so future refactor work follows them without rediscovery or having to read the cmuxterm-hq blueprint.

Granular rules (placed in their existing sections):

  • Testability — test through an injected protocol seam, never a nonisolated(unsafe) static var fooForTesting global hook; deleting such a hook is part of extracting the type.
  • Modern Swift concurrency — when extracting code that uses a forbidden primitive, redesign it at the seam: an NSLock single-resume race (process termination vs. timeout vs. spawn failure) becomes a tiny actor guard around withCheckedContinuation; drain Process pipes on detached tasks keyed by raw fd.
  • Concurrency exceptions — one-shot DispatchSource.makeTimerSource is acceptable (with justification) for a genuine deadline/timeout; for true deadlines only.
  • Testing policy — reload.sh builds only the cmux scheme, so a green reload does not prove cmuxTests compiles; build cmux-unit or rely on the tests job. (Real misses: a write(to:atomically:) typo and a removed TabManager.CommandResult that only surfaced in the tests job.)
  • Package architecture — how to wire a new local package into project.pbxproj, linking into both the cmux and cmux-unit targets.

Architecture patterns (new "Refactor architecture" section) — these previously lived only in the cmuxterm-hq blueprint (docs/cmux-refactor-audit/blueprint/CONVENTIONS.md), so a reader of cmux's CLAUDE.md alone had the granular rules but not the architecture they serve:

  • The five-layer, downward-only package DAG (Core / Services / Domain / UI / Executable).
  • Classify extracted entities by intent: Coordinator (@MainActor @Observable orchestrator), Service (actor capability), Repository (actor persistence).
  • Dependency inversion: lower packages publish protocols, higher depend on any Protocol; constructor injection only; the executable app target is the single composition root.
  • State + SwiftUI wiring (@Observable sub-models; @State/@Bindable/@Environment, never @StateObject/@ObservedObject/@EnvironmentObject).
  • The executable-target boundary (three hard constraints: @main+AppDelegate stay; extensions invert into Coordinators/Services and forward; stored state decomposes into sub-models).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation
    • Expanded developer guidance for Swift package integration, stricter layered refactor architecture and dependency-inversion rules, and clearer SwiftUI/state wiring.
    • Strengthened testability guidance to replace global mutable test hooks with injected seams.
    • Updated concurrency extraction guidance with explicit allowed carve-outs and timer usage expectations.
    • Clarified build/script behavior about which targets are compiled.

Note: This release contains no user-facing changes.

Captures the patterns we enforced while extracting CmuxFoundation,
CmuxSocketControl, and CmuxProcess so future package/refactor work follows them
without rediscovery:

- Testability: test through an injected protocol seam, never a
  `nonisolated(unsafe) static var fooForTesting` global hook; deleting such a
  hook (and the lock it needed) is part of extracting the type.
- Concurrency: when extracting code that uses a forbidden primitive, redesign it
  at the seam rather than carrying it across — e.g. an `NSLock` single-resume
  race becomes a tiny `actor` guard around `withCheckedContinuation`, with
  `Process` pipes drained on detached tasks keyed by raw fd.
- Concurrency exceptions: one-shot `DispatchSource.makeTimerSource` is acceptable
  (with justification) for a genuine deadline/timeout, since async-native timers
  are disallowed here; never to poll or fake a sleep.
- Testing: `reload.sh` builds only the `cmux` scheme, not the test target, so a
  green reload does not prove `cmuxTests` compiles; build `cmux-unit` or rely on
  the `tests` CI job before pushing package/refactor changes.
- Package architecture: how to wire a new local package into project.pbxproj,
  linking into both the `cmux` and `cmux-unit` targets.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 1, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jun 1, 2026 4:32pm
cmux-staging Building Building Preview, Comment Jun 1, 2026 4:32pm

@coderabbitai

coderabbitai Bot commented Jun 1, 2026 •

Copy link
Copy Markdown

Review 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: Pro

Run ID: e032cb40-954d-4e31-86e6-2e214cd3bb0a

📥 Commits

Reviewing files that changed from the base of the PR and between 1a90c4c and 07d34fe.

📒 Files selected for processing (1)
  • CLAUDE.md

📝 Walkthrough

Walkthrough

Updated CLAUDE.md with package wiring steps for cmux.xcodeproj, mandatory removal of global/static test hooks in favor of initializer-injected protocol seams, revised concurrency guidance including a narrow synchronous lock carve-out and allowed one-shot timers with justification, and clarified that reload.sh does not build test targets so cmux-unit must be built to verify tests.

Changes

Developer Guidance Clarifications

Layer / File(s) Summary
Package integration and wiring
CLAUDE.md
New section documenting how to wire local Swift packages into cmux.xcodeproj, including mirroring project.pbxproj package reference/product entries and linking package products into both cmux and cmux-unit targets.
Testability: remove globals, use seams
CLAUDE.md
Requires deleting static/global mutable “for testing” hooks when extracting code into packages and replacing them with protocol-based seams injected via initializers.
Concurrency guidance and allowed carve-outs
CLAUDE.md
Reworked forbidden-primitives guidance: clarifies actor misuse, mandates actor/AsyncStream surfaces for new runtime synchronization, documents a narrow synchronous lock carve-out for one-shot continuation resume-guard compare-and-set patterns, and allows DispatchSource.makeTimerSource only for genuine one-shot deadlines with cancellation on non-timeout paths. Code-review checklist now rejects certain primitives in new code unless a one-line justification for an allowed carve-out is provided.
Local build/test workflow
CLAUDE.md
Clarified that reload.sh builds only the cmux scheme and does not compile test targets; developers must build the cmux-unit scheme (or rely on CI) to verify tests compile after refactors.

Estimated Code Review Effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • manaflow-ai/cmux#4919: Overlapping CLAUDE.md guidance additions for Swift package/refactor conventions.
  • manaflow-ai/cmux#4836: Related pbxproj normalization and objectVersion guidance for wiring packages into the Xcode project.
  • manaflow-ai/cmux#4562: Related CLAUDE.md updates and CI lint for wiring test files into cmux.xcodeproj/project.pbxproj.

Poem

I’m a rabbit in the docs tonight,
Tiding packages, making hooks take flight,
Threads and timers neatly penned,
Tests wired up from end to end,
A hop, a patch — now build and bright! 🐇✨


Caution

Pre-merge checks failed

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

  • Ignore

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Cmux Swiftui State Layout ❌ Error Commit introduces 216 @Published, 49 ObservableObject, 19 @StateObject, and 58 @ObservedObject patterns—new SwiftUI code violating the review rule against legacy state where @Observable is modern. Refactor to use @Observable models, @State/@Bindable/@Environment in views, avoiding @StateObject/@ObservedObject/@EnvironmentObject as documented in CLAUDE.md guidance being added.
Description check ⚠️ Warning The description is comprehensive and covers the key changes, but is missing explicit sections for Testing, Demo Video, Review Trigger, and Checklist from the required template. Add the missing template sections: Testing (how was this tested), Demo Video (if applicable), Review Trigger block for bot reviews, and complete the Checklist items (especially noting that this is docs-only and indicating whether tests/bots were requested).
✅ Passed checks (16 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: codifying modular-refactor rules into CLAUDE.md, which matches the documentation update summarized in the raw_summary.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 PR contains only documentation (CLAUDE.md) and project configuration changes; no production Swift code modifications to evaluate against actor isolation rules.
Cmux Swift Blocking Runtime ✅ Passed Initial repository import codifying existing blocking primitives in CLAUDE.md with explicit carve-outs, not introducing new blocking synchronization patterns.
Cmux No Hacky Sleeps ✅ Passed All setTimeout usages are legitimate timeout abstractions with cancellation-aware cleanup. Shell sleeps are in test files or build scripts. All conform to rule exceptions.
Cmux Algorithmic Complexity ✅ Passed PR contains only documentation (CLAUDE.md), metadata (version bumps), and static data changes (changelog cleanup). No production algorithmic code introduced.
Cmux Swift Concurrency ✅ Passed PR modifies only documentation (CLAUDE.md), changelog files, and version metadata; zero Swift code changes. The check evaluates actual code patterns, not guidance documentation.
Cmux Swift @Concurrent ✅ Passed Two @concurrent annotations correctly added to nonisolated async functions with proper isolation, no actor combination, no synchronous decoration, compiler-gated for Swift 6.2+.
Cmux Swift File And Package Boundaries ✅ Passed PR imports existing codebase with no new boundary violations. CLAUDE.md change is documentation-only; large Swift files imported as-is per allowance.
Cmux Swift Logging ✅ Passed PR is docs-only (CLAUDE.md guidance); no production Swift code added/changed; logging rule only applies to production changes and explicitly allows documentation.
Cmux User-Facing Error Privacy ✅ Passed PR updates only CLAUDE.md (developer docs), not production code with user-facing errors. Docs are explicitly allowed per user-facing-errors.md rules.
Cmux Full Internationalization ✅ Passed CLAUDE.md is developer-only documentation, explicitly exempted by the i18n rule as "operational docs not shown to end users." No user-facing UI text or localization needed.
Cmux Architecture Rethink ✅ Passed CLAUDE.md forbids locks/sleeps/observers but documents carve-outs for platform callbacks, aligning with swift-architectural-rethink.md's allowance for required platform code with documented reasons.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed Swift windows have cmux.* identifiers registered in cmuxAuxiliaryWindowIdentifiers, and debug windows are #if DEBUG-only fixtures, complying with auxiliary window close shortcut rules.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-claudemd-refactor-rules

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 and usage tips.

@greptile-apps

greptile-apps Bot commented Jun 1, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This docs-only PR codifies the architectural patterns and enforcement rules discovered during the wave 1–2 package extractions (CmuxFoundation, CmuxSocketControl, CmuxProcess) directly into CLAUDE.md, so future refactor work has a single authoritative reference without consulting the cmuxterm-hq blueprint.

  • Architecture section added: five-layer downward-only package DAG, Coordinator/Service/Repository classification, dependency-inversion rules, SwiftUI state wiring, and the three hard executable-target constraints.
  • Concurrency section refined: distinguishes between "promote to actor" (the default) and the narrow lock carve-out for synchronous single-resume guards; explicitly bans single-method actors used only as mutexes; adds DispatchSource.makeTimerSource (one-shot) to the exceptions list for genuine deadlines.
  • Testability and build guidance strengthened: bans nonisolated(unsafe) static var fooForTesting hooks in favour of injected protocol seams; clarifies that reload.sh builds only the cmux scheme and does not prove cmuxTests compile.

Confidence Score: 5/5

Docs-only change with no production code modified; safe to merge.

The entire diff is prose additions to CLAUDE.md. The new guidance is internally consistent, refines rather than contradicts existing rules, and the one known gap (GlobalISel xcodebuild flag) was already flagged in a prior review thread.

No files require special attention.

Important Files Changed

Filename Overview
CLAUDE.md Docs-only additions: new "Refactor architecture" section, package-wiring guidance, concurrency carve-outs, testability rule for static hooks, and reload.sh build-scope clarification. No code changes; guidance is internally consistent with the existing rules.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["5. Executable\n(cmuxApp / AppDelegate)\nComposition root — no business logic"] --> B
    B["4. UI\nSwiftUI/AppKit views\n(e.g. CmuxSettingsUI)"] --> C
    C["3. Domain / State\n@MainActor @Observable Coordinators\n(e.g. CmuxSettings)"] --> D
    D["2. Services / Infrastructure\nactor-based capabilities\n(e.g. CmuxSocketControl, CmuxProcess)"] --> E
    E["1. Core\nSendable values, IDs, DTOs,\nprotocol seams (e.g. CmuxCore)"]
Loading

Reviews (3): Last reviewed commit: "Correct the lock guidance: don't make an..." | Re-trigger Greptile

Comment thread CLAUDE.md

- **E2E / UI tests:** trigger via `gh workflow run test-e2e.yml` (see cmuxterm-hq CLAUDE.md for details)
- **Unit tests:** `xcodebuild -scheme cmux-unit` is safe (no app launch), but prefer CI
- **`reload.sh` does not compile the test target.** It builds only the `cmux` scheme, so a green `reload.sh` says nothing about whether `cmuxTests`/`cmuxUITests` still compile. A symbol that is moved or renamed can keep the `cmux` app building while breaking the test target (real case: a `write(to:atomically:)` typo and a removed `TabManager.CommandResult` only surfaced in the `tests` job). Before pushing package/refactor changes, build the `cmux-unit` scheme (with `-derivedDataPath /tmp/cmux-<tag>` and, for `cmuxApp`/`AppDelegate` churn, the GlobalISel workaround flag) or let the `tests` CI job gate it — never treat `reload.sh` alone as proof the tests build.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 GlobalISel workaround flag left undefined for xcodebuild

The bullet references "the GlobalISel workaround flag" when building the cmux-unit scheme directly, but that flag is only surfaced as --swift-frontend-workaround / --swift-disable-global-isel on reload.sh (which builds cmux, not cmux-unit). A developer or agent following this guidance literally won't know the equivalent xcodebuild argument: OTHER_SWIFT_FLAGS='$(inherited) -Xllvm -aarch64-enable-global-isel-at-O=-1'. Spelling it out — or cross-referencing reload.sh --swift-frontend-workaround and noting the xcodebuild translation — would make the bullet self-contained.

…itory, dependency inversion) to CLAUDE.md

These higher-level patterns lived only in the cmuxterm-hq blueprint
(blueprint/CONVENTIONS.md), so anyone reading the cmux repo CLAUDE.md alone had
the granular rules (no locks, inject, DocC) but not the architecture they serve.
Distills the enforceable core:

- Five-layer downward-only package DAG (Core / Services / Domain / UI / Executable).
- Classify extracted entities by intent: Coordinator (@mainactor @observable
  orchestrator), Service (actor capability), Repository (actor persistence).
- Dependency inversion: lower packages publish protocols, higher depend on
  `any Protocol`; constructor injection only; the executable app target is the
  single composition root.
- State + SwiftUI wiring: @observable sub-models; @State/@Bindable/@Environment,
  never @StateObject/@ObservedObject/@EnvironmentObject.
- Executable-target boundary: @main + AppDelegate stay; extensions invert into
  Coordinators/Services and forward; stored state decomposes into sub-models.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 1 file

Re-trigger cubic

Per maintainer feedback: a single-method `actor` whose only job is to guard a
flag is an antipattern, not a fix. It forces synchronous callers (Process
termination handlers, DispatchSource handlers, a withCheckedContinuation resume
race) through `Task { await guard.claim() }`, adding suspension points and
reentrancy to a synchronous compare-and-set.

- Add a narrow lock carve-out: a lock is allowed for a synchronous
  compare-and-set called from non-async callbacks (canonical case: a one-shot
  resume guard via `OSAllocatedUnfairLock`), where promoting to an actor would
  only add Task/await hops. For tiny flags/counters, not ongoing domain state.
- Replace the earlier "extract NSLock into an actor guard" recommendation, which
  recommended exactly this antipattern.
- Align the forbidden-locks bullet and the review checklist with the carve-out,
  and have reviewers reject a single-method mutex-actor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview – cmux — 07d34fe6 Deployed Jun 1, 2026 by vercel[bot]
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