Airflow Sketcher
Airflow Sketcher is an Airflow 3.1+ plugin to build Airflow DAGs from Excelidraw drawings.
What is included
src/airflow_sketcher/dag_factory.py: Excalidraw to Airflow DAG parser/importer.src/airflow_sketcher/plugins/builder.py: Airflow plugin exposing the Excalidraw builder UI.src/airflow_sketcher/sitecustomize.py: optional startup hook for importer registration.examples/airflow/: thin wrapper files that can be mounted into an Airflowdags/andplugins/folder.tests/: unit tests and real.excalidrawfixtures.
Local development
With uv (recommended)
uv sync --all-extras
uv run python -m unittest discover -s tests
With traditional venv
python3 -m venv .venv
source .venv/bin/activate
pip install -e '.[dev]'
python3 -m unittest discover -s tests
Plugin functionality
The AirflowSketcherPlugin adds an Excalidraw-based DAG builder page to the Airflow UI under /airflow-sketcher.
Key capabilities:
- Renders an interactive Excalidraw canvas in Airflow for creating and editing DAG diagrams.
- Saves diagrams as
.excalidrawfiles in the AirflowDAGS_FOLDER. - Enforces safe filenames (letters, numbers,
.,_,-) and prevents path traversal. - Auto-appends the
.excalidrawextension when omitted. - Loads existing scenes and preserves selected visual app state (for example grid and viewport settings).
- Derives DAG metadata (such as
dag_idandschedule) fromdag:text blocks in the drawing. - Resolves a diagram for an existing DAG by checking DAG params (
excalidraw_source_file) first, then scanning.excalidrawfiles. - Registers the Excalidraw importer at startup so saved diagrams can be translated into Airflow DAG objects.
How to open the plugin
You can open the builder in two ways:
- Dedicated icon/view:
Open the Airflow top navigation entry named
Airflow Sketcher(with the plugin icon). This opens the builder home at/airflow-sketcher/. - From a DAG created by this plugin:
Open DAG details and click the
Builderexternal view. It opens/airflow-sketcher/?dag_id=<your_dag_id>and tries to load the corresponding.excalidrawsource file.
First DAG
Create a very simple DAG with two empty tasks in the builder UI:
- Open Airflow and navigate to
/airflow-sketcher. - Add one text element for DAG metadata with this content:
dag:
dag_id=first_two_tasks
schedule=@daily
- Draw two rectangles (each rectangle is a task).
- Add text inside the first rectangle:
task_a
- Add text inside the second rectangle:
task_b
- Draw an arrow from
task_atotask_b. - Save as
first_two_tasks.excalidraw.
Notes:
- You do not need to set
classfor this example. If omitted, tasks default toEmptyOperator. - If no
dag_idis provided in thedag:block, the file name (without extension) is used as the DAG ID.
Examples
1. The simplest DAG (two empty tasks)
Use these text blocks:
dag:
dag_id=1_simple_two_tasks
schedule=@daily
Task rectangle 1:
task_a
Task rectangle 2:
task_b
Then draw one arrow: task_a -> task_b.
In the Airflow UI, it should look like:
2. DAG with BashOperator and PythonOperator
Use these text blocks:
dag:
dag_id=2_bash_and_python
schedule=@daily
vars:
def greet(**kwargs):
print("hello from python task")
Task rectangle 1:
bash_task
class = operators.bash.BashOperator
bash_command = 'echo "hello from bash"'
Task rectangle 2:
python_task
class = operators.python.PythonOperator
python_callable = greet
Then draw one arrow: bash_task -> python_task.
In the Airflow UI, it should look like:
Example files
Ready-to-use .excalidraw files are available in examples/excalidraw/:
Supported sections and task attributes
The parser reads specific text blocks from the Excalidraw scene.
dag: section
Use a text element starting with dag: and put one key=value pair per line.
Supported keys:
dag_id: explicit DAG identifier.schedule: DAG schedule string (for example@dailyor cron expression).
If dag_id is omitted, the importer uses the .excalidraw filename (without extension). If schedule is omitted, it defaults to None.
Example:
dag:
dag_id=my_first_dag
schedule=@daily
imports: section
Use a text element starting with imports: to declare Python imports used by tasks.
- Only Python import statements are supported in this block.
import ...andfrom ... import ...are both supported.- Imported names are available when evaluating task attributes (for example
class,python_callable,op_args,op_kwargs). - You can use multiple
imports:blocks in the same diagram.
Default import behavior:
- No custom project modules are imported automatically. Add them in
imports:when needed. - Python builtins are available when evaluating attribute values.
- For the
classattribute only, theoperators.prefix is treated as shorthand forairflow.providers.standard.operators..- Example:
class = operators.bash.BashOperatorresolves toairflow.providers.standard.operators.bash.BashOperator.
- Example:
- If
classis omitted, the task defaults toairflow.providers.standard.operators.empty.EmptyOperator.
Example:
imports:
from airflow.providers.standard.operators.bash import BashOperator
import shared_funcs
vars: section
Use a text element starting with vars: to define Python variables/functions reused in task attributes.
- Contents are executed as Python code.
- Names defined here are available when evaluating task attributes (for example
python_callable=my_func).
Example:
vars:
def my_func(**kwargs):
print("hello")
Task text format (inside each rectangle)
Each task rectangle is configured by its associated text content.
Supported attributes:
- First non-empty line: task id (required), for example
task_a. class(optional): operator class path or imported symbol.- Default when omitted:
operators.empty.EmptyOperator.
- Default when omitted:
- Any other
key=valuelines are passed as operator keyword arguments.
Attribute values support:
- Python literals (strings, numbers, booleans, lists, dicts).
- Names imported or defined in
vars:. - Multi-line Python snippets. If a snippet is statements plus a final expression, that expression becomes the value. You can also assign to
resultand that value is used.
Example:
task_python
class = operators.python.PythonOperator
python_callable = my_func
op_kwargs = {"name": "world"}
Airflow integration
Install the package into your Airflow image or environment, then expose the thin wrapper files from examples/airflow/ inside the Airflow plugins/ and dags/ directories.
Installation
From PyPI:
pip install airflow-sketcher
From sources (editable/development mode):
# With uv
uv pip install -e .
# With pip
pip install -e .
Typical setup
- Install the package (see above).
- If you are not installing with
pip, copy the wholeairflow_sketcherpackage directory into Airflow'splugins/folder (for example asplugins/airflow_sketcher/). - Copy
examples/airflow/plugins/excalidraw_builder_plugin.pyinto Airflow'splugins/folder. - Copy
examples/airflow/plugins/sitecustomize.pyinto Airflow'splugins/folder if you want automatic importer registration at process startup. - Copy
examples/airflow/dags/airflow_dag_generator.pyinto Airflow'sdags/folder if you want a Python entrypoint that re-exports the factory symbols.
Testing strategy
The unit tests install lightweight Airflow stubs when Apache Airflow is not installed. That keeps parser and factory coverage runnable in a plain Python environment while still allowing the same package to run under real Airflow.
Release files for airflow-sketcher 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| airflow_sketcher-0.1.0.tar.gz | 20.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| airflow_sketcher-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 38.2 kB
Release files / airflow_sketcher-0.1.0.tar.gz
| Download URL | airflow_sketcher-0.1.0.tar.gz |
|---|---|
| Size | 20.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c70a988c675cbe4b933664005b15d7b394da20fd6add2da83bf7da04a8e428a7
|
|
BLAKE2b-256 checksum How to use checksums |
13de07d45bd8abd08cd8bec8634aa2bd724a977b2d9c119d2428722235a0f205
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|
Release files / airflow_sketcher-0.1.0-py3-none-any.whl
| Download URL | airflow_sketcher-0.1.0-py3-none-any.whl |
|---|---|
| Size | 17.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c8806c8dfad9c6be7251276c79c820e63c80ccf158dfa7d049cde0e6122d93cc
|
|
BLAKE2b-256 checksum How to use checksums |
62ab6c4e612116466b3c823507faeddd2ed171b1fcaca763282130713f9e234b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|