# 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:
```sh
cargo install rmycli --locked
```
To install from a source checkout instead, run `cargo install --path . --locked`
in the project directory. Then connect to Redis:
```sh
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:
```sh
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][redis-cli].
| 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` |
```sh
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](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`:
```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:
```sh
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:
```sh
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][command] and, when available,
[COMMAND DOCS][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.
| 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][keyboard-protocol]
and [tmux modifier-key troubleshooting][tmux-modifiers]. The application does
not modify terminal or tmux configuration.
[keyboard-protocol]: https://sw.kovidgoyal.net/kitty/keyboard-protocol/
[tmux-modifiers]: https://github.com/tmux/tmux/wiki/Modifier-Keys
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:
```text
rmycli> LRANGE list:<Tab>
```
starts discovery on an independent connection with:
```text
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:
| 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:
```text
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:
```sh
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:
```sh
cargo build --locked
python3 tests/terminal_smoke.py
```
Use the 80-column `rustfmt.toml` configuration and keep `Cargo.lock` tracked.
See [AGENTS.md](AGENTS.md), [CHANGELOG.md](CHANGELOG.md), and the bundled help's
[attribution and license](data/README.md).
### Publishing
For your first release, sign in to [crates.io](https://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:
```sh
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][publishing] for details.
## License
The application source code is licensed under the [MIT License](LICENSE).
The bundled Redis command documentation in `data/commands.json` is separately
licensed under CC BY-SA 4.0; see its [attribution and license](data/README.md).
[publishing]: https://doc.rust-lang.org/cargo/reference/publishing.html
[command]: https://redis.io/docs/latest/commands/command/
[command-docs]: https://redis.io/docs/latest/commands/command-docs/
[redis-cli]: https://redis.io/docs/latest/develop/tools/cli/