rmycli 0.1.0

A Redis shell with live command help and type-aware completion
rmycli-0.1.0 is not a library.

rmycli

A Rust Redis shell with live command help, metadata-driven argument completion, and type-aware key completion.

Status

The first interactive implementation is available. It connects to Redis, executes arbitrary commands, discovers the server's command catalog, shows syntax and argument help while editing, and completes keys using bounded, cancellable SCAN requests. It also estimates LRANGE replies before execution.

Common redis-cli connection, scripting, and output options are supported, including RESP3 and cluster redirects. Cluster-wide discovery, replication/RDB transfers, and estimates for commands other than LRANGE are not implemented. See Compatibility and limits below for metadata and streaming limitations.

Install and connect

Use Rust 1.88 or newer (the current stable toolchain is recommended).

Once version 0.1.0 is published to crates.io, install it with:

cargo install rmycli --locked

To install from a source checkout instead, run cargo install --path . --locked in the project directory. Then connect to Redis:

rmycli
rmycli -3
rmycli -h localhost -p 6379 -n 2
rmycli -s /tmp/redis.sock
rmycli -u redis://localhost:6379/2
rmycli -u rediss://redis.example.com:6379/0
REDISCLI_AUTH=secret rmycli --user alice

--tls enables certificate-verified TLS for -h/-p connections or upgrades an existing TCP URI without changing its host or port. System trust roots are used unless --cacert FILE or --cacertdir DIR supplies PEM CA certificates. Use --cert FILE --key FILE for a PEM client certificate chain and private key. These flags also work with rediss:// URLs and TLS instances. --insecure explicitly disables certificate verification; verification is otherwise on. A URL supplies connection settings; explicit -n, --user, and -a/REDISCLI_AUTH override its database and credentials. REDIS_URL is also supported. Use rmycli --help for all options (-h selects the host).

Commands can also be supplied directly or one per line on stdin:

rmycli PING
rmycli --raw GET greeting
printf 'MULTI\nSET greeting "hello world"\nEXEC\n' | rmycli
rmycli --yes LRANGE big-list 0 -1

Command-line arguments pass through as supplied by the operating system. Interactive and stdin input support single/double quotes, backslash escapes, and \xHH byte escapes. Suggestions round-trip through the same parser, so spaces, quotes, backslashes, NULs, and non-UTF-8 key bytes remain intact. Formatted output escapes terminal control sequences. Redirected stdout now uses raw output by default, like redis-cli; --no-raw restores formatted output. --raw writes reply bytes verbatim in noninteractive mode. Redis errors exit noninteractive mode with a nonzero status, with or without -e. Server errors show the server's message without the Redis library's preamble (for example, (error) syntax error in the editor). Errors without a message show their server error code. Client and connection errors retain their context.

Familiar redis-cli options

rmycli --help groups options by purpose and includes connection, scripting, TLS, and configuration examples. -h selects the host; help is --help. Options precede the command. Once a command starts, subsequent arguments pass through unchanged, including -1, --raw, and other option-looking values. Existing rmycli long names, including --password, remain supported. The names and core semantics follow the Redis CLI reference.

