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
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
+
91
+
**Package structure:**
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
+
-`_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
95
+
-`_table.py` — `format_table(rows, columns)` for columnar list output
96
+
-`_resolver.py` — `resolve_resource(shorthand)` for parsing `project`, `ws/project`, `ws/project/3`
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)`.
98
+
99
+
**Adding a new command:**
100
+
1. Create `roboflow/cli/handlers/mycommand.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`
108
+
109
+
**Agent experience requirements for all CLI commands:**
110
+
- Support `--json` for structured output (stable schema)
111
+
- No interactive prompts when all required flags are provided
- Exit codes: 0 = success, 1 = error, 2 = auth error, 3 = not found
114
+
- Actionable error messages: always tell the user what went wrong AND what to do
115
+
116
+
**Documentation policy:**`CLI-COMMANDS.md` in this repo is a quickstart only. The full command reference lives in `roboflow-product-docs` (published to docs.roboflow.com). When adding commands, update both.
94
117
95
118
### Key Design Patterns
96
119
97
120
1.**Hierarchical Access**: Always access objects through their parent (Workspace → Project → Version → Model)
98
121
2.**API Key Flow**: API key is passed down through the object hierarchy
4.**Batch Operations**: Upload and download operations support concurrent processing
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`)
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
126
+
7.**Backwards Compatibility**: Legacy command names and flag signatures are preserved as hidden aliases
0 commit comments