Phase 05: CLI & Developer Tools
Objective: Build a comprehensive CLI tool (m) to replace Frappe's "bench", with commands for development, deployment, and management.
1. CLI Framework Setup
-
Create
src/framework_m/cli/main.py -
Use
cycloptsfor CLI framework (native async, better type support) -
Setup main CLI app:
app = cyclopts.App(name="m", help="Framework M CLI") -
Add version command:
m --version -
Add help documentation for all commands
1.1 Pluggable CLI Architecture (Entry Points)
- Define Entry Point Group:
framework_m.cli_commands - Implement Plugin Loader in
plugin_loader.py:- Use
importlib.metadata.entry_points(group="framework_m.cli_commands") - Iterate over registered entry points
- If entry point is a
cyclopts.App:app.command(plugin_app, name=ep.name) - If entry point is a function:
app.command(plugin_func, name=ep.name)
- Use
- Goal: 3rd party apps (and
framework-m-studio) can add commands tomwithout modifying core. - Customization Philosophy:
- Standard commands (
start,test) are strict relays. - For customization (e.g.,
start-mqtt,super-test): Users MUST register a custom command via entry points. - Result:
mremains a clean, standard runner.
- Standard commands (
2. Development Server (Uvicorn Relay)
2.1 Start Command
- Implement
m start:- Implementation: Wrapper around
uvicorn. - Argument Forwarding: Uses cyclopts Parameter for options.
- Usage:
m start --workers 4 --log-level debug - Value Add: Sets
PYTHONPATH, auto-detects app, transparently passes args.
- Implementation: Wrapper around
2.2 Worker Command (Taskiq Relay)
- Implement
m worker:- Implementation: Native Taskiq integration (better than wrapper).
- Options:
--concurrency,--verbose. - Usage:
m worker --concurrency 8
2.3 Studio Command (Litestar Relay)
- Implement
m studio:- Implementation: Wrapper around
uvicornfor Studio app. - Options:
--host,--port,--reload,--log-level. - Usage:
m studio --port 9000 --reload
- Implementation: Wrapper around
3. Database Commands (Alembic Relay)
3.1 Migration Commands
- Implement
m migrate:- Implementation: Wrapper around MigrationManager (uses Alembic).
- Commands:
migrate,create,rollback,status,history,init. - Usage:
m migrate create "add users" --autogenerate - Value Add: Auto-detects schema changes, supports custom DB URL, env vars.
4. Scaffolding (Cruft/Cookiecutter Relay)
4.1 New App (Starter Template)
- Implement
m new:app:- Implementation: Wrapper around
cruft(cookiecutter). - Options:
--template,--checkout,--no-input. - Usage:
m new:app myapp --checkout main
- Implementation: Wrapper around
4.2 New DocType (Jinja Relay)
- Implement
m new:doctype <name>:- Implementation: Template rendering (embedded templates).
- Output:
doctype.py,controller.py,test_*.py,__init__.py. - App Detection:
--app> pyproject.toml > interactive prompt.
App Detection Strategy
-
CLI Parameter (Unattended/Automation):
-
--app <app_name>: Explicit app target. - If
--appprovided, use it directly (no prompt). - Automation Friendly: Scripts can pass
--appto avoid prompts.
-
-
Auto-Detection from CWD:
- If
--appnot provided, attempt to detect from current directory. - Check if CWD is inside an app's source tree.
- Look for
pyproject.tomlin CWD or parent directories. - Read
[project] nameto determine app.
- If
-
Interactive Prompt (Default Fallback):
- If detection fails AND stdin is interactive (TTY):
- List installed apps from
framework_m.appsentry points. - Prompt user to select:
"Which app? [my_app, other_app]".
- List installed apps from
- If stdin is NOT interactive (pipe/automation):
- Fail with clear error:
"Cannot detect app. Use --app <name>.". - Exit code 1 (enables CI/automation to catch failures).
- Fail with clear error:
- If detection fails AND stdin is interactive (TTY):
-
Implementation: check
require_app()innew.py -
Scaffold Output Location:
- Files created in:
{cwd}/doctypes/{doctype_name}/ - Structure:
__init__.py,doctype.py,controller.py,test_*.py
- Files created in:
-
Templates:
- Embedded templates in
new.py(no external Jinja2 files needed).
- Embedded templates in
5. Testing & Quality (Standard Tool Relays)
5.1 Test Relay
- Implement
m test:- Command:
pytest - Options:
--verbose,--coverage,-k. - Usage:
m test -k "user" --verbose - Value Add: Configures
PYTHONPATH.
- Command:
5.2 Lint/Format Relay
- Implement
m lint:- Command:
ruff check . --fix
- Command:
- Implement
m format:- Command:
ruff format .
- Command:
- Implement
m typecheck:- Command:
mypy .
- Command:
6. Configuration Management
6.1 Config File
- Create
framework_config.tomlstructure:- Supports
[framework],[apps]sections - Load/save with TOML format
- Auto-detect in CWD or parent directories
- Supports
6.2 Config Commands
- Implement
m config:show: Display current config. - Implement
m config:set <key> <value>: Update config.
7. Utility Relays
7.1 Console (IPython Relay)
- Implement
m console:- Implementation: Wrapper around
ipythonorpython -m asyncio. - Value Add: Pre-imports framework, async support.
- Options:
--no-ipythonfor plain Python.
- Implementation: Wrapper around
7.2 System Info
- Implement
m info:- Show versions (Framework, Python).
-
--verbosefor platform and service info.
7.3 Routes
- Implement
m routes:- Points to OpenAPI/Swagger docs.
8. Build Commands
8.1 Frontend Build
[!NOTE] Frontend build logic (
m build) is defined in Phase 09: Frontend & Docs. The CLI command is registered here but implementation details are in Phase 09.
- Implement
m build(placeholder):- Relay to frontend build system (see Phase 09).
- Detects package.json and runs
npm run build.
8.2 Docker Build
- Implement
m build:docker:- Command: Wrapper around
docker build. - Value Add: Reads image name/tag from
framework_config.toml. - Options:
--tag,--file,--no-cache,--push.
- Command: Wrapper around
9. Pluggable Extensions
- These commands are NOT in
framework-m. - Provided by
framework-m-studiovia entry points:- Plugin loader implemented (
load_plugins()) -
m studio(external) -
m docs:generate(external) -
m codegen(external)
- Plugin loader implemented (
10. CLI Entry Point
- Configure
pyproject.tomlscripts:m = "framework_m.cli.main:app" - Test installation (
m --help) - 22 commands registered.