Purpose Supported redis-cli options
Connection -h, -p, -s, -u, -n, -t
Authentication -a, --pass, --user, --askpass, --no-auth-warning
Protocol and session -2, -3, --name, -c, --show-pushes yes/no
TLS --tls, --cacert, --cacertdir, --cert, --key, --insecure
Output --raw, --no-raw, --csv, --json, --quoted-json, -d, -D
Scripting -x, -X, --quoted-input, -r, -i, --eval, -e
Key listing --scan, --pattern, --quoted-pattern, --count
Information --help, --version, -v, --verbose
rmycli -3 --name maintenance -h localhost -p 6379
rmycli --askpass --user alice
rmycli --tls --cacert ca.pem --cert client.pem --key client.key
rmycli --json HGETALL account:1
rmycli -r 5 -i 0.5 INCR counter
printf 'hello\n' | rmycli -x SET greeting
rmycli -D '' --raw DUMP key > key.dump
rmycli -X payload RESTORE key2 0 payload REPLACE < key.dump
rmycli --quoted-input GET '"key\x00with-nul"'
rmycli --eval script.lua key1 key2 , arg1 arg2
rmycli --scan --pattern 'user:*' --count 100
  • RESP2 remains the default. -3 negotiates RESP3 on connection; --json and --quoted-json also select RESP3 unless -2 is given. -2 and -3 together are rejected. Auxiliary connections use RESP2 independently.
  • --pass/-a takes precedence over REDISCLI_AUTH; --askpass overrides every password source. The prompt requires terminal stdin and disables echo; it cannot be combined with -x/-X. Use REDISCLI_AUTH with piped input. Explicit command-line credentials produce a warning unless suppressed.
  • -t is a connection timeout in seconds, including fractions; -t 0 uses the OS timeout. Without -t, the existing --timeout-ms default of 1,000 ms applies. Auxiliary connections stay bounded by --timeout-ms even with -t 0. Commands that intentionally block still have no read timeout.
  • -x appends all stdin bytes, including trailing newlines, as one argument. -X TAG replaces the first argument matching TAG and rejects a missing tag or replacement of the command name. --quoted-input decodes each supplied argument separately, including \xHH escapes.
  • -r N repeats a command in noninteractive mode, with -i seconds between executions. -r 0 executes nothing; -r -1 repeats until Ctrl-C. --eval FILE sends EVAL, using the standalone comma to separate keys from arguments; without a comma all trailing arguments are keys.
  • -d separates raw array elements and -D separates raw replies. Empty delimiters are allowed. JSON preserves valid UTF-8; invalid UTF-8 falls back to ASCII byte escapes. --quoted-json always represents byte escapes as literal JSON strings. Nonfinite doubles become strings and nested errors become objects so output remains valid JSON. CSV uses redis-cli's escaped strings, rather than RFC 4180 quoting. The live editor always escapes terminal control bytes, even with --raw; JSON and CSV work in the editor.
  • --show-pushes controls unsolicited RESP3 messages (default: on for terminal stdout). The async session reader receives messages while idle and wakes the worker when a message or submitted command arrives. Invalidations appear without another command, in bold, while preserving the input and cursor. The default interactive format is -> invalidate: 'key', with one line per key, or -> invalidate: (nil) for a cache-wide invalidation. Keys are escaped safely; binary keys use double quotes and byte escapes. JSON, CSV, and noninteractive output retain their existing formats. Reading sends no Redis commands and also runs during WATCH and MULTI. Hidden pushes are still drained; Pub/Sub messages remain visible. Push styling is currently fixed. Noninteractive push display remains command driven.
  • --scan streams one SCAN batch at a time until cursor zero without retaining the whole keyspace. Ctrl-C interrupts it; -i throttles requests. --count is a Redis work hint, not a result limit. Like redis-cli, this explicit listing may contain duplicates and is not a snapshot. It does not use the bounded completion budgets and makes no unique-key-count claim.
  • -c follows up to five MOVED/ASK redirects, including ASKING before an ASK retry. It preserves TLS, authentication, database, protocol, and client name. It never retries network failures, or redirects while MULTI/WATCH is active. Reconnecting to a redirected node does not restore other connection-local state. Discovery and estimates cover only the currently connected node. -c cannot be combined with -s.

Deliberately omitted and currently unsupported options

Use redis-cli for its separate administration and diagnostic tools: --cluster and its sub-options; --replica/--slave, --rdb, --functions-rdb; --pipe/--pipe-timeout; --stat, --latency*, --intrinsic-latency, --lru-test, --vset-recall*; --bigkeys, --memkeys*, --keystats*, --hotkeys and their --cursor/--top modifiers; and --ldb/--ldb-sync-mode. These are distinct workflows beyond the interactive shell and ordinary command execution.

Address-family selection (-4/-6), a separate --sni, --tls-ciphers, and --tls-ciphersuites are also currently unsupported: rmycli does not expose those transport controls. TLS uses the connection hostname for SNI and rustls cipher defaults. Unsupported switches before the command fail with a usage error; they are never accepted as no-ops. Full option parity is not claimed.

The session uses asynchronous TCP, Unix sockets, or TLS, with the published Redis 1.8 parser and command encoder; no vendored dependency is required. A dedicated reader keeps partial frames across waits and feeds a bounded 64-message channel. User commands remain serialized on the same connection, including protocol changes, transactions, RESP2/RESP3 Pub/Sub, and MONITOR. This raw stream is needed because redis-rs's async multiplexer does not expose arbitrary streaming replies on an existing connection. Dropping a session aborts its reader; Ctrl-C still kills the exact server client to cancel a blocking command. Completion, estimation, and metadata use separate synchronous connections with timeouts on their worker thread.

Configuration and saved instances

