# digit v0.3.0 Spec -- Hardening, Completions, and Documentation
**Date:** 2026-04-11
**Status:** Draft
**Baseline:** v0.2.0 (commit `d8ee947`)
## Overview
Four areas of improvement: response size capping, raw output mode, shell completion generation, and comprehensive documentation for docs.rs. Documentation is done incrementally with each feature, plus a final pass at the end.
## 1. Response Size Cap
Protect the client from unbounded server responses.
**New CLI flag:**
```
--max-size <BYTES> Maximum response size in bytes [default: 1048576]
```
Default is 1 MiB (1,048,576 bytes). Overridable by the user.
**Implementation:** The `finger()` and `finger_raw()` functions accept a `max_response_size: u64` parameter. Replace `stream.read_to_end(&mut buf)` with `stream.take(max_response_size).read_to_end(&mut buf)`.
**Truncation behavior:** If the response reaches the cap, return what was read and print a warning to stderr:
```
digit: warning: response truncated at 1048576 bytes (use --max-size to increase)
```
This is a warning, not an error -- the partial response is still printed to stdout. Exit code remains 0.
**How the caller detects truncation:** `finger()` / `finger_raw()` return the data they read. The caller compares `buf.len()` to `max_response_size` -- if equal, the response was likely truncated (it read exactly the cap). Print the warning from `main.rs`.
**Testing:** Integration test with a mock server that sends more bytes than the cap, verifying the response is truncated to the cap size.
## 2. Raw Output Mode
Write raw response bytes to stdout without UTF-8 decoding.
**New CLI flag:**
```
--raw Write raw response bytes to stdout without UTF-8 decoding
```
**Implementation:** Add `finger_raw()` to `protocol.rs` that returns `Vec<u8>` instead of `String`. Refactor `finger()` to call `finger_raw()` internally and apply `String::from_utf8_lossy`.
```rust
pub fn finger_raw(query: &Query, timeout: Duration, max_response_size: u64) -> Result<Vec<u8>, FingerError> { ... }
pub fn finger(query: &Query, timeout: Duration, max_response_size: u64) -> Result<String, FingerError> {
let bytes = finger_raw(query, timeout, max_response_size)?;
Ok(String::from_utf8_lossy(&bytes).into_owned())
}
```
**CLI behavior:** When `--raw` is set, call `finger_raw()` and write bytes to stdout via `std::io::stdout().write_all()`. When not set, call `finger()` as today. Truncation warning goes to stderr regardless.
**Testing:** Integration test verifying that raw mode preserves non-UTF-8 bytes (no replacement characters).
## 3. Shell Completions
Generate shell completions via a `completions` subcommand.
**New dependency:**
```toml
clap_complete = "4"
```
**CLI structure:** Add an optional subcommand to the `Cli` struct:
```rust
#[derive(Subcommand)]
enum Command {
/// Generate shell completions
Completions {
/// Shell to generate completions for
shell: clap_complete::Shell,
},
}
```
The `Cli` struct gets `#[command(subcommand)] command: Option<Command>`. When `Some(Command::Completions { shell })`, generate completions to stdout via `clap_complete::generate()` and exit. When `None`, proceed with normal finger query.
**Supported shells:** bash, zsh, fish, powershell, elvish (all handled by `clap_complete::Shell`).
**Usage examples:**
```bash
digit completions bash > ~/.bash_completion.d/digit
digit completions zsh > ~/.zfunc/_digit
digit completions fish > ~/.config/fish/completions/digit.fish
```
## 4. Documentation
Incremental documentation with each feature, plus a final pass.
### Final pass additions
**`src/lib.rs`** -- crate-level `//!` doc comment:
- One-line description
- What the crate provides (query parsing, wire format, TCP client)
- `no_run` example showing `Query::parse` -> `finger()` -> print
- Links to RFC 1288 and RFC 742
**`src/query.rs`** -- module-level `//!` doc comment. Rustdoc example on `Query::parse` showing both success and error cases.
**`src/protocol.rs`** -- module-level `//!` doc comment. Rustdoc examples on `build_query_string` (compilable), `finger` (`no_run`), `finger_raw` (`no_run`).
**`README.md`** -- update:
- Add `--raw` and `--max-size` to options table
- Add "Shell completions" section with per-shell install instructions
- Add docs.rs badge/link for library documentation
### docs.rs build
No special `Cargo.toml` configuration needed. Publishing v0.3.0 to crates.io triggers a docs.rs build automatically. The crate-level doc comment and per-item docs will populate the docs.rs pages.
## Files Changed
| `Cargo.toml` | Add `clap_complete` dependency, bump version to 0.3.0 |
| `src/lib.rs` | Crate-level `//!` documentation |
| `src/query.rs` | Module-level `//!` doc, rustdoc examples |
| `src/protocol.rs` | Add `finger_raw()`, `max_response_size` parameter, module docs, rustdoc examples |
| `src/main.rs` | `--max-size` flag, `--raw` flag, `completions` subcommand, truncation warning |
| `tests/integration.rs` | Tests for size cap and raw mode |
| `README.md` | New options, shell completions section, docs.rs link |
## Non-breaking API note
The `finger()` signature gains a `max_response_size` parameter. This is a breaking change for library consumers. Combined with the new `finger_raw()` function, this warrants a minor version bump to 0.3.0.