# Contributing to stream-rs
Thanks for your interest in improving `stream-rs`. This is a small, focused
crate: the low-level plumbing that turns a raw byte stream into usable LLM
values. Contributions that keep it correct, spec-compliant, and dependency-free
are very welcome.
## Ground rules
- **Zero core dependencies.** The default build must not add runtime
dependencies. Anything optional goes behind a Cargo feature (as `stream` does
with `futures-core`).
- **Spec first.** The SSE parser follows the
[WHATWG event-stream algorithm](https://html.spec.whatwg.org/multipage/server-sent-events.html).
Behaviour changes that diverge from the spec need a clear rationale.
- **Chunk-boundary invariance.** Any incremental parser change must preserve the
core property: *the same input split at any byte boundary yields identical
output*. This is asserted by tests and by the fuzz targets.
- **Document public items.** `missing_docs` is a warning and CI treats warnings
as errors, so every public item needs a doc comment.
## Local checks (what CI runs)
Before opening a PR, run the same checks CI enforces:
```sh
# Format (CI runs --check)
cargo fmt --all
# Lint: clippy with pedantic lints, warnings as errors
cargo clippy --all-features --all-targets -- -D warnings
# Tests, including doctests, across all features
cargo test --all-features
# Make sure the examples still reassemble their streams correctly
cargo run --example openai_stream
cargo run --example anthropic_stream
cargo run --example gemini_stream
# Minimum supported Rust version (the crate targets 1.70)
# rustup toolchain install 1.70
cargo +1.70 build --all-features
```
### Benchmarks
```sh
cargo bench
```
Criterion reports MB/s for both a single bulk `feed` and realistic 64-byte
ragged chunks.
### Fuzzing
The fuzz crate lives in `fuzz/` and needs nightly + `cargo-fuzz`:
```sh
cargo install cargo-fuzz --locked
cargo +nightly fuzz run sse_parser
cargo +nightly fuzz run json_splitter
```
Each target asserts that arbitrary input never panics and that splitting the
input at a fuzzer-chosen point produces the same output as feeding it whole.
## Adding a provider accumulator
Accumulators live in `src/accumulators/`. They are deliberately JSON-library
agnostic: they accept already-parsed primitive pieces and fold them into the
final value. When adding one:
1. Add `src/accumulators/<provider>.rs` with a doc comment, a runnable doctest,
and `#[must_use]` on constructors/getters where appropriate.
2. Register it in `src/accumulators/mod.rs`.
3. Add tests to `tests/accumulators.rs`.
4. Add a runnable, no-network example to `examples/`.
5. Add a row to the feature table in `README.md` and a note to `CHANGELOG.md`.
## Commit / PR conventions
- Keep PRs focused; one logical change per PR where possible.
- Update `CHANGELOG.md` under `## [Unreleased]`.
- Make sure `cargo fmt`, `clippy`, and `cargo test --all-features` are clean.
## License
By contributing you agree that your contributions are licensed under the MIT
license, the same as the rest of the project.