Settings are read once at startup from the first available file, in this order:

  1. $XDG_CONFIG_HOME/rmycli.toml, or ~/.config/rmycli.toml when XDG_CONFIG_HOME is unset, empty, or relative.
  2. rmycli.toml in each directory in $XDG_CONFIG_DIRS, in order (default: /etc/xdg). Relative directory entries are ignored.

Use --config /path/to/settings.toml to select a file explicitly, or --no-config to use built-in settings. Files are not merged. Missing discovered files are skipped; a missing explicit file, unreadable file, malformed TOML, unknown setting, or invalid value causes an error before connecting. No file is created during normal startup. --help and --version work without loading settings.

See rmycli.dist.toml for a commented reference covering every supported setting, defaults, color formats, and authentication examples. Copy it to ~/.config/rmycli.toml (or $XDG_CONFIG_HOME/rmycli.toml); the distribution file is not loaded automatically.

For a shorter example, create ~/.config/rmycli.toml:

[theme]
inline-hint = "dark_grey"

[theme.commands]
GET = "cyan"
LRANGE = "#89b4fa"
XGROUP = "green"
"XGROUP CREATE" = "yellow"

[instances.qa]
host = "redis.qa.example.com"
port = 6379
db = 0
user = "alice"
password-env = "QA_REDIS_PASSWORD"
tls = false

Select an instance with rmycli --instance qa (also works with a command, such as rmycli --instance qa PING). Authentication happens automatically on connect, including background completion and reply-estimation connections. Instances are selected explicitly, not inferred from host/port. Instance names are case sensitive. An unknown instance is an error.

All instance fields are optional: host and port default to 127.0.0.1:6379, database to zero, and TLS to off. Omit user for Redis's default user or password-only authentication. Set tls = true for certificate-verified TLS. Use either password = "..." or password-env = "ENVIRONMENT_VARIABLE"; the latter reads the password from that variable when the instance is selected. A missing password variable is an error unless a higher-priority password is provided. Protect a file containing passwords with owner-only permissions.

Explicit -h, -p, -n, --user, and -a/--pass override the selected instance's values. REDISCLI_AUTH overrides its password too; -a takes precedence over that environment variable. --tls can enable TLS on an instance. --instance cannot be combined with -u/REDIS_URL or -s; unset REDIS_URL before selecting an instance. Without --instance, connection behavior is unchanged. Connection timeouts and discovery/reply limits remain command-line options.

The theme controls the foreground color of inline argument hints. Command names are case insensitive, with whitespace normalized; a subcommand's color overrides its parent's color, which overrides inline-hint. Matching uses the resolved metadata command, not key or argument text. Unknown command names are allowed so the same file can cover module commands on different servers. Duplicate names after normalization are errors. Popup colors are unchanged.

Colors accept black, red, green, yellow, blue, magenta, cyan, white, grey, dark_grey, and the dark_ variants of red, green, yellow, blue, magenta, and cyan. Also supported: reset (terminal default), "#RRGGBB", "rgb_(R,G,B)", and "ansi_(N)" (components/index 0–255). For example, inline-hint = "#ffffff" selects white; hex digits accept either case. Keep the quotes because an unquoted # starts a TOML comment. Named colors follow the terminal palette; RGB rendering depends on terminal support. The built-in hint color remains dark_grey.

Read and edit settings from the command line

Local configuration commands run without connecting to Redis:

rmycli config get theme.inline-hint
rmycli config set theme.inline-hint cyan
rmycli config set theme.commands.LRANGE '#89b4fa'
rmycli config set 'theme.commands."XGROUP CREATE"' yellow
rmycli config unset theme.commands.LRANGE
rmycli config set instances.qa.host redis.qa.example.com
rmycli config set instances.qa.port 6380
rmycli config set instances.qa.password-env QA_REDIS_PASSWORD
rmycli config get instances.qa.host

get prints the effective value, including built-in defaults and parent-command color inheritance. Missing optional settings and unknown instances return an error. It reads the file's settings, without applying connection flags or resolving password environment variables. set prints the saved value; password updates print [redacted]. An explicit get of a stored password prints it.

For color settings, both get and set show the value followed by sample text rendered in that color when stdout is a terminal. Redirected output is just the value and a newline. A nonempty NO_COLOR disables automatic previews. Use --color always to force a preview (including when NO_COLOR is set), or --color never to suppress it:

rmycli config get theme.inline-hint --color always
rmycli config get theme.inline-hint --color never

