duckorch

Asset-zentrierte Datenorchestrierung mit JSON-Ingestion, Partitionen, deklarativem Automation-Sensor, Snowflake-kompatiblem CREATE DYNAMIC ASSET, MCP-Server, Lineage und OpenLineage-Emission — alles auf DuckDB

Maintainer: nkwork9999

Installation und Laden

INSTALL duckorch FROM community;
LOAD duckorch;

Beispiel

LOAD duckorch;
-- 1. Set up state schema and register a directory of *.sql task files.
PRAGMA orch_init;
PRAGMA orch_register('./tasks/');
-- 2. Run the DAG (topological order, per-layer parallelism).
SET orch_max_parallel = 4;
PRAGMA orch_run;
-- 3. Asset-aware features (Phase 13+):
PRAGMA orch_asset_list; -- all registered Assets
PRAGMA orch_asset_partitions('analytics.daily'); -- per-partition status
PRAGMA orch_backfill('analytics.daily', '2026-01-01', '2026-12-31');
-- 4. Snowflake-compatible declaration (Phase 17):
PRAGMA orch_create_dynamic_asset(
'analytics.region_total',
'5 minutes',
'SELECT region, SUM(total) AS rt FROM analytics.daily GROUP BY region');
-- 5. Sensor — auto-materializes when upstream updates (Phase 15):
PRAGMA orch_sensor_set_interval(30);
PRAGMA orch_sensor_start;
-- 6. Mermaid lineage:
PRAGMA orch_visualize('lineage');
-- 7. JSON ingestion (Phase 19): nested JSON becomes flat parent/child
-- tables, and later-arriving columns are absorbed automatically.
PRAGMA orch_ingest_preview('orders.jsonl', 'raw.orders'); -- shape only
PRAGMA orch_ingest_run('orders/*.jsonl', 'raw.orders');
PRAGMA orch_ingest_run('orders.jsonl', 'raw.orders',
disposition = 'merge', primary_key = 'id');
PRAGMA orch_ingest_http('https://api.example.com/orders', 'raw.orders',
secret = 'orders_api', paginate = 'cursor',
records_path = 'data', cursor_path = 'meta.next',
cursor_param = 'cursor');

Über duckorch

duckorch ist ein DuckDB-nativer, Single-File-Asset-Orchestrator, der die deklarative Automation von Dagster und Snowflakes Semantik von CREATE DYNAMIC TABLE in ein LOAD duckorch; bringt. Ausgelegt, auf einem Laptop oder im Flugzeug ohne Cloud-Control-Plane zu laufen.

Aufgabendefinition (SQLMesh-artige Header in einfachen .sql-Dateien):

-- @asset name=analytics.user_stats
-- @asset_group sales
-- @partitions_by daily(start=2026-01-01)
-- @param partition_key:DATE
-- @automation eager AND NOT in_progress()
-- @freshness max_lag=60min
-- @check name=positive "SELECT MIN(rev) FROM ${asset}" expect gt 0
CREATE OR REPLACE TABLE analytics.user_stats AS
SELECT country, SUM(rev) AS rev
FROM analytics.clean_users
WHERE event_date = $partition_key
GROUP BY country;

Eingaben werden automatisch über sqlparser-rs extrahiert. $partition_key wird über DuckDB PREPARE gebunden (mehranweisungsfähig).

Fähigkeiten:

  • Tasks + DAG (Phase 0–9): verzeichnisgeladene SQL-Dateien, topologische Ausführung, Parallelität pro Schicht, Exponential-Backoff-Retry, Downstream- Skip, @test, Mermaid (lineage / dag / combined), OpenLineage- Ereignisse, tabellen- und spaltenweise Lineage mit Subtyp-Taxonomie, optionale Ad-hoc-Abfrageerfassung, DuckLake-bewusster OL-Namespace.

  • MCP-Server (Phase 11): duck-orch-mcp-stdio-Server (rmcp 0.3) mit 9 Tools für die Claude-Code-Integration (list_assets, run_pipeline mit Standard dry_run usw.).

  • Asset (Phase 13): @asset-Header befördern Ausgaben zu erstklassigen Assets in __orch__.assets mit Materialisierungshistorie, code_version- Hash und deklarierten Kanten. Abwärtskompatibel mit @outputs.

  • Partition (Phase 14): @partitions_by daily/static/multi, Bindung von $partition_key, orch_backfill, kalenderartige ✅⚪-ASCII-Ansicht.

  • AutomationCondition + Sensor (Phase 15): DSL (eager / on_cron / on_missing / freshness_violated / in_progress

    • & / | / !), @target_lag-Drossel, Hintergrund-std::thread- Sensor, der pollt und RunSingleTask automatisch auslöst, wenn Bedingungen erfüllt sind.
  • Freshness + Asset Check (Phase 16): @freshness max_lag=..., @check name=N "<SQL>" expect <op> <value> mit automatischem Lauf bei Erfolg und severity=error, das Downstream blockiert.

  • Snowflake CREATE DYNAMIC ASSET (Phase 17): PRAGMA orch_create_dynamic_asset(name, target_lag, sql) synthetisiert Asset + automation_condition='eager()', sodass der Sensor es aufnimmt. Die CLI duck-orch dynamic migrate-from-snowflake <dump> parst Snowflake- Dumps und registriert jeden Block (überspringt WAREHOUSE/REFRESH_MODE).

  • JSON-Ingestion (Phase 19): orch_ingest_run / orch_ingest_http normalisieren verschachteltes JSON in Parent-/Child-Tabellen (Structs werden in den Parent geflacht, Arrays werden zu Child-Tabellen, verknüpft über _orch_parent_id / _orch_index). Ein Schema-Ledger versioniert jede Form und nimmt hinzugefügte Spalten und erweiternde Typen über ALTER auf; inkompatible Änderungen lassen den Load mit benannter Spalte fehlschlagen. Schreibdispositionen append / replace / merge (primary_key-gesteuert, Kinder eingeschlossen). HTTP-Quellen unterstützen page / offset / cursor / link-Pagination, Bearer-Tokens aus einem DuckDB-Secret, Resume-Cursor und eine gemeldete Seitenobergrenze. Ein dreiteiliges Ziel (lake.raw.orders) lädt in einen angehängten Katalog, sodass DuckLake nur ein weiteres Ziel ist. Geladene Tabellen registrieren sich als Assets mit Lineage zurück zur Quell-URI.

