Summary
cli.py is 3,944 lines with 67 helpers and 17 command handlers. core.py is 1,370 lines with 8 distinct subsystems. Both have clear internal boundaries that map to natural module splits. No circular dependencies between them — safe to refactor independently.
CLI.py Analysis (3,944 lines)
Current Structure
- 17 subcommands in a single
run_cli() dispatcher
- 67 helper functions mixed across concerns
- Inline template strings (YAML examples, HTML templates) account for ~800 lines
Proposed Module Boundaries
| Module |
Approx Lines |
Commands |
Key Functions |
cli/init.py |
~1,400 |
init, quickstart, onboard |
_init_project(), _scaffold_*(), _run_quickstart(), _run_onboard_flow() |
cli/config.py |
~200 |
config |
_run_setup_flow(), provider wizard, .env management |
cli/run.py |
~400 |
run |
Executor creation, workflow resolution, input parsing |
cli/inspect.py |
~500 |
inspect, state-diff, resume, replay |
Step display, state diff, redaction |
cli/viz.py |
~300 |
visualize, runs, metrics |
RunLoader integration, HTML rendering |
cli/test.py |
~600 |
test |
_run_project_tests(), tool/function spec tests |
cli/helpers.py |
~400 |
— |
_redact(), _load_dotenv(), _prompt_*(), tarball utils, cost estimation |
cli/__init__.py |
~100 |
— |
run_cli() dispatcher, argparse setup |
Inline Templates to Extract
RUNTIME_YAML_TEMPLATE — runtime.yaml scaffold
EXAMPLE_WORKFLOW / EXAMPLE_FUNCTION — starter stubs
- Various HTML templates for dashboard/visualization
- Could become
cli/templates/ directory or constants module
Core.py Analysis (1,370 lines)
Current Structure
Executor class (~800 lines) with 8 distinct responsibilities
- 4 dataclasses:
RunState, Run, StepExecution, StepDefinition
- Helper methods for retry, branching, timeout, heartbeat
Extractable Concerns
| Module |
Lines |
Functions |
dispatch.py |
~150 |
_dispatch_agent(), _dispatch_function(), _dispatch_tool(), _execute_tool_async() |
retry.py |
~50 |
_compute_backoff_delay(), retry loop logic |
branching.py |
~50 |
_resolve_next_step(), NextRule evaluation |
validation.py |
~60 |
_validate_output_schema(), output contract checks (currently duplicates tools/validation.py) |
models.py |
~130 |
RunState, Run, StepExecution, StepDefinition, StepStatus, RetryPolicy |
What Stays in core.py
Executor.__init__() — wiring all subsystems
run() / run_async() — public entry points
__execute_steps_loop() — main orchestration loop
_emit() — event callbacks
_run_with_timeout_and_heartbeat() — async wrapper
Coupling Analysis
cli.py → core.py imports
from .core import Executor, Run, RunState, StepDefinition, StepStatus
Only public-facing types. No internal methods accessed.
core.py → other modules
core.py → config, storage, memory, agent, tools, state, observability, errors, utils
All one-directional. No circular dependencies detected.
Breakage Risk: LOW
- If
core.py is split, CLI only needs updated imports
- If
cli.py is split, nothing depends on CLI internally
- Test files import from
core directly — would need import updates
Existing Duplication
Output contract validation in core.py:1317-1370 duplicates type-checking from tools/validation.py:16-46:
- Both check
type (str/int/float/bool/list/dict)
core.py adds enum and regex
tools/validation.py has required field checking
- Could be unified into a single
validation.py module
Priority
P1 — Maintainability. Neither module is blocking features, but the monolith size slows navigation and increases merge conflict risk. CLI split is higher priority (3,944 lines vs 1,370). ~3 days effort.
🤖 Generated with Claude Code
Summary
cli.pyis 3,944 lines with 67 helpers and 17 command handlers.core.pyis 1,370 lines with 8 distinct subsystems. Both have clear internal boundaries that map to natural module splits. No circular dependencies between them — safe to refactor independently.CLI.py Analysis (3,944 lines)
Current Structure
run_cli()dispatcherProposed Module Boundaries
cli/init.pyinit,quickstart,onboard_init_project(),_scaffold_*(),_run_quickstart(),_run_onboard_flow()cli/config.pyconfig_run_setup_flow(), provider wizard,.envmanagementcli/run.pyruncli/inspect.pyinspect,state-diff,resume,replaycli/viz.pyvisualize,runs,metricscli/test.pytest_run_project_tests(), tool/function spec testscli/helpers.py_redact(),_load_dotenv(),_prompt_*(), tarball utils, cost estimationcli/__init__.pyrun_cli()dispatcher, argparse setupInline Templates to Extract
RUNTIME_YAML_TEMPLATE— runtime.yaml scaffoldEXAMPLE_WORKFLOW/EXAMPLE_FUNCTION— starter stubscli/templates/directory or constants moduleCore.py Analysis (1,370 lines)
Current Structure
Executorclass (~800 lines) with 8 distinct responsibilitiesRunState,Run,StepExecution,StepDefinitionExtractable Concerns
dispatch.py_dispatch_agent(),_dispatch_function(),_dispatch_tool(),_execute_tool_async()retry.py_compute_backoff_delay(), retry loop logicbranching.py_resolve_next_step(), NextRule evaluationvalidation.py_validate_output_schema(), output contract checks (currently duplicatestools/validation.py)models.pyRunState,Run,StepExecution,StepDefinition,StepStatus,RetryPolicyWhat Stays in core.py
Executor.__init__()— wiring all subsystemsrun()/run_async()— public entry points__execute_steps_loop()— main orchestration loop_emit()— event callbacks_run_with_timeout_and_heartbeat()— async wrapperCoupling Analysis
cli.py → core.py imports
Only public-facing types. No internal methods accessed.
core.py → other modules
All one-directional. No circular dependencies detected.
Breakage Risk: LOW
core.pyis split, CLI only needs updated importscli.pyis split, nothing depends on CLI internallycoredirectly — would need import updatesExisting Duplication
Output contract validation in
core.py:1317-1370duplicates type-checking fromtools/validation.py:16-46:type(str/int/float/bool/list/dict)core.pyaddsenumandregextools/validation.pyhasrequiredfield checkingvalidation.pymodulePriority
P1 — Maintainability. Neither module is blocking features, but the monolith size slows navigation and increases merge conflict risk. CLI split is higher priority (3,944 lines vs 1,370). ~3 days effort.
🤖 Generated with Claude Code