Tail DuckLake tables via CDC
Project description
ducktail
tail -f for DuckLake tables.
Watch inserts, deletes, and updates flow through a DuckLake table in real time, powered by DuckLake's built-in CDC.
$ ducktail tail orders -C meta.duckdb
+ id=1 name=Alice amount=100.0
+ id=2 name=Bob amount=50.0
- id=2 name=Bob amount=50.0
Δ amount: 100.0 → 150.0
Install
pip install ducktail # or: uv add ducktail
Requires Python 3.12+ and DuckDB 1.4+ (ducklake extension loads automatically).
Usage
Basic
ducktail tail TABLE -C CONNECTION
# DuckDB metadata catalog
ducktail tail events -C meta.duckdb -d /data
# Postgres metadata catalog
ducktail tail events -C "postgres:dbname=ducklake host=localhost user=ducklake password=ducklake"
Interactive mode
Full-screen TUI with color-coded rows (green inserts, red deletes, yellow updates):
ducktail tail events -C meta.duckdb -m interactive
Filter what you see
# Only specific columns
ducktail tail events -C meta.duckdb -col status -col amount
# Server-side filter (pushed into the CDC query)
ducktail tail events -C meta.duckdb -f "amount > 100"
# Faster polling
ducktail tail events -C meta.duckdb -i 0.5
Compose with Unix tools
Pager mode (the default) writes one line per change to stdout, so it plays nicely with the usual suspects:
# Inserts only
ducktail tail orders -C meta.duckdb | grep '^\+'
# Deletes only
ducktail tail orders -C meta.duckdb | grep '^\-'
# Count changes per second
ducktail tail orders -C meta.duckdb | pv -l > /dev/null
Options
ducktail tail [OPTIONS] TABLE_NAME
| Option | Short | Default | Description |
|---|---|---|---|
TABLE_NAME |
(required) | Table to tail | |
--connection |
-C |
(required) | Catalog connection string |
--catalog |
-c |
lake |
Catalog name |
--data-path |
-d |
. |
Path to DuckLake data files |
--namespace |
-n |
main |
Table namespace |
--interval |
-i |
1.0 |
Poll interval (seconds) |
--columns |
-col |
(all) | Columns to show (repeat for multiple) |
--filter |
-f |
(none) | CDC filter expression |
--mode |
-m |
pager |
pager or interactive |
Change symbols
| Symbol | Color | Meaning |
|---|---|---|
+ |
Green | Row inserted |
- |
Red | Row deleted |
Δ |
Yellow | Row updated — shows column: old → new for each changed field |
Try the demo
The repo includes a Docker-based demo that stands up a Postgres metadata catalog and a producer that streams a mix of inserts, deletes, and updates.
# Terminal 1 — infrastructure + producer
just demo-up
just demo-producer
# Terminal 2 — watch it happen
just demo-tail # pager mode
just demo-tail-interactive # or interactive mode
# Cleanup
just demo-down
Development
Requires flox and Docker (for integration tests and demo).
flox activate
just sync # install deps
just test # unit tests
just ci # format + lint + typecheck + unit tests
| Recipe | What it does |
|---|---|
just sync |
Install dependencies |
just fmt |
Format code |
just lint |
Lint |
just typecheck |
mypy strict |
just test |
Unit tests |
just test-integration |
Integration tests |
just test-all |
Both |
just ci |
fmt-check + lint + typecheck + test |
License
Apache License 2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ducktail-1.0.2.tar.gz.
File metadata
- Download URL: ducktail-1.0.2.tar.gz
- Upload date:
- Size: 672.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d94810d82311aa1d7e2e4361e1f627b567e3ed57fb2122a734e7f9eb3b355002
|
|
| MD5 |
3debd90ebfbdc4c5c3ab7e8b666100e9
|
|
| BLAKE2b-256 |
09cc31d0617982adf373eaa7383dcee9d7949bd180afdf7151181168930ec498
|
Provenance
The following attestation bundles were made for ducktail-1.0.2.tar.gz:
Publisher:
release.yml on jghoman/ducktail
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ducktail-1.0.2.tar.gz -
Subject digest:
d94810d82311aa1d7e2e4361e1f627b567e3ed57fb2122a734e7f9eb3b355002 - Sigstore transparency entry: 1343785768
- Sigstore integration time:
-
Permalink:
jghoman/ducktail@093a2dea12cae4f3f84fd18a7b18c7bd0374cad3 -
Branch / Tag:
refs/tags/v1.0.2 - Owner: https://github.com/jghoman
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@093a2dea12cae4f3f84fd18a7b18c7bd0374cad3 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ducktail-1.0.2-py3-none-any.whl.
File metadata
- Download URL: ducktail-1.0.2-py3-none-any.whl
- Upload date:
- Size: 8.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fb26162700068d36f00ab1061b4164872a85b3e27e4ddfcfac6e27e3b4993d17
|
|
| MD5 |
4aca8b5f92a2a62df4973b57091eaff5
|
|
| BLAKE2b-256 |
f5e2f87a346dbe7ccf4acfa9f7dbfb05524e6f1cae6a3cdd3bfb22ecfd4cfe83
|
Provenance
The following attestation bundles were made for ducktail-1.0.2-py3-none-any.whl:
Publisher:
release.yml on jghoman/ducktail
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ducktail-1.0.2-py3-none-any.whl -
Subject digest:
fb26162700068d36f00ab1061b4164872a85b3e27e4ddfcfac6e27e3b4993d17 - Sigstore transparency entry: 1343785799
- Sigstore integration time:
-
Permalink:
jghoman/ducktail@093a2dea12cae4f3f84fd18a7b18c7bd0374cad3 -
Branch / Tag:
refs/tags/v1.0.2 - Owner: https://github.com/jghoman
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@093a2dea12cae4f3f84fd18a7b18c7bd0374cad3 -
Trigger Event:
push
-
Statement type: