Contributing to llmtrim

July 27, 2026 · View on GitHub

Thanks for your interest! llmtrim is a static, deterministic LLM prompt compressor: zero auxiliary model calls, every transform measured with the real target tokenizer.

By participating you agree to the Code of Conduct.

Ground rules

Four principles guide every change:

  • Simplicity first: minimum code that solves the problem; no speculative abstraction.
  • Surgical changes: touch only what the change requires.
  • Code universally: text processing must handle any language/locale, not just English (detect the language, use the matching resource; prefer Unicode-aware operations).
  • Goal-driven: turn the task into a verifiable test, then make it pass.

Development

The standard check loop (run all three before pushing):

cargo fmt
cargo clippy --all-targets
cargo nextest run --profile ci

Notes:

  • Use cargo nextest run, not cargo test: it runs in parallel and prints compact output. --profile ci matches the GitHub Actions job (see .config/nextest.toml).
  • Do not pass -- -D warnings to clippy locally. warnings = "deny" is already set in the workspace [lints.rust], and adding the flag forks the build cache between clippy and test. CI still runs clippy with -D warnings.
  • Default features already include intercept and mcp. Pass feature flags only when you intentionally change that set (e.g. --features live for the bench network path).

The suite is deterministic and hits no network. cargo build --features live builds the optional bench network path (async-openai + tokio); async is confined to that path and is not allowed in the core compression stages.

Before the first push that opens a PR, also check coverage of the files you changed:

cargo llvm-cov nextest --features intercept,mcp --summary-only

CI runs fmt, clippy, and the test suite on Linux, macOS, and Windows. Keep all three green.

Enable the local git hooks (mirror of CI plus a gitleaks secret scan; needs gitleaks or Docker):

git config core.hooksPath .githooks

Adding a compression stage

Stages implement the Transform trait (crates/llmtrim-core/src/gate.rs) and are assembled in stages_for (crates/llmtrim-core/src/lib.rs). A stage:

  1. Declares a GateKind: InputTokens (reverted if it doesn't reduce tokens), OutputShaping, or Structural.
  2. Mutates the JSON-backed Request at JSON-pointer addresses (lossless by construction for any field it doesn't touch).
  3. Adds a config flag in DenseConfig (crates/llmtrim-core/src/config.rs) and is wired into a preset.
  4. Ships with unit tests proving the token win and quality behavior.

Lossy stages stay off by default and are quality-checked offline (see README → Configuration and The numbers).

Editing the user's config file

Read with toml, write with toml_edit, and never write back a parsed toml::Value.

config.toml is hand-edited, so it carries comments, key order, and spacing that belong to the user. toml_edit edits the document in place and keeps them; parsing to toml::Value and re-serializing throws them away. That failure is silent, since the output is valid TOML that round-trips cleanly, so tests pass while the user's comments disappear.

Before a large change

Open an issue first for anything beyond a small fix. Describe the problem and the approach you have in mind, and wait for a maintainer to confirm the direction. A short agreement up front saves a large PR from a redesign in review. New user-facing surfaces (a CLI mode, an MCP tool, an output channel) and any change to the published llmtrim-core public API need this step.

Reporting vs. implementing

Filing an issue does not commit you to writing the code. Tell us which you mean: the feature-request template has a checkbox, or just say so in the issue.

If you want to implement it, comment to claim it and a maintainer will assign you; an assigned issue is yours until it goes quiet for about two weeks. If you only want to report it, a maintainer or another contributor may pick it up. Either way, for a feature we agree the approach in the issue before a PR is opened, so a maintainer implementing your request will post the intended design on the issue first and give you a chance to respond.

Pull requests

  • One logical change per PR; every changed line should trace to the stated goal.
  • Link the issue the PR addresses (Closes #123).
  • Add or update tests for new behavior.
  • Add a CHANGELOG.md entry under ## [Unreleased] for any user-observable change, written for users. Skip it only for invisible changes (cosmetic, docs, tests, no-op refactors).
  • Run the check loop above before pushing.
  • Fill in the PR template.

Commit hygiene

One coherent change per commit, with a message that explains it for a reviewer. Fold every fixup, "wip", or review-fix tweak into the commit it belongs to before you push. Force-push a rewritten branch with --force-with-lease, never a bare --force.

Review

A maintainer reviews each PR and may ask you to split a large change into smaller pieces or to move ecosystem-specific logic out of llmtrim-core. Expect a first response within a week. A request for changes is about the code, not about you.

Sign your commits (DCO)

We use the Developer Certificate of Origin. Sign off every commit:

git commit -s -m "your message"

The Signed-off-by line certifies you wrote the patch or have the right to submit it under the project license.

License

By contributing, you agree your contributions are licensed under MPL-2.0.

You also grant François Kiene, and his successors and assigns, the right to license your contribution under any other license, including proprietary or commercial terms, so the project can relicense or offer a commercial dual-license later without contacting every contributor. You keep the copyright to your contribution. This is separate from your DCO sign-off, which only certifies the origin of your work.