Metadata-Version: 2.5
Name: dagwick
Version: 0.2.0
Summary: The wick that keeps your DAGs lit: DAG quality scores, a fleet view, and fixes you can act on, inside the Airflow 3 UI.
Project-URL: Homepage, https://github.com/ardalan-jalal/dagwick
Project-URL: Repository, https://github.com/ardalan-jalal/dagwick
Project-URL: Issues, https://github.com/ardalan-jalal/dagwick/issues
Project-URL: Changelog, https://github.com/ardalan-jalal/dagwick/blob/main/CHANGELOG.md
Author: The Dagwick Authors
License-Expression: MIT
License-File: LICENSE
Keywords: airflow,airflow-plugin,apache-airflow,dag,data-quality,linting
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Plugins
Classifier: Environment :: Web Environment
Classifier: Framework :: Apache Airflow
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# Dagwick

![Dagwick: grade your Airflow DAGs from A to F, right inside the Airflow UI](https://raw.githubusercontent.com/ardalan-jalal/dagwick/main/docs/banner.png)

## Setup

**1. Install** it where Airflow runs:

```bash
pip install dagwick
```

Using Docker? Add `dagwick` to your Airflow image's `requirements.txt`.

**2. Restart** the Airflow api-server.

**3. Open Airflow.** You now have:

- a **Dagwick** tab on every DAG page, and
- a **Dagwick** page in the sidebar that grades all your DAGs.

That's it. There is nothing to configure.

## What you get

- **A score and a grade for every DAG.** 20 checks in 7 categories:
  reliability, observability, ownership, scheduling, structure, performance
  and security. Each check that doesn't pass tells you how to fix it. See
  [what it checks](https://github.com/ardalan-jalal/dagwick/blob/main/docs/checks.md).
- **Checks that read your DAG file without running it:** `Variable.get` at
  parse time, deprecated Airflow imports, hard-coded secrets (the value is
  never shown), and sensors that hold a worker slot while they wait.
- **Run health** next to the score: success rate, retries, typical run time
  and its trend over the last 30 days. It never changes the score.
- **Score history:** the score of each of the last 20 versions of a DAG, and
  which checks started or stopped passing at each step.
- **A fleet page** that grades all the DAGs you can see and shows the most
  common issues.
- **`dagwick check` and a pre-commit hook** to grade DAG files before they are
  merged. See [Check DAGs before they are merged](#check-dags-before-they-are-merged).
- **Break a check on purpose, with a reason.** Some DAGs need `catchup=True`
  or no retries. See [Acknowledge a check on purpose](#acknowledge-a-check-on-purpose).

Experimental and off by default: the lantern can dress up for holidays like
Newroz, Eid, Christmas and Halloween ([seasonal moods](https://github.com/ardalan-jalal/dagwick/blob/main/docs/moods.md)).

![The Dagwick tab on a DAG](https://raw.githubusercontent.com/ardalan-jalal/dagwick/main/docs/screenshots/dag-tab.png)

![The Dagwick fleet page](https://raw.githubusercontent.com/ardalan-jalal/dagwick/main/docs/screenshots/fleet.png)

## Acknowledge a check on purpose

Some DAGs break a check for a good reason: an ingest DAG uses `catchup=True` to
backfill the days it missed during an outage, or a task that inserts without
de-duplicating must never retry. Tell Dagwick with a comment in the DAG file:

```python
# dagwick: ack <check> -- <reason>
```

For example:

```python
DAG(
    "daily_ingest",
    catchup=True,  # dagwick: ack catchup -- backfills one file per missed day
    default_args={"retries": 0},  # dagwick: ack retries -- inserts are not idempotent
)
```

After Airflow parses the file again, the check is shown greyed out with your
reason, and it no longer counts toward the score. It is never hidden, and the
fleet page counts it as "acknowledged". To score the check again, delete the
comment.

- Put the comment anywhere in the file. It applies to every DAG in that file.
- One comment can name several checks: `# dagwick: ack retries, catchup -- <reason>`.
- The reason after `--` is required. Without it the comment is ignored.
- Dagwick reads the comment from the DAG's source code; it never runs the file.

**Checks you can acknowledge** (use the id in the comment):

| Check | Id | The reason must say |
| --- | --- | --- |
| Tasks retry on failure | `retries` | why the DAG breaks it on purpose |
| Retries are visible | `retry_alerts` | why the DAG breaks it on purpose |
| Has a schedule | `schedule` | why the DAG breaks it on purpose |
| No surprise backfills | `catchup` | why the DAG breaks it on purpose |
| Bounded parallel runs | `max_active_runs` | why the DAG breaks it on purpose |
| Split into steps | `decomposition` | why the DAG breaks it on purpose |
| Someone hears about failures | `failure_alerts` | where failures are alerted instead, e.g. a central listener or a Grafana rule |
| Stops after repeated failures | `auto_pause` | what stops the DAG when it keeps failing, e.g. on-call pausing it by hand |
| Sensors free their worker slot | `sensor_slots` | why the sensor must keep its worker slot, e.g. it needs sub-minute reaction |

Every other check (owner, docs, tags, timeouts, naming, file name, imports,
parse time, `Variable.get` and secrets) **can't be acknowledged**: each one
protects something every DAG needs. A comment for one of them is ignored, and
the Dagwick tab says so. Run `./dev/run.sh` from a clone of this repository to
see a demo DAG (`demo_acknowledged_ingest`) with every case.

## Check DAGs before they are merged

`dagwick check` grades DAG files with the same checks as the UI and can fail a
pull request below a chosen grade:

```bash
dagwick check dags/ --min-grade C     # exit 1 if any DAG is below C
dagwick check dags/my_dag.py --json   # machine-readable report
```

It needs Airflow installed next to it, and it **imports the DAG files**, so
their top-level code runs, the same as in Airflow's DAG processor. Use it on a
developer machine or in CI. The Airflow plugin itself never runs DAG code.

Exit codes: `0` all good, `1` a DAG is below `--min-grade`, `2` a file failed
to load.

### pre-commit

```yaml
- repo: https://github.com/ardalan-jalal/dagwick
  rev: v0.2.0
  hooks:
    - id: dagwick
      args: [--min-grade, C]   # default: D
```

The hook uses `language: system`, so run pre-commit from an environment where
Airflow and Dagwick are installed.

## Requirements

- Apache Airflow 3.1 or newer
- Python 3.10 – 3.15

Dagwick has no dependencies of its own, so installing it never changes your
other packages. It is read-only and only shows each user the DAGs they can
already see.

## Remove

```bash
pip uninstall dagwick
```

Then restart the api-server.

## More

- [Seasonal moods, and how to turn them off](https://github.com/ardalan-jalal/dagwick/blob/main/docs/moods.md)
- [What it checks, and how to add your own checks](https://github.com/ardalan-jalal/dagwick/blob/main/docs/checks.md)
- [Roadmap](https://github.com/ardalan-jalal/dagwick/blob/main/ROADMAP.md)
- [Security](https://github.com/ardalan-jalal/dagwick/blob/main/SECURITY.md) · [Contributing](https://github.com/ardalan-jalal/dagwick/blob/main/CONTRIBUTING.md) · [Changelog](https://github.com/ardalan-jalal/dagwick/blob/main/CHANGELOG.md) · [Releasing](https://github.com/ardalan-jalal/dagwick/blob/main/RELEASING.md)
- License: [MIT](https://github.com/ardalan-jalal/dagwick/blob/main/LICENSE)
