Skip to content

Contributing

github-actions[bot] edited this page Oct 28, 2026 · 2 revisions

Contributing

Development setup

git clone https://github.com/metalayerlab/mitm-proxy && cd mitm-proxy
uv sync                                  # Python >= 3.13: uv fetches it if needed
uv tool install pre-commit && pre-commit install -t pre-commit -t commit-msg
uv run pytest                            # all green before you start

Workflow

  1. Branch from main: feat/<topic> or dev/<topic>. Pushes build :<branch> images.
  2. Non-trivial change (a new feature or dependency, or a change to a public interface): write a design record first, and get it approved.
  3. Open a PR against main with a Conventional Commit title (feat: add retry to uploads). It becomes the squash commit and the CHANGELOG line: see Release Process.
  4. CI must be green: tests, lint, types, secret scan, manifests, and the wiki checks.
  5. A code owner reviews (review checklist), then squash-merge.

Never edit CHANGELOG.md or the version, and never push tags: release-please does that.

Code style

  • ruff (lint + format, line length 100) and mypy --strict decide formatting and typing. Don't argue with them in review.
  • Comments explain why. Logging goes through logging; only the CLI prints.
  • Settings go through config.SETTINGS. Secrets come from _FILE, and are never logged.
  • Prefer the standard library and existing dependencies. Justify every new one in the PR.

Project rules

  • One event loop, no threads. Everything is asyncio. Work that blocks the loop (CPU-heavy code, blocking I/O) stalls the whole proxy, in middleware too.
  • Never background a middleware hook. The pipeline awaits each hook in line; asyncio.create_task around one breaks backpressure. A test enforces it.
  • Protocol layers stay protocol layers. h1.py and h2.py produce IncomingRequests and Responders; only exchange.py builds flows, runs middleware and picks framing.
  • Errors: raise the types in errors.py. Upstream failures become 502/504 responses, never exceptions out of a connection. No assert in src/ (ruff S101).
  • Read the snapshot once. A connection uses the configuration snapshot current when it arrived; don't cache fields of Config elsewhere.
  • Never weaken verification or the allowlist "for testing": use upstream.extra_ca_file and test CAs instead.

Working with AI assistants

AI assistants are welcome and expected, under the same rules as anyone else:

  • They follow AGENTS.md. Each tool's own file (CLAUDE.md, GEMINI.md, .github/copilot-instructions.md, .cursor/rules/) points there.
  • Kick-off prompts: docs/ai/prompts.md.
  • The PR template asks how much was generated. Say so honestly: it tells the reviewer how closely to read.
  • A human who understands the change approves every PR. "The AI wrote it" is never a reason to merge.

Documentation

This wiki's source is docs/wiki/, in the repository. It's published to the GitHub wiki from main, so never edit the GitHub wiki directly: the next publish overwrites it.

  • Code and docs change in the same PR. AGENTS.md's "Docs map" says which page goes with which code, and CI fails a PR that changes watched paths without touching docs/wiki/. A reviewer, never the author, can add the no-docs-needed label when nothing user-visible changed.
  • The required pages and headings are in docs/wiki/.standard.toml (template-owned). Add pages freely, and link each one from _Sidebar.md.
  • Tables between <!-- generated:start/end --> markers come from the code: run uv run scripts/gen-wiki.py.
  • Link pages by name ([Quick Start](Quick-Start)), and repo files by full URL.
  • Check locally: python3 scripts/check-wiki.py.

Keeping AI context small

Assistants pay for what they read in every session, so the instruction files are written for that:

  • AGENTS.md holds the rules, tersely. The reasons live on these wiki pages. CI fails if AGENTS.md or a tool pointer file (CLAUDE.md, GEMINI.md, Copilot, Cursor) exceeds [context_budget] in docs/wiki/.standard.toml. That budget is template-owned: if it's genuinely too small, change it in project-template.
  • AGENTS.md's "Don't read" list (and the Read denies in .claude/settings.json) keep lock files, caches and generated output out of context. Add any large or generated path the project introduces.
  • docs/design/README.md indexes every design record, so an assistant reads one line per record instead of every record. CI checks the index is complete.
  • Pointer files only point: don't copy AGENTS.md content into them.

mitm-proxy

GitHub • Releases


📚 Getting Started

📖 Core Concepts

🔧 Configuration

🔒 Security

🆘 Help & Support

🧑‍💻 For Developers


🔑 Key Features

  • 🔍 Intercept only the hosts you list; tunnel the rest untouched
  • 🔀 HTTP/1.1 and HTTP/2 on both sides, bridged
  • 🧩 Python middleware: inspect, rewrite, answer or deny
  • 🔐 Its own root CA; origins always verified
  • 📈 Prometheus metrics and a read-only status API

🔗 Quick Links

Clone this wiki locally