Thank you for considering a contribution! IntelCLI aims to stay a small, fast, lawful, and well-tested OSINT toolkit — contributions that keep that spirit are very welcome.
- Lawful sources only. Every new data source must use a publicly documented protocol or API (standard WHOIS, public DNS, a site's own public HTTP/HTTPS endpoint, or a free/public API). PRs that scrape a site in violation of its terms of service, bypass authentication, or otherwise enable unauthorized access will not be merged.
- No secrets in source. API keys are always optional and always read from
the user's local config file via
ConfigManager— never hardcoded. - Test everything. New services and commands need unit tests (network
mocked) and, for commands, an integration test using Typer's
CliRunner. We maintain 90%+ coverage; PRs that drop coverage below that will be asked to add tests before merge.
git clone https://github.com/intelcli/intelcli.git
cd intelcli
pip install -e ".[dev]"Run the full quality gate before opening a PR:
ruff check .
black --check .
mypy src
pytest --cov=intelcli --cov-report=term-missingSee docs/architecture.md for the full layered
design (cli → commands → services → models/storage/utils). In short:
services/— one class per external data source. Pure logic, returns a typed Pydantic model, raises fromexceptions.py. Noprint(), no Rich, no Typer.commands/— argument parsing, calling services, rendering Rich output, exporting, and history logging. Thin orchestration only.models/— Pydantic models shared across layers.
- Add Pydantic model(s) to
models/. - Add service(s) to
services/with narrow, single-purpose public methods. - Add a
commands/<name>.pymodule exposing a plain function (not a nested Typer app, unless the command needs sub-commands likehistory/config). - Register it in
cli/app.pyviaapp.command("name")(your_function). - Add unit tests for the service(s) under
tests/unit/. - Add an integration test for the command under
tests/integration/, mocking the service layer so the test is deterministic and offline. - Update
docs/usage.mdwith examples.
Follow the try/except-and-append-to-errors pattern already used in
commands/domain.py and commands/ip.py: a failing source should never take
down the whole command. Catch intelcli.exceptions.IntelCLIError (or a
specific subclass) and append a human-readable message to the report's
errors list.
- Python 3.12+, full type hints,
from __future__ import annotations. - Formatted with Black (line length 100).
- Linted with Ruff (
E, F, I, UP, B, SIM, C4rule sets). - Docstrings on every public class/function using a concise, factual style (see existing modules for the convention).
- Prefer composition over inheritance; prefer small, focused classes.
- Fork the repo and create a feature branch.
- Make your changes with tests.
- Run the full quality gate (see above) — all checks must pass.
- Open a PR describing what changed and why. Link any relevant issue.
- Be responsive to review feedback; small, focused PRs merge fastest.
Please do not open a public issue for security vulnerabilities. Instead, email the maintainers directly (see the repository's security policy) so a fix can be prepared before public disclosure.
Be respectful, assume good faith, and keep discussions focused on the technical merits. We want IntelCLI's community to be as welcoming as its codebase is clean.