Keys use TOML dotted-key syntax; quote a component containing spaces or dots, as in 'theme.commands."XGROUP CREATE"' or 'instances."qa.eu".host'. String values are literal arguments, requiring only shell quoting. Ports and databases must be integers; TLS takes true or false. The complete updated file must pass validation before it is saved. unset removes an explicit value, restoring its default/inheritance, and fails if that value was not set.

Edits preserve comments and unrelated settings and replace the file atomically. By default they write $XDG_CONFIG_HOME/rmycli.toml (normally ~/.config/rmycli.toml), creating directories as needed. If only a system file exists, its contents are copied into the new user file before editing, so the other effective settings are retained. System files are not edited implicitly. --config PATH, before or after config, selects a specific file; set can create it. Existing symlinks are followed, existing file permissions are retained, and new files have owner-only permissions on Unix. Changes take effect in new shell sessions.

Lowercase rmycli config is reserved for these local operations. Use uppercase rmycli CONFIG GET ... or rmycli CONFIG SET ... for the Redis command. Interactive Redis commands are unaffected. rmycli config --help lists the local commands; rmycli --no-config config get ... reads built-in defaults.

Live help and editing

On connection, rmycli loads COMMAND and, when available, COMMAND DOCS. Remaining arguments appear in grey by default on the input line, like redis-cli: typing lrange displays lrange key start stop, with only key start stop supplied by the program. Typing the key changes the hint to start stop. Hints never become part of the submitted command. They are hidden while editing inside the line and clipped at the terminal's right edge. Redraws are buffered and use synchronized terminal updates where supported, so clearing hints, printing output, and drawing the next prompt appear together. F1 opens a dismissible help panel with current command documentation, editor shortcuts, and connection status. HELP command prints full syntax, summary, version, group, and complexity to the terminal. Nested alternatives, optional clauses, repeated arguments, subcommands, and module documentation come from the server rather than a fixed set of handwritten command signatures.

The complete official Redis command-help catalog is bundled as a fallback. Live documentation takes precedence, including for module commands. Fallback help is labeled because it can differ from the connected server's version. Command names are restricted to the live catalog when COMMAND succeeds.

Key / command Action
Tab / Shift-Tab Start completion / cycle through popup candidates
Enter with popup open Accept the candidate; does not execute
Enter without popup Submit the command
Ctrl+Enter on KEYS <pattern> Stream matching keys with SCAN
Hold Ctrl (with modifier-event support) Show [Ctrl] in the prompt
Escape Close the popup or cancel discovery/confirmation
Left / Right, Home / End, Ctrl-A / Ctrl-E Move the cursor
Backspace / Delete, Ctrl-U / Ctrl-K Delete characters or text before/after the cursor
Up / Down Browse in-memory command history
F1 Open or close command help, editor shortcuts, and connection details
PageUp / PageDown, Up / Down with help open Scroll the help panel
Enter with help open Close help without submitting input
CLEAR, Ctrl-L Clear the screen locally without sending a Redis command
Ctrl-C Stop alternate KEYS scanning; otherwise clear input or close an executing/streaming connection
Ctrl-D, \quit, \q, QUIT, EXIT Exit
HELP command, HELP @group Full command help or commands in a group
HELP, \help Open editor help and connection details
\reconnect Open a new connection and refresh metadata

Experiment with KEYS * or KEYS foo:* followed by Ctrl+Enter to stream keys using SCAN until cursor zero. The pattern is passed through unchanged: KEYS foo:* uses SCAN ... MATCH foo:* COUNT 128. Empty batches do not stop iteration. Output is streamed with bounded buffering; duplicates are possible and the listing is not a snapshot. It covers the current database on the connected node, without completion budgets or a unique-key-count claim.

Ctrl-C stops further iterations without exiting or disconnecting. Any in-flight request finishes first; buffered keys are discarded, and the output is labeled partial. You can then run another command on the same connection. Alternate KEYS is unavailable during MULTI, WATCH, or streaming sessions. Normal Enter still sends KEYS directly; there is no default-remapping setting yet. With a completion popup open, either Enter only accepts the candidate.

Ctrl+Enter requires a terminal that distinguishes it from Enter. The editor requests the Kitty keyboard protocol, including modifier presses and releases. On supporting terminals, holding either Ctrl key changes rmycli> to rmycli[Ctrl]>; releasing it restores the prompt. Modifier events leave the input, completion popup, and confirmation unchanged. Shift remains available for typing case-sensitive keys. Ctrl+Enter with a popup open only accepts the candidate; release events never submit commands.

