Architecture

Overview

resqui is built around three concepts: plugins, executors, and a configuration-driven pipeline. The CLI wires them together but the components are independent.

CLI (cli.py)
 │
 ├─ Configuration (config.py)      ← JSON file or built-in defaults
 │
 ├─ GitInspector (cli.py)          ← extracts metadata from the repo
 │
 ├─ IndicatorPlugin subclasses     ← one per tool (HowFairIs, Gitleaks, …)
 │    └─ uses Executor             ← PythonExecutor or DockerExecutor
 │
 └─ Summary (core.py)              ← aggregates CheckResults → JSON-LD

Plugin system

Every quality check is a subclass of IndicatorPlugin. The CLI discovers plugins at runtime via __subclasses__() — no registration step is needed. Each plugin declares a list of indicator names in its indicators class attribute; each name corresponds to a method of the same name on the class.

A single plugin instance is reused for all of its indicators within one run, which means Docker images are pulled and Python venvs are created only once per plugin class.

Executor design

Plugins delegate subprocess execution to one of two executors:

PythonExecutor creates a temporary venv via the stdlib venv module, installs the required packages with pip, and runs Python snippets inside it. The venv is torn down in __del__. This approach keeps plugin dependencies completely isolated from the resqui installation.

DockerExecutor pulls a Docker image on construction and runs commands inside containers via docker run. The Docker daemon is the only external dependency.

Both raise ExecutorInitError when they cannot initialise (Docker unavailable, pip install failure, etc.). The CLI catches this and skips all indicators belonging to that plugin with a warning, allowing the rest of the run to continue.

Why not extend IndicatorPlugin with Python magic?

Subclassing is used purely as a discovery mechanism — __subclasses__() gives a flat list of all available plugins without any import-side-effect registration. There is no __init_subclass__ hook or metaclass. This keeps plugin authorship simple: write a class, import it, and it is automatically available.

Output format

Summary.to_json() serialises results as JSON-LD conforming to the EVERSE Research Software Quality Assessment schema (https://w3id.org/everse/rsqa/0.0.1/). Each CheckResult maps to one entry in the checks array with linked indicator, software, and status IRIs.