You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CLAUDE.md
+15-12Lines changed: 15 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -86,22 +86,25 @@ The Roboflow Python SDK follows a hierarchical object model that mirrors the Rob
86
86
87
87
### CLI Package (`roboflow/cli/`)
88
88
89
-
The CLI is a modular package with auto-discovered handler modules. `roboflow/roboflowpy.py` is a backwards-compatibility shim that delegates to `roboflow.cli.main`.
89
+
The CLI is built on [typer](https://typer.tiangolo.com/) (which uses Click under the hood). `roboflow/roboflowpy.py` is a backwards-compatibility shim that delegates to `roboflow.cli.main`.
90
90
91
91
**Package structure:**
92
-
-`__init__.py` — Root parser with global flags (`--json`, `--workspace`, `--api-key`, `--quiet`), auto-discovery via `pkgutil.iter_modules`, custom `_CleanHelpFormatter`, and `_reorder_argv` for flexible flag positioning
92
+
-`__init__.py` — Root `typer.Typer()` app with global `@app.callback()` for `--json`, `--workspace`, `--api-key`, `--quiet`. Explicitly registers all handler apps via `app.add_typer()`.
93
93
-`_output.py` — `output(args, data, text)` for JSON/text output, `output_error(args, msg, hint, exit_code)` for structured errors, `suppress_sdk_output()` to silence SDK noise, `stub()` for unimplemented commands
94
+
-`_compat.py` — `ctx_to_args(ctx, **kwargs)` bridge that converts `typer.Context` to the `SimpleNamespace` that output helpers expect
94
95
-`_table.py` — `format_table(rows, columns)` for columnar list output
95
96
-`_resolver.py` — `resolve_resource(shorthand)` for parsing `project`, `ws/project`, `ws/project/3`
96
-
-`handlers/` — One file per command group (auto-discovered). `_aliases.py` registers backwards-compat top-level commands (loaded last)
97
+
-`handlers/` — One file per command group, each exporting a `typer.Typer()` app. `_aliases.py` registers backwards-compat top-level commands via `register_aliases(app)`.
97
98
98
99
**Adding a new command:**
99
100
1. Create `roboflow/cli/handlers/mycommand.py`
100
-
2. Export `register(subparsers)` — it will be auto-discovered
101
-
3. Use lazy imports for heavy dependencies (inside handler functions, not at module top level)
102
-
4. Use `output()` for all output, `output_error()` for all errors
103
-
5. Wrap SDK calls in `with suppress_sdk_output():` to prevent "loading..." noise
104
-
6. Add tests in `tests/cli/test_mycommand_handler.py`
101
+
2. Create a module-level `mycommand_app = typer.Typer(help="...", no_args_is_help=True)`
102
+
3. Add commands with `@mycommand_app.command("verb")` decorators
103
+
4. Each command takes `ctx: typer.Context` + typed params, calls `ctx_to_args(ctx, **params)` to create args namespace
104
+
5. Use `output()` for all output, `output_error()` for all errors
105
+
6. Wrap SDK calls in `with suppress_sdk_output():` to prevent "loading..." noise
106
+
7. Register in `roboflow/cli/__init__.py`: `app.add_typer(mycommand_app, name="mycommand")`
107
+
8. Add tests using `typer.testing.CliRunner` in `tests/cli/test_mycommand_handler.py`
105
108
106
109
**Agent experience requirements for all CLI commands:**
107
110
- Support `--json` for structured output (stable schema)
@@ -119,16 +122,16 @@ The CLI is a modular package with auto-discovered handler modules. `roboflow/rob
4.**Batch Operations**: Upload and download operations support concurrent processing
121
124
5.**CLI Noun-Verb Pattern**: Commands follow `roboflow <noun> <verb>` (e.g. `roboflow project list`). Common operations have top-level aliases (`login`, `upload`, `download`)
122
-
6.**CLI Auto-Discovery**: Handler modules in `roboflow/cli/handlers/` are loaded automatically — no registration list to maintain
125
+
6.**CLI Explicit Registration**: Handler apps are explicitly imported and registered via `app.add_typer()` in `__init__.py` — clear dependency chain, no runtime discovery
123
126
7.**Backwards Compatibility**: Legacy command names and flag signatures are preserved as hidden aliases
124
127
125
128
## Project Configuration
126
129
127
-
-**Python Version**: 3.8+
128
-
-**Main Dependencies**: See `requirements.txt`
130
+
-**Python Version**: 3.10+
131
+
-**Main Dependencies**: See `requirements.txt` (includes `typer>=0.12.0`)
129
132
-**Entry Point**: `roboflow=roboflow.roboflowpy:main` (shim delegates to `roboflow.cli.main`)
130
133
-**Code Style**: Enforced by ruff with Google docstring convention
131
-
-**Type Checking**: mypy configured for Python 3.8
134
+
-**Type Checking**: mypy configured for Python 3.10
The CLI lives in `roboflow/cli/` with auto-discovered handler modules. To add a new command:
81
+
The CLI is built on [typer](https://typer.tiangolo.com/). Each command group is a separate `typer.Typer()` app registered in `roboflow/cli/__init__.py`. To add a new command:
-[ ] SDK calls wrapped in `with suppress_sdk_output():`
124
131
-[ ] Exit codes: 0=success, 1=error, 2=auth, 3=not found
125
132
126
-
**Documentation policy:**`CLI-COMMANDS.md` in this repo is a quickstart only. The comprehensive command reference lives in [`roboflow-product-docs`](https://github.com/roboflow/roboflow-product-docs) and is published to docs.roboflow.com. When adding a new command, update both: add a quick example to `CLI-COMMANDS.md` and the full reference to the product docs CLI page.
133
+
**Documentation policy:**`CLI-COMMANDS.md` in this repo is a quickstart only. The comprehensive command reference lives in [`roboflow-dev-reference`](https://github.com/roboflow/roboflow-dev-reference) and is published to docs.roboflow.com/developer/command-line-interface. When adding a new command, update both: add a quick example to `CLI-COMMANDS.md` and the full reference to the dev-reference CLI page.
0 commit comments