Terminals or multiplexers without this support may send plain Enter for both, which executes ordinary KEYS. They may also omit standalone Ctrl presses and releases, so the held-key indicator cannot work there. An ordinary Ctrl chord alone does not turn on the indicator, since its release may never be reported.

If modified Enter acts like Enter, check the whole terminal path, including tmux or screen. For example, tmux with extended-keys off cannot forward the distinction. Changing the application shortcut alone cannot fix that. Try a terminal supporting the Kitty keyboard protocol directly, outside tmux, to test the held-key indicator. See the keyboard protocol and tmux modifier-key troubleshooting. The application does not modify terminal or tmux configuration.

The prompt starts at the terminal's current cursor row and follows replies, like a conventional command-line shell. If existing output ends mid-line, the prompt starts on the next line. There is no startup banner or persistent connection footer. Startup shows a metadata-loading status only after 200 ms or when you type, avoiding a flash on fast connections. The shell uses the normal terminal buffer, so earlier shell output and command replies remain in your terminal's scrollback, including after exit. Use your terminal's scrollback controls to review output.

Completion choices appear in a bordered window below the current argument. The selected choice is highlighted; long menus scroll as you cycle through them. Short status messages share the input line when it is empty. Help, completion, and longer messages reserve space below the prompt only when visible, scrolling as needed at the bottom of the terminal. Closing a panel removes it and preserves the input. Errors, discovery progress, and confirmations still appear when needed. The prompt is rmycli> for database zero and rmycli[N]> otherwise.

History is bounded to 500 commands and is not saved to disk. Pasting text never submits a command. Output retention is controlled by your terminal's scrollback settings; the application does not keep a separate transcript.

Key completion

For example:

rmycli> LRANGE list:<Tab>

starts discovery on an independent connection with:

SCAN 0 MATCH list:* COUNT 128 TYPE list

Redis key specifications determine argument positions: fixed indexes, keyword-based starts, key counts, strides, and ranges. Argument trees help identify key positions in unfinished commands, including trailing timeouts and stream IDs that have not been typed yet. Legacy first/last/step metadata is supported. Unknown or incomplete specifications can fall back to COMMAND GETKEYS when enough of the command has been entered for Redis to extract its keys; this introspection does not execute the command.

Separate type hints cover lists, hashes, sets, sorted sets, streams, strings, bitmaps, and HyperLogLogs. Commands accepting multiple types, overwrite operations, and unknown module types use unfiltered discovery. Existing-key suggestions never prevent entering a new destination key. If the server rejects SCAN TYPE syntax, discovery retries without that filter and labels the candidates as unfiltered.

Completion escapes glob metacharacters in the typed prefix before adding *. It preserves key case and bytes, deduplicates batches, and continues past empty batches until cursor zero or a budget is reached. It never uses KEYS.

  • Zero matches after a complete scan leaves the input unchanged.
  • One match after a complete scan inserts that key.
  • Multiple matches open a popup; Tab and Shift-Tab cycle, Enter accepts, and Escape closes it.
  • Above the display threshold, confirmation is required before showing keys.
  • Partial scans say at least N matches (partial scan). Choose y to show discovered keys, c to continue discovery, or Enter/Escape/n to cancel. A partial scan with one candidate still requires explicit acceptance.

Default limits and their options:

Limit Default Option
Display confirmation threshold 100 keys --completion-threshold
Retained distinct keys 10,000 --scan-max-keys
Retained raw key bytes 4 MiB --scan-max-bytes
SCAN requests per discovery step 32 --scan-max-batches
Time per discovery step 750 ms --scan-ms
Connection / auxiliary socket timeout 1,000 ms --timeout-ms

A continuation permits another threshold-sized page within the hard key/byte limits. COUNT is only a Redis work hint. The client checks limits between requests; an in-flight request can add up to its socket timeout, and a single reply must be received before its retained-key budget can be checked. Editing or pressing Escape cancels further requests; generation IDs discard stale results. Network work runs outside the terminal input loop.

Reply-size guidance and session state

Before ordinary LRANGE execution, an auxiliary LLEN request estimates the number of elements in the inclusive range, including negative indexes and bounds. Above --reply-threshold (default 10,000), interactive mode asks:

Continue? [y/N] May return about 3000000 elements (not bytes; data can change).

