Repository navigation
Description
Problem Statement
crates/openshell-cli/src/run.rs has become the central implementation file for most CLI command execution, rendering helpers, parsing helpers, and inline tests. That makes unrelated CLI changes collide in the same file and makes review harder because command behavior, shared utilities, and tests are interleaved.
Current measurements from the feat/gateway-status-driver-info branch:
run.rsis 10,103 lines out of 21,091 total lines incrates/openshell-cli/src, about 48% of the CLI source.- The next largest CLI files are
main.rsat 4,942 lines andssh.rsat 2,356 lines. run.rscontains about 199 function definitions, including 60pub async fncommand-style entry points and 13pub fnentry points.- The inline test module starts around line 8,058 and contains about 2,046 lines with 95 test functions.
- In the last six months,
run.rswas touched by 88 commits, with roughly 12,827 insertions and 2,724 deletions. main.rswas touched by 71 commits in the same period, and 59 commits touched bothmain.rsandrun.rs, which suggests frequent parser/dispatch/execution coupling.
This matters because CLI work is a high-churn area. A single large execution file increases merge conflicts, makes small behavior changes look broad, and makes command-specific tests harder to find.
Proposed Design
Split CLI command execution incrementally by command group while preserving behavior.
Suggested target structure:
crates/openshell-cli/src/
main.rs # clap parser, global setup, dispatch
run.rs # temporary compatibility layer or shared entrypoint during migration
commands/
mod.rs
gateway.rs
sandbox.rs
provider.rs
service.rs
policy.rs
settings.rs
Start with the gateway command group because it is actively changing and has a natural boundary around gateway registration, selection, status, info, auth, and inference. Move gateway-specific tests with the gateway module. Keep shared utilities, output formatting, TLS/auth setup, and gRPC client construction in existing shared modules or extract them only when multiple command groups need them.
The refactor should be mechanical and behavior-preserving:
- Move command execution functions by command group.
- Move command-specific renderers and JSON helpers with their command group.
- Move tests close to the command implementation they cover.
- Avoid introducing a command trait or dynamic registry unless a later design requires plugin-style CLI commands.
- Keep public CLI behavior unchanged except for any already-planned command changes in separate commits.
Definition of done:
- Gateway command execution is moved out of
run.rs. - Gateway command tests move with the implementation.
- Shared helpers remain accessible without circular dependencies.
- No user-facing CLI behavior changes are introduced by the refactor.
- Focused CLI tests and
cargo fmt --checkpass.
Alternatives Considered
Keep run.rs as-is:
- Lowest immediate risk.
- Does not address the high churn and conflict surface.
Split into one file per individual command:
- Gives maximum isolation.
- Likely too granular at first; command groups are a better intermediate shape for OpenShell's current CLI size.
Introduce a command trait/registry:
- Useful for plugin-like dynamic commands.
- More abstraction than needed for a static clap CLI and would make a mechanical refactor harder to review.
Agent Investigation
- Reviewed
crates/openshell-cli/src/run.rs,main.rs, and surrounding CLI modules. - Counted CLI source lines and found
run.rsis about 48% ofcrates/openshell-cli/src. - Counted function/test density in
run.rs: about 199 function definitions and 95 test functions. - Reviewed six-month git churn for
run.rsandmain.rs; found 88 commits touchingrun.rs, 71 touchingmain.rs, and 59 touching both. - Searched open issues for
run.rs CLI refactor split commands; no duplicates were found.
Checklist
- I've reviewed existing issues and the architecture docs
- This is a design proposal, not a "please build this" request
Activity
varshaprasad96 commentedon Jul 17, 2026
varshaprasad96 commentedon Jul 17, 2026
@elezar I can take up this issue and work on refactoring PRs.
elezar commentedon Jul 17, 2026
@varshaprasad96 sure. Please ping me for review on the proposal as well as the PRs.
varshaprasad96 commentedon Jul 20, 2026
Since the change here is only a refactor, RFC seems to not be required according to contribution guideline. I'm using this comment as a meta issue to create self contained sequence of 6 PRs addressing the issue. Please feel free to comment/add your thoughts.
Proposed PR Sequence
After reviewing
run.rsin detail — function groupings, cross-group dependencies, and call sites frommain.rs— here's an incremental split plan. Each PR leaves the codebase compiling and tests passing.PR 1: Scaffolding + shared helpers
Create
commands/mod.rsandcommands/common.rs. Move intocommon.rs:phase_name,format_epoch_ms,format_elapsed,format_timestamp,print_yaml_line,print_sandbox_policy,short_hash,non_empty_or,format_timestamp_ms,format_optional_epoch_ms,truncate_status_field,truncate_displayparse_env_pairs,parse_key_value_pairs,parse_secret_material_env_pairs,parse_credential_*,parse_cli_setting_value,parse_duration_to_msPolicyGetView,SandboxUploadPlan,ProvisioningStep,ProvisioningDisplay,SandboxCreateConfig,ForwardTcpConnectionErrorconfirm_global_setting_takeover,confirm_global_setting_deleterun.rsre-exports everything fromcommands::commonso all existing callers (includingmain.rs) keep working unchanged. This is the foundation — every later PR depends on it.PR 2: Gateway commands
Move all gateway functions (~25 functions, lines 553–1726) and their tests (~20 tests) into
commands/gateway.rs. This is the cleanest group to extract — almost no inbound dependencies from other command groups, only uses shared helpers already incommon.rs.run.rsre-exportscommands::gateway::*.PR 3: Provider commands
Move provider commands (~20 public functions), the auto-detection helpers (
inferred_provider_type,ensure_required_providers,auto_create_provider), and provider-specific tests intocommands/provider.rs. The auto-detection helpers live here because they're provider-domain logic —sandbox_createwill import fromcommands::providerwhen it moves later.PR 4: Service + Settings + Inference
Three small groups bundled into one PR:
commands/service.rs(includesservice_forward_tcpand its TCP forwarding helpers)commands/settings.rscommands/inference.rsfetch_ready_sandbox_for_forwardmoves tocommon.rssince it bridges service and sandbox.PR 5: Policy + Logs + Draft
commands/policy.rscommands/logs.rscommands/draft.rsprint_sandbox_policyis already incommon.rsfrom PR 1, so the cross-ref betweensandbox_getandsandbox_policy_updateis clean.PR 6: Sandbox + cleanup
Move sandbox commands (~15 functions) and sandbox_provider sub-commands into
commands/sandbox.rs. This is the most tangled group — doing it last means all its dependencies (provider auto-detection, policy display, settings parsing) are already in their final homes. Remove or shrink therun.rsre-export shim. Move git/upload helpers intocommon.rsorcommands/upload.rs.Why this order
sandbox_create→ provider auto-detection (ensure_required_providers,inferred_provider_type). PR 3 exports those publicly fromcommands/provider.rs; PR 6 imports them when sandbox moves.Target structure
refactor(cli): extract shared helpers into commands/common module
refactor(cli): extract shared helpers into commands/common module (NV…
refactor(cli): extract gateway commands into commands/gateway module (N…
refactor(cli): extract provider commands into commands/provider module
github-actions commentedon Aug 28, 2026
This issue has had no activity for 14 days and is now marked stale. It may be closed in 7 days if there is no further activity. Comment or remove the state:stale label to keep it open.
refactor(cli): extract provider commands into commands/provider module
refactor(cli): extract provider commands into commands/provider module (
varshaprasad96 commentedon Sep 4, 2026
Implementation Plan
Issue type:
refactorComplexity: Medium
Confidence: High — boundaries and call sites are clear
Summary
Extract the next three command groups from
run.rsinto dedicated service, settings, and inference modules without changing CLI behavior or dispatch. Preserve the existingrun::*compatibility surface somain.rsremains unchanged.Scope
commands/service.rs: Move service forwarding, CRUD/exposure commands, TCP relay/session helpers, renderers, JSON conversion, and service tests.commands/settings.rs: Move the six gateway/sandbox settings commands and JSON renderers.commands/inference.rs: Move the four inference route commands and their display/error helpers.commands/common.rs: Keep shared setting parsing/confirmation helpers here and relocate their remaining tests fromrun.rs.commands/mod.rs: Register the three modules.run.rs: Re-export moved entry points and remove moved implementations/tests/imports.main.rs: No changes; existingrun::*calls continue compiling.fetch_ready_sandbox_for_forwardis only used by service forwarding, so it remains private inservice.rs.Implementation Steps
upstream/main.common.rs.run.rsre-exports, prune imports, and move/add focused tests.Test Plan
cargo test -p openshell-cli; existing parser/dispatch and RPC integration tests cover compatibility.mise run pre-commit,mise run test, andmise run ci.Risks & Open Questions
run.rs.Documentation Impact
None expected; commands, flags, output, RPCs, and workflows remain unchanged.
Gateway Configuration Impact
None.
LSM Compatibility
No impact.
Revision 1 — initial plan for PR 4
github-actions commentedon Sep 18, 2026
This issue has had no activity for 14 days and is now marked stale. It may be closed in 7 days if there is no further activity. Comment or remove the state:stale label to keep it open.
github-actions commentedon Oct 13, 2026
Closing this issue after 14 days with no activity since it was marked stale. Reopen it if the work is still relevant.