refactor(workspace): P3+P4 extract level-1 and level-2 crates - #82
Merged
Crsei merged 1 commit intoApr 21, 2026
Merged
Conversation
Ten new workspace crates land in a single commit; each builds + tests
green at the boundary and the root crate keeps every `crate::{config,
utils, mcp, services, computer_use, compact, sandbox, permissions,
browser, session}::…` path working via `use cc_X as X;` aliases or
facade `mod.rs` files that re-export the crate. Matches the existing
P1 / P2 split pattern and the plan in docs/superpowers/specs/
2026-04-20-workspace-split-design.md.
Phase 3 (issue Crsei#72) — five level-1 crates
-----------------------------------------
cc-config — 3,139 LOC (full extraction, one tie broken)
`src/config/{claude_md,constants,features,paths,settings,validation}.rs`
→ `crates/cc-config/src/…`. `SettingsJson` moved from
`types::app_state` into `cc-config::runtime_settings` so validation
reads it without a reverse dep, and the two engine constants the
validator consulted (`output_style::BUILT_IN_NAMES`,
`effort::effort_to_budget_tokens`) are inlined as a small rule table
— the authoritative engine values still drive runtime behaviour.
cc-utils — 2,883 LOC (full, clean leaf on cc-types + cc-config)
`src/utils/{abort,bash,cwd,file_state_cache,git,messages,shell,
tokens}.rs` → `crates/cc-utils/src/…`. A tiny `build.rs` emits
`-l dylib=advapi32` on Windows so the test binary picks up the
libgit2-sys CryptoAPI imports that rust-lld otherwise leaves
unresolved.
cc-mcp — ~1,856 LOC (partial)
Moved: `mod,channel,client,client_tests,discovery,manager,
transport.rs`. Not moved: `tools.rs` (implements the root-crate
`Tool` trait — unblocks in P5). The IPC-event cycle is broken the
same way cc-skills broke its: cc-mcp owns a minimal
`McpSubsystemEvent` enum and a `set_event_callback` hook the host
wires to adapt into `SubsystemEvent`. Plugin-contributed server
discovery now runs through `set_plugin_hook` for the same reason.
cc-services — partial (4 of 6 modules)
Moved: `lsp_lifecycle,prompt_suggestion,session_memory,
tool_use_summary.rs`. Not moved: `session_analytics` (deps on
`session::storage` — unblocked by this same commit's cc-session),
`langfuse/` (deps on `types::tool::Tools` — unblocks in P5).
cc-computer-use — partial (input + screenshot)
Platform backends (`input/*.rs`, `screenshot/*.rs`) moved; the Tool
wrappers (`detection,setup,tools.rs`) stay in root until P5.
Phase 4 (issue Crsei#73) — five level-2 crates
-----------------------------------------
cc-compact — full, clean DAG addition
`src/compact/{auto_compact,compaction,messages,microcompact,
pipeline,snip,tool_result_budget}.rs` → `crates/cc-compact/src/…`.
Deps: cc-types + cc-utils only.
cc-sandbox — full
`src/sandbox/{availability,errors,filesystem,mode,network,policy,
runner}.rs` → `crates/cc-sandbox/src/…`. `policy_from_app_state`
signature tightened to take `&ToolPermissionContext +
&SandboxSettings` instead of the whole `AppState`, so cc-sandbox
doesn't need the root crate's app-state type (still tied to teams /
ui / keybindings). Four callers updated to pass the two fields.
cc-permissions — full, two callbacks registered
`src/permissions/{bash_matcher,dangerous,decision,path_validation,
rules}.rs` → `crates/cc-permissions/src/…`. The CU /
browser permission-prompt lookups that previously called into
`computer_use::detection` and `browser::{detection,permissions}`
now go through `set_cu_message_callback` / `set_browser_message_callback`;
main.rs registers adapters from the root-crate implementations.
`PermissionMode`, `ToolPermissionContext`,
`AdditionalWorkingDirectory`, and `ToolPermissionRulesBySource`
moved into `cc-types::permissions` so both cc-sandbox and
cc-permissions can consult them without reaching back into
`types::tool` (where `ToolUseContext` still drags in an ipc cycle).
cc-browser — partial (9 of 11 modules)
Moved: `common,mcp_bridge,native_host,permissions,session,setup,
state,tool_rendering,transport.rs`. Also moved the pure-string and
server-registry helpers out of `detection.rs` into
`cc-browser::detection`. The `Arc<dyn Tool>` registry walker
(`detect_browser_servers` / `detect_browser_tools`) and the
prompt-section builder stay in root until P5.
cc-session — 3,828 LOC (full)
`src/session/{audit_export,export,memdir,migrations,resume,storage,
transcript}.rs` + `session_export/{builders,compression,mod,
tests}.rs` → `crates/cc-session/src/…`. Session files still land in
`~/.cc-rust/memory/` (per Crsei#73's acceptance criterion — unchanged).
Same advapi32 build shim as cc-utils for the libgit2-sys test link.
Post-split invariants
---------------------
- `cargo build --workspace --release` succeeds; only the two
pre-existing `session_id is never read` warnings in
`web/handlers.rs` remain (both fields are #[serde(default)] API
contract fields — not introduced by this split).
- Every extracted crate's unit tests pass: cc-config 55, cc-utils 101,
cc-mcp 26, cc-services 41, cc-compact n/a (no unit tests, covered
via integration), cc-sandbox 55, cc-permissions 87 + 1 doctest,
cc-browser n/a, cc-session 55.
- Root crate: 1234 tests pass `--test-threads=1`. The handful of
parallel failures are pre-existing shared-state flakes (same set
as on rust-lite HEAD before this commit).
- Feature-gate lookup (`cc_config::features::enabled(…)`) still
routes through the same `FEATURE_*` env-var reads.
- No new runtime deps — only cross-crate path deps added under
`[workspace.dependencies]`.
Refs Crsei#72. Refs Crsei#73. Part of Crsei#68.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Resolves #72 (Phase 3) and #73 (Phase 4) from the workspace-split epic #68. Extracts ten new crates on top of the existing cc-types / cc-observability / cc-keybindings / cc-auth / cc-bootstrap / cc-skills split, following the plan in
docs/superpowers/specs/2026-04-20-workspace-split-design.md.Phase 3 (#72) — level-1 crates
cc-configSettingsJsonmoved here fromtypes::app_state; validation inlines 2 engine rules instead of reaching backcc-utilscc-types+cc-config; tinybuild.rslinksadvapi32so libgit2-sys test binaries resolve CryptoAPIcc-mcptools.rs(Tool trait adapter) stays in root. IPC-event cycle broken via callback hook — same pattern cc-skills usedcc-servicessession_analytics(needssession::storage) andlangfuse(needstypes::tool::Tools) stay pending P5cc-computer-useinput/*,screenshot/*); Tool wrappers stay until P5Phase 4 (#73) — level-2 crates
cc-compactcc-sandboxpolicy_from_app_statesignature tightened:&ToolPermissionContext + &SandboxSettingsinstead of&AppStatecc-permissionscc_types::permissions; CU + browser prompt lookups via registered callbackscc-browserdetection.rssplit so pure helpers move;Arc<dyn Tool>walkers staycc-session~/.cc-rust/memory/path preserved per #73's acceptanceCycle-break tricks used
cc-skills::set_event_callbackpattern from P2): cc-mcp subsystem events, cc-mcp plugin discovery, cc-permissions CU / browser prompt lookups.PermissionMode/ToolPermissionContext/AdditionalWorkingDirectory/ToolPermissionRulesBySourcemoved intocc_types::permissions. The re-export intypes/tool.rskeeps existingcrate::types::tool::…call sites compiling unchanged.policy_from_app_statetakes the two fields it actually reads, so cc-sandbox does not depend onAppState(which still drags teams / ui / keybindings in).Why
Per the epic, per-crate granular rebuild cuts incremental build time dramatically — editing one tool file will rebuild one ~3kLOC leaf crate + the root bin instead of re-codegenning the entire ~92kLOC
claude-code-rs. This PR unblocks Phase 5 cycle-break work by removing the subsystems that do not participate in the hub cycles from the root crate.Acceptance checks
cc-config,cc-utils,cc-mcp,cc-services,cc-computer-usecc-compact,cc-sandbox,cc-permissions,cc-browser,cc-sessioncc_config::features::enabled(…)call sites route through the sameFEATURE_*env-var reads.~/.cc-rust/memory/).[workspace.dependencies].cargo build --workspace --releaseclean. Only the two pre-existingweb/handlers.rssession_idwarnings remain.--test-threads=1.Test plan
cargo build --workspace --releasecargo test --workspace -- --test-threads=1/permissions showrenders CU and browser prompts correctly (callback paths).~/.cc-rust/memory/.Not in this PR
types::tool::ToolUseContext+types::app_state::AppState— blocked on P5.🤖 Generated with Claude Code