Declining leaves the command unexecuted and available for editing. In noninteractive mode, an oversized estimate causes an error before execution; --yes explicitly bypasses the check. Unknown estimates, unsupported commands, and failed probes remain unknown and permit manual execution. These estimates are not memory limits or guarantees.

Discovery and estimation use separate connections with the active database and credentials. They are paused during MULTI, WATCH, and streaming modes. SELECT changes are tracked, including successful queued changes at EXEC; DISCARD leaves the database unchanged. AUTH, HELLO AUTH, and RESET update auxiliary connection settings. Probes never enter the user's transaction. Commands queued inside transactions execute without reply-size confirmation.

Connection errors never trigger automatic command replay. Use \reconnect explicitly; reconnecting starts a fresh session and does not restore transaction, WATCH, subscription, or other connection-local state. Ctrl-C during execution uses CLIENT ID and CLIENT KILL ID through the auxiliary connection to close only this client's socket. If ACLs forbid cancellation, Ctrl-D exits the client. Closing the socket cannot undo a command the server has already executed.

Compatibility and limits

  • Redis 7+ provides the richest metadata. Integration tests run against Redis 8.0.2. Older metadata and ACL-restricted introspection use labeled bundled documentation and available legacy fields; they are tested with fixtures.
  • A module must expose key specifications or argument documentation for completion of an unfinished command. COMMAND GETKEYS requires sufficient arguments and permission. Missing metadata never prevents manual submission.
  • Some partial commands are intrinsically ambiguous: after XREAD STREAMS k, the next word could be another key or the first ID. Suggestions are advisory, not command validation. Unrecognized option ordering may reduce argument hints.
  • A scan describes only the connected node and database. -c follows command redirects; slot-map routing and cluster-wide discovery are not implemented. Even a completed SCAN is not a snapshot of a changing keyspace.
  • Pub/Sub and MONITOR replies stream to the transcript. In interactive streaming mode, Ctrl-C ends the stream; reconnect before submitting further commands. Replication protocols and an interactive unsubscribe workflow are not provided.
  • History is bounded and displayed output is released by the application, but command replies are decoded in memory before display. The LRANGE estimate is not a general reply-memory cap.
  • No persistent history, SSH tunnels, or full redis-cli option compatibility is claimed by this version. See the option compatibility section above.

Development

The code separates byte parsing, command metadata and argument grammar, type hints, scan discovery, estimation, session transport, workers, and the terminal. Dependencies are redis for RESP and auxiliary connections, tokio for async session I/O, and combine for the decoder state required by Redis's public async parser. tokio-rustls, rustls, and rustls-native-certs provide TLS, its crypto provider, and system trust roots. crossterm handles terminal I/O, clap handles options, serde_json handles metadata, and unicode-width handles cursor/layout calculations. toml and serde parse typed configuration and reject unknown fields and invalid values; xdg resolves configuration directories. Crossterm's Serde support validates color values. toml_edit preserves comments during CLI edits, and tempfile provides temporary files for atomic replacement.

Install redis-server for the isolated integration fixtures, which start their own Unix-socket servers with persistence disabled. Tests never use an existing Redis database. Before every commit, including documentation-only commits:

cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets --all-features

To exercise the actual executable, terminal editing, completion acceptance, cancellation, streaming, and noninteractive policy, also install redis-cli and Python 3, then run:

cargo build --locked
python3 tests/terminal_smoke.py

Use the 80-column rustfmt.toml configuration and keep Cargo.lock tracked. See AGENTS.md, CHANGELOG.md, and the bundled help's attribution and license.

Publishing

For your first release, sign in to crates.io, verify your email address, create an API token with permission to publish, and run cargo login. Paste the token at Cargo's prompt.

Before publishing, move the release's changelog entries from Unreleased into a version heading dated YYYY-MM-DD, retaining an Unreleased section. Run the formatting, Clippy, and test checks above and commit the release changes. Then:

cargo package --list
cargo publish --dry-run --locked
cargo publish --locked

Review the package file list before uploading. The manifest explicitly includes source, bundled help and its license, tests, and project documentation; local recordings are excluded. The dry run builds the packaged source without uploading it. After a successful publish, tag the release commit (for example, git tag v0.1.0). A published version cannot be overwritten; corrections need a new version. See the Cargo publishing guide for details.

License

The application source code is licensed under the MIT License. The bundled Redis command documentation in data/commands.json is separately licensed under CC BY-SA 4.0; see its attribution and license.