Contributing to servo-fetch

August 2, 2026 · View on GitHub

Thank you for considering contributing to servo-fetch.

If your contribution is not straightforward, please open an issue first to discuss the change before submitting a PR.

Development setup

Requires Rust 1.88.0+ (see rust-version in Cargo.toml).

git clone https://github.com/konippi/servo-fetch
cd servo-fetch
cargo build

First build takes several minutes due to Servo compilation.

Useful commands

cargo run -- "https://example.com"                          # Markdown output
cargo run -- "https://example.com" --format json            # JSON output
cargo run -- "https://example.com" --format png -o page.png # Screenshot
cargo run -- "https://example.com" --js "document.title"    # JS execution
cargo test                                                  # Run tests
cargo test -- --ignored                                     # Run Servo+network tests (slow)
cargo clippy                                                # Lint (pedantic)
cargo +nightly fmt                                          # Format
cargo deny check                                            # License & advisory check
taplo fmt                                                   # Format TOML files (install: cargo install taplo-cli --locked)
typos                                                       # Spell check

For exact CI parity (with --locked, CI profile, etc.), use these cargo aliases:

cargo lint        # CI cargo-clippy
cargo test-ci     # CI cargo-test (unit/integration)
cargo test-doc    # CI cargo-test (doc)
cargo test-e2e    # CI e2e (Servo-backed)

Build/test run on stable. Format requires nightly rustfmt for unstable imports_granularity / group_imports; one-time: rustup toolchain install nightly --component rustfmt --profile minimal.

Profiling

cargo build --profile profiling produces a release-optimized binary with debug symbols and thin LTO for use with cargo flamegraph or perf record.

Coverage

cargo install cargo-llvm-cov
cargo llvm-cov --lib --tests

Benchmark harness (Python)

The benchmark harness in benchmarks/ is a separate Python package managed with uv. Requires Python 3.11+.

cd benchmarks
uv sync --group dev                           # Install deps
uv run pytest                                 # Run tests
uv run ruff check src tests tools             # Lint
./benchmarks/bench all                        # Full benchmark suite (~25 min)

See benchmarks/README.md for the full guide.

Language bindings

The bindings live outside the cargo workspace and each has its own dev loop and README. The single source of truth for versions is [workspace.package].version in Cargo.toml (bumped by release-plz); the Node package.json versions are 0.0.0-development placeholders that the release workflow fills from the release tag, so they never need hand-editing.

Python (bindings/python/) — uv, Python 3.11+:

cd bindings/python
uv sync --group all --no-install-project  # venv + dev deps
uv run --no-sync maturin develop          # build the extension
uv run --no-sync pytest                   # tests
uv run --no-sync ruff check python tests && uv run --no-sync ty check python  # lint + types

Node (bindings/node/) — pnpm, Node 22+:

cd bindings/node
pnpm install
pnpm run build            # tsdown → dist (ESM + CJS + d.ts)
pnpm test                 # vitest
pnpm run typecheck && pnpm run lint   # tsc + biome

Commit conventions

This project uses Conventional Commits. The CHANGELOG.md is generated from these by release-plz.

feat: add PDF output support
fix: handle empty body in extract
refactor: simplify bridge error handling

Breaking changes

Mark breaking changes with ! in the subject — for example, feat(api)!: split sync and async or refactor(error)!: rename Error::Timeout. The subject marker keeps the breaking nature visible in commit logs, PR titles, and the auto-generated changelog.

Pull request guidelines

  • Keep PRs focused on a single change
  • Ensure cargo clippy, cargo +nightly fmt --check, and cargo test pass with zero warnings
  • Run cargo test -- --ignored if your change affects Servo integration or network behavior
  • Update documentation if behavior changes

Use of AI

AI tools (e.g. Claude Code, Kiro) can be useful for generating code. However, you remain responsible for any code you publish, and we are responsible for any code we merge and release. A few expectations:

  • Human in the loop. Do not submit pull requests created autonomously by AI agents. We will close any PR we believe was created without a human author who understands the change.
  • Write PR descriptions and replies yourself. Describe the change and reply to review comments in your own words. Do not paste AI output as a reply to maintainers. We may hide comments we believe are AI-generated.
  • Disclose AI context when you quote it. If you paste output from an AI tool into an issue or PR, put it in a > quote block and add your own commentary explaining why it is relevant.

Issue labels

We use four label categories:

  • type: * — what kind of work, aligned with Conventional Commits: type: bug, type: feature, type: docs, type: refactor, type: perf, type: test, type: deps, type: ci, type: build, type: security
  • component — area of the codebase: cli, mcp, skill, benchmark
  • status — workflow state: good first issue, help wanted, needs triage, needs info
  • resolution — closing reason: duplicate, wontfix

Start with good first issue if you are new to the project.

Labels are declared in .github/labels.yml and synced by the Sync Labels workflow. To propose a new label, open a PR editing that file.

Reporting bugs

Please use the bug report template and include:

  • Steps to reproduce
  • Expected vs actual behavior
  • Output of servo-fetch --version
  • OS info

License

By contributing, you agree that your contributions will be licensed under the MIT License.