Skip to content

Commit af832ef

Browse files
docs(cli): Clean up CLI command structure and improve documentation (#594)
## Motivation This PR improves the discoverability of the existing `rvl` CLI surface without changing the public command model. Before this change, the top-level help was sparse, `rvl index` did not present its operations as proper documented subcommands, and the docs did not clearly mirror the current command tree. That made it harder to understand the intended workflows directly from the terminal, especially for maintainers and support engineers who need to inspect the available commands quickly. ## Changes This change keeps the top-level surface unchanged at `index`, `stats`, `version`, and `mcp`, but refines the `argparse` wiring so the help output reads like a deliberate interface. `rvl --help` now lists the command groups with short purpose text and representative examples, `rvl index --help` exposes `create`, `info`, `listall`, `delete`, and `destroy` as proper documented subcommands, and `rvl stats --help` now explains the expected inputs and shows both index-name and schema-path examples along with a Redis connection example. The MCP help text was also aligned to use direct `rvl mcp ...` examples where the CLI is already assumed to be installed. The documentation changes keep the written guidance in sync with the runtime help. The README now reflects the revised top-level help and points readers to the richer `index` and `stats` help entrypoints, while the CLI notebook now documents the full current command tree rather than only the top-level groups. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Primarily refactors `argparse` wiring for `rvl`, `rvl index`, and `rvl stats`; while intended to be behavior-preserving, changes to command parsing/help text could impact existing scripts relying on previous usage/error behavior. > > **Overview** > Improves `rvl` CLI discoverability by expanding top-level `--help` output with command-group descriptions and examples, and by documenting `rvl index` operations as proper `argparse` subcommands (`create`, `info`, `listall`, `delete`, `destroy`) with per-command help/epilog text. > > Enhances `rvl stats` help text similarly, reorganizes shared CLI flags in `cli/utils.py` into clearer argument groups (index selection vs Redis connection), and aligns `rvl mcp` help examples to assume an installed `rvl` binary. > > Updates README and the CLI user-guide notebook to match the revised help/command tree, and adjusts unit tests to reflect the new help text and parsing structure. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 71a6711. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: limjoobin <joobin.lim@redis.com> Co-authored-by: limjoobin <38883279+limjoobin@users.noreply.github.com>
1 parent 270b48f commit af832ef

11 files changed

Lines changed: 275 additions & 84 deletions

File tree

README.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -527,17 +527,27 @@ router("Hi, good morning")
527527
Create, destroy, and manage Redis index configurations from a purpose-built CLI interface: `rvl`.
528528

529529
```bash
530-
$ rvl -h
530+
$ rvl --help
531531
532532
usage: rvl <command> [<args>]
533533
534-
Commands:
535-
index Index manipulation (create, delete, etc.)
536-
mcp Run the RedisVL MCP server
537-
version Obtain the version of RedisVL
538-
stats Obtain statistics about an index
534+
Redis Vector Library CLI.
535+
536+
Command groups:
537+
index Create, inspect, list, and delete Redis search indexes
538+
stats Show statistics for an existing Redis search index
539+
version Show the installed RedisVL version
540+
mcp Run the RedisVL MCP server
541+
542+
Examples:
543+
rvl index --help
544+
rvl index create -s schema.yaml
545+
rvl stats -i user_index
546+
rvl mcp --config /path/to/mcp.yaml
539547
```
540548

549+
Use `rvl index --help` to see documented subcommands such as `create`, `info`, `listall`, `delete`, and `destroy`. Use `rvl stats --help` to see both index-name and schema-path examples plus the shared Redis connection options for data-plane commands.
550+
541551
Run the MCP server over stdio (default):
542552

543553
```bash

docs/user_guide/cli.ipynb

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"source": [
77
"# The RedisVL CLI\n",
88
"\n",
9-
"RedisVL is a Python library with a dedicated CLI to help load and create vector search indices within Redis.\n",
9+
"RedisVL is a Python library with a dedicated CLI to create, inspect, list, and delete Redis search indexes, inspect index statistics, and run the RedisVL MCP server.\n",
1010
"\n",
1111
"This notebook will walk through how to use the Redis Vector Library CLI (``rvl``).\n",
1212
"\n",
@@ -39,18 +39,20 @@
3939
"metadata": {},
4040
"source": [
4141
"## Commands\n",
42-
"Here's a table of all the rvl commands and options. We'll go into each one in detail below.\n",
42+
"The table below documents the current CLI tree. Use ``rvl index --help`` and ``rvl stats --help`` for detailed flag help and examples.\n",
4343
"\n",
44-
"| Command | Options | Description |\n",
45-
"|---------------|--------------------------|-------------|\n",
46-
"| `rvl version` | | display the redisvl library version|\n",
47-
"| `rvl index` | `create --schema` or `-s <schema.yaml>`| create a redis index from the specified schema file|\n",
48-
"| `rvl index` | `listall` | list all the existing search indices|\n",
49-
"| `rvl index` | `info --index` or ` -i <index_name>` | display the index definition in tabular format|\n",
50-
"| `rvl index` | `delete --index` or `-i <index_name>` | remove the specified index, leaving the data still in Redis|\n",
51-
"| `rvl index` | `destroy --index` or `-i <index_name>`| remove the specified index, as well as the associated data|\n",
52-
"| `rvl stats` | `--index` or `-i <index_name>` | display the index statistics, including number of docs, average bytes per record, indexing time, etc|\n",
53-
"| `rvl stats` | `--schema` or `-s <schema.yaml>` | display the index statistics of a schema defined in <schema.yaml>. The index must have already been created within Redis|"
44+
"| Command | Purpose |\n",
45+
"|---------|---------|\n",
46+
"| `rvl version` | display the installed RedisVL version |\n",
47+
"| `rvl index create` | create a new Redis search index from a schema YAML file |\n",
48+
"| `rvl index info` | display schema and storage details for an index |\n",
49+
"| `rvl index listall` | list Redis search indexes available on the target Redis deployment |\n",
50+
"| `rvl index delete` | delete an index while leaving indexed data in Redis |\n",
51+
"| `rvl index destroy` | delete an index and drop its indexed data |\n",
52+
"| `rvl stats` | display statistics for an existing Redis search index |\n",
53+
"| `rvl mcp` | run the RedisVL MCP server |\n",
54+
"\n",
55+
"Within data-plane commands, ``-i`` or ``--index`` targets an existing Redis index name and ``-s`` or ``--schema`` points to a schema YAML file. Shared Redis connection options such as ``--url``, ``--host``, and ``--port`` apply to ``rvl index`` and ``rvl stats``."
5456
]
5557
},
5658
{
@@ -59,7 +61,7 @@
5961
"source": [
6062
"## Index\n",
6163
"\n",
62-
"The ``rvl index`` command can be used for a number of tasks related to creating and managing indices. Whether you are working in Python or another language, this cli tool can still be useful for managing and inspecting your indices.\n",
64+
"The ``rvl index`` command groups the index management workflows. Use ``rvl index --help`` to see the documented subcommands: ``create``, ``info``, ``listall``, ``delete``, and ``destroy``. Whether you are working in Python or another language, this CLI can still be useful for managing and inspecting your indexes.\n",
6365
"\n",
6466
"First, we will create an index from a yaml schema that looks like the following:\n"
6567
]
@@ -251,7 +253,7 @@
251253
"source": [
252254
"## Stats\n",
253255
"\n",
254-
"The ``rvl stats`` command will return some basic information about the index. This is useful for checking the status of an index, or for getting information about the index to use in other commands."
256+
"The ``rvl stats`` command returns basic information about an index. Use ``-i`` or ``--index`` to target an existing Redis index name, or ``-s`` or ``--schema`` to target a schema-defined index. Shared Redis connection options such as ``--url``, ``--host``, and ``--port`` also apply here."
255257
]
256258
},
257259
{

redisvl/cli/index.py

Lines changed: 109 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -52,40 +52,132 @@ def exit_redis_search_error(
5252

5353

5454
class Index:
55-
usage = "\n".join(
55+
description = (
56+
"Create, inspect, list, and delete Redis search indexes.\n\n"
57+
"Use `-i/--index` to target an existing Redis index name or "
58+
"`-s/--schema` to load a schema YAML file. Shared Redis connection "
59+
"options apply to these data-plane commands."
60+
)
61+
epilog = "\n".join(
5662
[
57-
"rvl index <command> [<args>]\n",
58-
"Commands:",
59-
"\tinfo Obtain information about an index (use --json for machine output)",
60-
"\tcreate Create a new index",
61-
"\tdelete Delete an existing index",
62-
"\tdestroy Delete an existing index and all of its data",
63-
"\tlistall List all indexes (use --json for machine output)",
64-
"\n",
63+
"Examples:",
64+
" rvl index create -s schema.yaml",
65+
" rvl index info -i user_index",
66+
" rvl index listall --url redis://localhost:6379",
6567
]
6668
)
6769

6870
def __init__(self):
69-
parser = argparse.ArgumentParser(usage=self.usage)
70-
71-
parser.add_argument("command", help="Subcommand to run")
72-
parser = add_index_parsing_options(parser)
73-
parser = add_json_output_flag(parser)
71+
parser = self._build_parser()
7472

7573
args = parser.parse_args(sys.argv[2:])
7674

77-
if not hasattr(self, args.command):
78-
print(f"Unknown command: {args.command}\n", file=sys.stderr)
75+
if not args.command:
7976
parser.print_help(sys.stderr)
8077
sys.exit(2)
8178

8279
try:
83-
getattr(self, args.command)(args)
80+
args.handler(args)
8481
except Exception as e:
8582
logger.error(e, exc_info=True)
8683
print(str(e), file=sys.stderr)
8784
sys.exit(1)
8885

86+
def _build_parser(self) -> argparse.ArgumentParser:
87+
parser = argparse.ArgumentParser(
88+
prog="rvl index",
89+
description=self.description,
90+
epilog=self.epilog,
91+
formatter_class=argparse.RawDescriptionHelpFormatter,
92+
)
93+
shared_options = argparse.ArgumentParser(add_help=False)
94+
add_index_parsing_options(shared_options)
95+
add_json_output_flag(shared_options)
96+
97+
subparsers = parser.add_subparsers(dest="command", title="Commands")
98+
99+
create_parser = subparsers.add_parser(
100+
"create",
101+
parents=[shared_options],
102+
help="Create a new index from a schema file",
103+
description="Create a new Redis search index from a schema YAML file.",
104+
epilog="\n".join(
105+
[
106+
"Examples:",
107+
" rvl index create -s schema.yaml",
108+
" rvl index create -s schema.yaml --url redis://localhost:6379",
109+
]
110+
),
111+
formatter_class=argparse.RawDescriptionHelpFormatter,
112+
)
113+
create_parser.set_defaults(handler=self.create)
114+
115+
info_parser = subparsers.add_parser(
116+
"info",
117+
parents=[shared_options],
118+
help="Show details about an index (use --json for machine output)",
119+
description="Display schema and storage details for an index.",
120+
epilog="\n".join(
121+
[
122+
"Examples:",
123+
" rvl index info -i user_index",
124+
" rvl index info -s schema.yaml --json",
125+
]
126+
),
127+
formatter_class=argparse.RawDescriptionHelpFormatter,
128+
)
129+
info_parser.set_defaults(handler=self.info)
130+
131+
listall_parser = subparsers.add_parser(
132+
"listall",
133+
parents=[shared_options],
134+
help="List indexes available on the target Redis deployment (use --json for machine output)",
135+
description="List all Redis search indexes available on the target Redis deployment.",
136+
epilog="\n".join(
137+
[
138+
"Examples:",
139+
" rvl index listall",
140+
" rvl index listall --host localhost --port 6379 --json",
141+
]
142+
),
143+
formatter_class=argparse.RawDescriptionHelpFormatter,
144+
)
145+
listall_parser.set_defaults(handler=self.listall)
146+
147+
delete_parser = subparsers.add_parser(
148+
"delete",
149+
parents=[shared_options],
150+
help="Delete an index but leave its data in Redis",
151+
description="Delete an existing Redis search index without dropping indexed data.",
152+
epilog="\n".join(
153+
[
154+
"Examples:",
155+
" rvl index delete -i user_index",
156+
" rvl index delete -s schema.yaml",
157+
]
158+
),
159+
formatter_class=argparse.RawDescriptionHelpFormatter,
160+
)
161+
delete_parser.set_defaults(handler=self.delete)
162+
163+
destroy_parser = subparsers.add_parser(
164+
"destroy",
165+
parents=[shared_options],
166+
help="Delete an index and drop its indexed data",
167+
description="Delete an existing Redis search index and drop its indexed data.",
168+
epilog="\n".join(
169+
[
170+
"Examples:",
171+
" rvl index destroy -i user_index",
172+
" rvl index destroy -s schema.yaml",
173+
]
174+
),
175+
formatter_class=argparse.RawDescriptionHelpFormatter,
176+
)
177+
destroy_parser.set_defaults(handler=self.destroy)
178+
179+
return parser
180+
89181
def create(self, args: Namespace):
90182
"""Create an index.
91183

redisvl/cli/main.py

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,56 @@
11
import argparse
22
import sys
33

4-
from redisvl.cli.index import Index
5-
from redisvl.cli.stats import Stats
6-
from redisvl.cli.version import Version
74
from redisvl.utils.log import get_logger
85

96
logger = get_logger(__name__)
107

118

129
def _usage():
13-
usage = [
14-
"rvl <command> [<args>]\n",
15-
"Commands:",
16-
"\tindex Index manipulation (create, delete, etc.)",
17-
"\tmcp Run the RedisVL MCP server",
18-
"\tversion Obtain the version of RedisVL",
19-
"\tstats Obtain statistics about an index",
10+
return "rvl <command> [<args>]"
11+
12+
13+
def _command_overview():
14+
command_groups = [
15+
"Command groups:",
16+
" index Create, inspect, list, and delete Redis search indexes",
17+
" stats Show statistics for an existing Redis search index",
18+
" version Show the installed RedisVL version",
19+
" mcp Run the RedisVL MCP server",
20+
]
21+
return "\n".join(command_groups)
22+
23+
24+
def _examples():
25+
examples = [
26+
"Examples:",
27+
" rvl index --help",
28+
" rvl index create -s schema.yaml",
29+
" rvl stats -i user_index",
30+
" rvl mcp --config /path/to/mcp.yaml",
2031
]
21-
return "\n".join(usage) + "\n"
32+
return "\n".join(examples)
2233

2334

2435
class RedisVlCLI:
2536
def __init__(self):
2637
parser = argparse.ArgumentParser(
27-
description="Redis Vector Library CLI", usage=_usage()
38+
prog="rvl",
39+
description=f"Redis Vector Library CLI.\n\n{_command_overview()}",
40+
usage=_usage(),
41+
epilog=_examples(),
42+
formatter_class=argparse.RawDescriptionHelpFormatter,
2843
)
2944

30-
parser.add_argument("command", help="Subcommand to run")
45+
parser.add_argument("command", nargs="?", help="Command group to run")
3146

3247
if len(sys.argv) < 2:
3348
parser.print_help(sys.stdout)
3449
sys.exit(0)
3550

3651
args = parser.parse_args(sys.argv[1:2])
3752

38-
if not hasattr(self, args.command):
53+
if not args.command or not hasattr(self, args.command):
3954
print(f"Unknown command: {args.command}\n", file=sys.stderr)
4055
parser.print_help(sys.stderr)
4156
sys.exit(2)
@@ -47,6 +62,8 @@ def __init__(self):
4762
sys.exit(1)
4863

4964
def index(self):
65+
from redisvl.cli.index import Index
66+
5067
Index()
5168
sys.exit(0)
5269

@@ -57,9 +74,13 @@ def mcp(self):
5774
sys.exit(0)
5875

5976
def version(self):
77+
from redisvl.cli.version import Version
78+
6079
Version()
6180
sys.exit(0)
6281

6382
def stats(self):
83+
from redisvl.cli.stats import Stats
84+
6485
Stats()
6586
sys.exit(0)

redisvl/cli/mcp.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ class MCP:
2121
epilog = (
2222
"Use this command when wiring RedisVL into an MCP client.\n\n"
2323
"Examples:\n"
24-
" uvx --from redisvl[mcp] rvl mcp --config /path/to/mcp_config.yaml\n"
25-
" uvx --from redisvl[mcp] rvl mcp --config /path/to/mcp_config.yaml --transport streamable-http --port 8000\n"
26-
" uvx --from redisvl[mcp] rvl mcp --config /path/to/mcp_config.yaml --transport sse --host 0.0.0.0 --port 9000"
24+
" rvl mcp --config /path/to/mcp_config.yaml\n"
25+
" rvl mcp --config /path/to/mcp_config.yaml --transport streamable-http --port 8000\n"
26+
" rvl mcp --config /path/to/mcp_config.yaml --transport sse --host 0.0.0.0 --port 9000"
2727
)
2828
usage = "\n".join(
2929
[

redisvl/cli/stats.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,28 @@ def _stats_rows(index_info: dict) -> list[tuple[str, object]]:
8484

8585

8686
class Stats:
87-
usage = "\n".join(
87+
description = (
88+
"Display statistics for an existing Redis search index.\n\n"
89+
"Use `-i/--index` to inspect an existing Redis index by name or "
90+
"`-s/--schema` to load the target from a schema YAML file. Shared "
91+
"Redis connection options apply to this data-plane command."
92+
)
93+
epilog = "\n".join(
8894
[
89-
"rvl stats [<args>]\n",
95+
"Examples:",
96+
" rvl stats -i user_index",
97+
" rvl stats -s schema.yaml",
98+
" rvl stats -i user_index --host localhost --port 6379",
9099
]
91100
)
92101

93102
def __init__(self):
94-
parser = argparse.ArgumentParser(usage=self.usage)
103+
parser = argparse.ArgumentParser(
104+
prog="rvl stats",
105+
description=self.description,
106+
epilog=self.epilog,
107+
formatter_class=argparse.RawDescriptionHelpFormatter,
108+
)
95109
parser = add_index_parsing_options(parser)
96110
parser = add_json_output_flag(parser)
97111
args = parser.parse_args(sys.argv[2:])

0 commit comments

Comments
 (0)