Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .dlt/config.toml

This file was deleted.

3 changes: 0 additions & 3 deletions 04-dlthub-data-pond/README.md

This file was deleted.

8 changes: 4 additions & 4 deletions 05-write-ticker-data-to-iceberg/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Write Ticker Data to Iceberg
# Ingest API Data into an Iceberg Table

This example demonstrates how to acquire data from an external data source and store it in Iceberg. It downloads stock ticker data from Yahoo Finance and writes it to an Iceberg table using Tower.
You need to pull data from an external API on a schedule and land it in your lakehouse — idempotently, so re-runs never create duplicates. This app solves that problem end to end, using stock prices from Yahoo Finance as the demo dataset: it downloads daily ticker data and upserts it into an Iceberg table on Tower.

## Overview

Expand All @@ -9,7 +9,7 @@ The pipeline uses [yfinance](https://github.com/ranaroussi/yfinance) to download
## Prerequisites

- Tower CLI installed
- An Iceberg catalog configured in Tower (see setup below)
- An Iceberg catalog named `default` — Tower hosts this for you, nothing external to sign up for. Deploying this example from the [Tower app](https://app.tower.dev) creates it in one click; on the CLI path, see setup below.

## App Parameters

Expand All @@ -29,7 +29,7 @@ uv sync

### 2. Configure an Iceberg Catalog

This app writes to an Iceberg table, which requires an Iceberg catalog configured in Tower.
This app writes to an Iceberg table, which requires an Iceberg catalog configured in Tower. The catalog is hosted by Tower — if you deploy this example from the Tower app's examples gallery, it is created for you automatically and you can skip this step. On the CLI path:

1. Go to [app.tower.dev](https://app.tower.dev/)
2. Navigate to your environment settings
Expand Down
10 changes: 5 additions & 5 deletions 06-analyze-ticker-data-in-iceberg/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Analyze Ticker Data in Iceberg
# Analyze Lakehouse Data with an LLM

This app demonstrates how to use statistical and AI inference analytics on data stored in Iceberg. It uses the Deepseek R1 LLM to generate buy/sell/hold recommendations based on trends in stock prices and trading volume. The data is read from the `daily_ticker_data` Iceberg table, which is populated by the [05-write-ticker-data-to-iceberg](../05-write-ticker-data-to-iceberg) example.
You have data accumulating in your lakehouse and want an LLM to reason over it — with no export pipeline to build. This app runs statistical analysis directly on an Iceberg table, then sends the derived metrics to the Deepseek R1 LLM to generate buy/sell/hold recommendations from trends in stock prices and trading volume. The data is read from the `daily_ticker_data` Iceberg table, which is populated by the [05-write-ticker-data-to-iceberg](../05-write-ticker-data-to-iceberg) example.

## Overview

Expand All @@ -18,9 +18,9 @@ The pipeline performs the following steps:

## Prerequisites

- A Tower account with an Iceberg catalog configured
- A Tower account with an Iceberg catalog configured (Tower-hosted — created automatically when you deploy from the [Tower app](https://app.tower.dev))
- The `daily_ticker_data` table populated by [05-write-ticker-data-to-iceberg](../05-write-ticker-data-to-iceberg)
- A Hugging Face account with an API token
- A Hugging Face account with an API token — or skip this and check **Use Tower sandbox value** on the setup screen when deploying from the Tower app

### Sign Up for Hugging Face Hub

Expand All @@ -42,7 +42,7 @@ Ensure you have an Iceberg catalog named `default` configured in the [Tower UI](

### 3. Create the Secrets

Add your inference provider credentials as Tower secrets:
Deploying from the Tower app? The setup screen can fill these with Tower's sandbox values for testing — no Hugging Face account needed. On the CLI path, add your inference provider credentials as Tower secrets:

```bash
tower secrets create --environment="default" \
Expand Down
4 changes: 2 additions & 2 deletions 08-fan-out-ticker-runs/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Fan out the downloads of ticker data
# Fan One Job Out into Parallel Runs

This app will download data for multiple tickers by running parallel runs of the "write-ticker-data-to-iceberg" app. It demonstrates Tower's `run` and `wait` orchestration capabilities.
You have a job that needs to run once per item — per ticker, per tenant, per file — and running them sequentially is too slow. This app shows Tower's `run` and `wait` orchestration: it downloads data for multiple stock tickers by launching parallel runs of the "write-ticker-data-to-iceberg" app and waiting for them all to finish.

# Schedule

Expand Down
32 changes: 32 additions & 0 deletions 09-run-duckdb-queries-on-iceberg/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Query Iceberg Tables with DuckDB

You have data in an Iceberg lakehouse and just want to run SQL on it — without standing up a query engine. This app connects DuckDB to a Tower Iceberg catalog and runs a query against the `daily_ticker_data` table (populated by [05-write-ticker-data-to-iceberg](../05-write-ticker-data-to-iceberg)).

## What It Does

1. Loads DuckDB's `iceberg` and `httpfs` extensions
2. Creates a DuckDB `SECRET` from your Iceberg REST catalog credentials
3. Attaches the catalog as a database and runs a plain `SELECT` against it

Swap the query at the bottom of [main.py](./main.py) for your own SQL.

## What You Need

- A Tower-hosted Iceberg catalog containing data (run example 05 first — nothing external to set up)
- Three Tower secrets with your Tower catalog's REST credentials:

```bash
tower secrets create --name=IRC_CLIENT_ID --value="[YOUR_CLIENT_ID]"
tower secrets create --name=IRC_CLIENT_SECRET --value="[YOUR_CLIENT_SECRET]"
tower secrets create --name=IRC_ENDPOINT --value="[YOUR_CATALOG_ENDPOINT]"
```

## Run It

```bash
cd 09-run-duckdb-queries-on-iceberg
tower deploy
tower run
```

Add `--local` to `tower run` to execute on your machine while still reading secrets from Tower.
4 changes: 2 additions & 2 deletions 11-trim-ticker-table/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Trim Ticker Table
# Enforce a Retention Window on an Iceberg Table

This app demonstates deletes from an Iceberg table. It shows how to delete old data from an Iceberg table using Tower.
Tables grow forever unless something deletes the old rows — and storage bills grow with them. This app shows how to delete data from an Iceberg table with Tower: it keeps a rolling window of recent ticker data and drops everything older.

## Overview

Expand Down
10 changes: 6 additions & 4 deletions 13-ticker-update-agent/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Ticker Update Agent
# Deploy an AI Agent over Your Business Data

This example demonstrates how to deploy and operate a data agent that uses business data for decision making. It creates an AI data agent that answers stock price questions and maintains a cache of prices in an Iceberg table.
You want an AI agent that answers questions from your business data — and keeps that data fresh itself. This app deploys a data agent on Tower that answers stock price questions from an Iceberg table, and when the answer isn't there, fetches it from the source and caches it for next time.

## Overview

Expand All @@ -24,7 +24,7 @@ The agent demonstrates how to build **agentic workflows** in Tower that can orch
## Prerequisites

- Tower CLI installed
- An Iceberg catalog configured in Tower (see setup below)
- An Iceberg catalog named `default` — Tower hosts this for you; deploying this example from the [Tower app](https://app.tower.dev) creates it (and can set a sandbox `OPENAI_API_KEY`) in one click. On the CLI path, see setup below.
- The `daily_ticker_data` table exists (created by example 05)
- The `write-ticker-data-to-iceberg` app deployed (example 05)

Expand Down Expand Up @@ -52,9 +52,11 @@ tower secrets create LANGCHAIN_API_KEY "<your-langchain-api-key>"
tower secrets create OPENAI_API_KEY "<your-openai-api-key>"
```

> No OpenAI key? When deploying from the Tower app, check **Use Tower sandbox value** on the setup screen to test with Tower's own key.

### 3. Configure an Iceberg Catalog

This app reads from and writes to an Iceberg table, which requires an Iceberg catalog configured in Tower.
This app reads from and writes to an Iceberg table, which requires an Iceberg catalog configured in Tower. The catalog is hosted by Tower — if you deploy this example from the Tower app's examples gallery, it is created for you automatically and you can skip this step. On the CLI path:

1. Go to [app.tower.dev](https://app.tower.dev/)
2. Navigate to your environment settings
Expand Down
28 changes: 28 additions & 0 deletions 16-sling-data/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Replicate Data into Snowflake with Sling

You need to move data into a warehouse without writing pipeline code. This app uses [Sling](https://slingdata.io/) to replicate a local JSON file into a Snowflake table from a declarative YAML config — the Python is just a thin runner.

## What It Does

1. Reads the replication config from [sling.yaml](./sling.yaml) (source: the bundled [data/input.json](./data/input.json); target: `PUBLIC.SLING_JSON_TOWER_DEMO`)
2. Runs the replication in `full-refresh` mode

Point `sling.yaml` at your own sources and targets — Sling supports databases, object stores, and files.

## What You Need

A Tower secret named `SNOWFLAKE_URL` with your Snowflake connection string, in [Sling's URL format](https://docs.slingdata.io/connections/database-connections/snowflake):

```bash
tower secrets create --name=SNOWFLAKE_URL --value="snowflake://user:password@account/database?schema=PUBLIC&warehouse=COMPUTE_WH"
```
Comment thread
coderabbitai[bot] marked this conversation as resolved.

> **Note:** Inline values like this end up in your shell history. Use a throwaway or sandbox Snowflake user for testing, and avoid pasting production credentials into commands.

## Run It

```bash
cd 16-sling-data
tower deploy
tower run
```
82 changes: 82 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Tower Examples

Working example apps for [Tower](https://tower.dev), each built around a common data problem. Every example is a complete Tower app — a few Python files plus a `Towerfile` — that you can clone, deploy, and run in minutes, then adapt to your own stack.

## Quick start

Install the [Tower CLI](https://docs.tower.dev/getting-started/installation), sign in, and run the first example — it needs no secrets and no setup:

```bash
git clone https://github.com/tower/tower-examples.git
cd tower-examples/01-hello-world
tower login
tower deploy
tower run
```

Then pick the example below that matches the problem you're actually trying to solve.

## Find your problem

### Start here — runs with zero setup

| Example | The problem it solves | What you need |
|---|---|---|
| [01-hello-world](./01-hello-world) | See the whole Tower workflow — deploy, run, parameters, logs — in two minutes | Nothing |
| [15-interactive-marimo-notebook](./15-interactive-marimo-notebook) | Serve an interactive Python notebook as a running app, no infra to host | Nothing |

### Load files into a warehouse

| Example | The problem it solves | What you need |
|---|---|---|
| [02-dlthub-s3-to-snowflake](./02-dlthub-s3-to-snowflake) | CSVs land in S3 and need to end up in Snowflake, incrementally and reliably (dlt) | Snowflake credentials — the source bucket is public |
| [03-dlthub-s3-to-motherduck](./03-dlthub-s3-to-motherduck) | Same S3 ingestion problem, targeting MotherDuck (dlt) | MotherDuck token — the source bucket is public |
| [16-sling-data](./16-sling-data) | Replicate local/JSON data into Snowflake with a declarative YAML config (Sling) | Snowflake connection secret |

### Build a lakehouse on Apache Iceberg

These examples form a small end-to-end lakehouse: ingest → analyze → query → maintain. They share one prerequisite: an Iceberg catalog named `default` — but Tower hosts this catalog for you, so there is nothing external to sign up for. Deploying an example from the [Tower app](https://app.tower.dev) creates it in one click (the same screen can fill required secrets with Tower sandbox values for testing); on the CLI path, create it once in the Tower UI.

| Example | The problem it solves | What you need |
|---|---|---|
| [05-write-ticker-data-to-iceberg](./05-write-ticker-data-to-iceberg) | Pull data from an external API on a schedule and land it in an Iceberg table (demo data: stock prices) | Tower-hosted catalog — no API keys |
| [06-analyze-ticker-data-in-iceberg](./06-analyze-ticker-data-in-iceberg) | Run LLM-assisted analysis over data already in your lakehouse | Tower-hosted catalog + inference key (or Tower's sandbox key in-app) |
| [09-run-duckdb-queries-on-iceberg](./09-run-duckdb-queries-on-iceberg) | Query Iceberg tables with plain SQL from DuckDB | Tower-hosted catalog + its REST credentials as secrets |
| [11-trim-ticker-table](./11-trim-ticker-table) | Enforce a retention window by deleting old rows from an Iceberg table | Tower-hosted catalog with data (run 05 first) |
| [17-list-catalog-tables](./17-list-catalog-tables) | Inspect what namespaces and tables exist in a catalog | Tower-hosted catalog |
| [18-read-table-rows](./18-read-table-rows) | Peek at the first rows of any Iceberg table | Tower-hosted catalog with data |

### Orchestrate many runs

| Example | The problem it solves | What you need |
|---|---|---|
| [08-fan-out-ticker-runs](./08-fan-out-ticker-runs) | Fan one job out into parallel runs and wait for them all (Tower `run`/`wait`) | Example 05 deployed |

### Put LLMs and agents to work on your data

| Example | The problem it solves | What you need |
|---|---|---|
| [07-deepseek-summarize-github](./07-deepseek-summarize-github) | Feed operational data (GitHub issues) to an LLM and get an actionable recommendation back | Tower-hosted catalog + inference API key |
| [13-ticker-update-agent](./13-ticker-update-agent) | Deploy an AI agent that answers questions from — and maintains — business data in your lakehouse | Tower-hosted catalog + `OPENAI_API_KEY` (or Tower's sandbox key in-app) |

### Run dbt in production

| Example | The problem it solves | What you need |
|---|---|---|
| [14-dbt-core-ecommerce-analytics](./14-dbt-core-ecommerce-analytics) | Run a real dbt Core project (seed → build) as a deployable, schedulable app | `DBT_PROFILE_YAML` secret with your warehouse profile |

## How every example works

Each directory is a self-contained Tower app:

- **`Towerfile`** — declares the app: name, entrypoint script, source files, and runtime parameters.
- **A Python script** — ordinary Python; no framework to learn.
- **`pyproject.toml`** — dependencies, installed automatically at run time.

The workflow is always the same: `tower deploy` from the example's directory, then `tower run` (add `--local` to execute on your machine while still using Tower secrets and catalogs). Set secrets with `tower secrets create`; each example's README lists exactly which ones it needs.

## Learn more

- [Tower documentation](https://docs.tower.dev) — concepts, CLI reference, guides
- [Tower Control](https://control.tower.dev) — describe an app in natural language and let the agent build and deploy it
- [tower.dev](https://tower.dev) — what Tower is and who it's for
Loading