3-Wege-Oberfläche: jede Funktion erreichbar über CLI (duck-orch ...), SQL (PRAGMA orch_*) und MCP (Claude Code).

Begleit-CLI: duck-orch mit den Unterbefehlen register / run / status / graph / test / validate / impact / lineage / schedule / asset / backfill / automation / sensor / check / dynamic, alle --json-fähig.

Zustandstabellen: __orch__.{tasks, runs, lineage_edges, column_lineage, task_edges, tests, schedules, assets, asset_materializations, asset_edges, asset_partitions, automation_evaluations, asset_checks, asset_check_results, ingest_schemas, ingest_schema_changes, ingest_loads, ingest_state, ingest_fetches}.

Architektur: dünner C++-Shim (ca. 3000 Zeilen, registriert PRAGMAs, führt SQL über eine Connection pro Thread aus, hostet den Sensor-Thread, stellt OptimizerExtension für Ad-hoc-Erfassung bereit) plus ein Rust-Workspace (orch_common / orch_dag / orch_lineage / orch_runtime / orch_ol / orch_ingest / orch_core / orch_cli / orch_mcp), der die gesamte Logik in Rust hält, während die C++-Schicht DuckDB-interne Aufrufe übernimmt.

Hinzugefügte Funktionen

function_name function_type description comment examples
orch_asset_health pragma NULL NULL
orch_asset_lineage pragma NULL NULL
orch_asset_list pragma NULL NULL
orch_asset_list_group pragma NULL NULL
orch_asset_materializations pragma NULL NULL
orch_asset_partitions pragma NULL NULL
orch_asset_partitions_calendar pragma NULL NULL
orch_asset_show pragma NULL NULL
orch_automation_simulate pragma NULL NULL
orch_automation_status pragma NULL NULL
orch_backfill pragma NULL NULL
orch_backfill_missing pragma NULL NULL
orch_build_dag scalar NULL NULL
orch_check_history pragma NULL NULL
orch_check_run pragma NULL NULL
orch_create_dynamic_asset pragma NULL NULL
orch_downstream_of scalar NULL NULL
orch_dynamic_list pragma NULL NULL
orch_dynamic_refresh pragma NULL NULL
orch_extract_io scalar NULL NULL
orch_hello scalar NULL NULL
orch_ingest_http pragma NULL NULL
orch_ingest_preview pragma NULL NULL
orch_ingest_reset pragma NULL NULL
orch_ingest_run pragma NULL NULL
orch_ingest_state pragma NULL NULL
orch_init pragma NULL NULL
orch_load_directory_json scalar NULL NULL
orch_parse_task scalar NULL NULL
orch_register pragma NULL NULL
orch_render_mermaid scalar NULL NULL
orch_restate pragma NULL NULL
orch_run pragma NULL NULL
orch_run_partition pragma NULL NULL
orch_sensor_set_interval pragma NULL NULL
orch_sensor_start pragma NULL NULL
orch_sensor_status pragma NULL NULL
orch_sensor_stop pragma NULL NULL
orch_test pragma NULL NULL
orch_visualize pragma NULL NULL

Überladene Funktionen

Diese Erweiterung fügt keine Funktionsüberladungen hinzu.

Hinzugefügte Typen

Diese Erweiterung fügt keine Typen hinzu.

Hinzugefügte Einstellungen

name description input_type scope aliases
orch_capture_interactive Capture column lineage for ad-hoc INSERT/CTAS queries via ParserExtension BOOLEAN GLOBAL []
orch_max_parallel Maximum parallel tasks per DAG layer BIGINT GLOBAL []
orch_namespace Job namespace for OpenLineage events VARCHAR GLOBAL []
orch_openlineage_api_key OpenLineage API key VARCHAR GLOBAL []
orch_openlineage_debug Log OpenLineage events to stderr BOOLEAN GLOBAL []
orch_openlineage_url OpenLineage backend URL (e.g. http://localhost:5000/api/v1/lineage) VARCHAR GLOBAL []