> ## Documentation Index
> Fetch the complete documentation index at: https://docs.duvo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Snowflake Workflows

> Build Duvo agents that query your Snowflake warehouse and turn the results into scheduled reports, threshold alerts, and spreadsheet exports.

<Info>
  **Time to complete:** 20–35 minutes

  **Difficulty:** Intermediate

  **Prerequisites:** Snowflake connection (key-pair authentication), Optional: Slack, Gmail, Outlook, or Google Sheets

  **You'll build:** Agents that query your data warehouse and turn the results into reports, alerts, and actions
</Info>

## Why Use Snowflake with Duvo?

**The Problem**: Valuable business data sits in your data warehouse — inventory levels, revenue figures, pipeline metrics, exception counts. Getting it into the hands of decision-makers requires a data engineer, a BI dashboard, or a manual export. Ad-hoc questions take hours. Monitoring dashboards go unread. Alerts are configured once and forgotten.

**The Solution**: Duvo agents can query Snowflake directly, interpret the results, and take action — sending a Slack message when a threshold is breached, writing a formatted report to Google Sheets, or summarizing warehouse trends in a Monday-morning email. No dashboards to maintain. No scheduled SQL scripts to babysit.

**What you can achieve**:

* Deliver scheduled KPI summaries before your team's Monday standup
* Get a Slack alert the moment inventory falls below a reorder threshold
* Pull a fresh data extract into Google Sheets for a stakeholder who needs it in minutes
* Monitor for anomalies across large datasets and escalate exceptions automatically

***

### Before You Start

Make sure you have these ready:

<Check>**Snowflake connection** — follow the [Snowflake connection guide](/user-guide/connections/available-connections/snowflake) to configure key-pair authentication and add the connection on the [Connections page](https://app.duvo.ai/integrations)</Check>
<Check>**Slack connection** (optional) — for threshold alerts and summaries. Click **Enable** on the Connections page and authorize with your Slack workspace</Check>
<Check>**Gmail or Outlook connection** (optional) — for email distribution of reports</Check>
<Check>**Google Sheets connection** (optional) — for writing query results to a spreadsheet</Check>

***

### Use Case 1: Scheduled KPI Report from Warehouse Data

**Outcome**: Every Monday morning, a summary of last week's key metrics — revenue, volume, exceptions — lands in your team's Slack channel. No one has to log into Snowflake or build a query.

This workflow queries Snowflake on a schedule, formats the results into a readable summary, and distributes it to the right people.

<Steps>
  <Step title="Create Your Agent" icon="plus">
    1. Click **"+ Create Agent"** from your dashboard
    2. Select **"Use Agent Builder"**
  </Step>

  <Step title="Paste This AOP" icon="pencil">
    Adapt the table names, columns, and metric names to match your warehouse schema:

    ```
    Every Monday at 7:00 AM, generate a weekly business metrics summary.

    Step 1: Query Snowflake for last week's metrics (Monday–Sunday).

    Run these queries and collect the results:
    - Total revenue: SELECT SUM(order_total) FROM orders WHERE order_date BETWEEN [last Monday] AND [last Sunday] AND status = 'completed'
    - Order count: SELECT COUNT(*) FROM orders WHERE order_date BETWEEN [last Monday] AND [last Sunday]
    - Average order value: calculate from the above
    - Exception count (failed or refunded orders): SELECT COUNT(*) FROM orders WHERE order_date BETWEEN [last Monday] AND [last Sunday] AND status IN ('failed', 'refunded')

    Step 2: Compare to the prior week by running the same queries for the previous Monday–Sunday period.

    Step 3: Calculate week-over-week change as a percentage for each metric.

    Step 4: Format a short summary message:
    "Weekly Metrics — [date range]
    - Revenue: $[value] ([+/-X%] vs prior week)
    - Orders: [count] ([+/-X%])
    - Avg order value: $[value] ([+/-X%])
    - Exceptions: [count] ([+/-X%])

    [If exceptions increased more than 20%, add: 'WARNING: Exception rate up — check the Orders table for details.']"

    Step 5: Post the message to the #data-ops Slack channel.
    ```
  </Step>

  <Step title="Connect Required Integrations" icon="plug">
    Under **Connections**, enable:

    * **Snowflake** — required
    * **Slack** — for posting the summary (or substitute Gmail/Outlook for email delivery)
  </Step>

  <Step title="Schedule the Agent" icon="calendar">
    1. Go to **Agent Settings** > **Triggers**
    2. Select **Schedule**
    3. Set to **Weekly** on **Monday** at **7:00 AM** in your timezone
  </Step>
</Steps>

#### Expected Results

* A Slack summary appears in your channel before your Monday standup
* Week-over-week comparisons show at a glance whether things are trending better or worse
* Anomaly flags are surfaced automatically so the team knows when to dig deeper
* No one needs to open Snowflake or write a query to get the numbers

***

### Use Case 2: Threshold Alert When a Metric Breaches a Limit

**Outcome**: When inventory for a top SKU drops below the reorder point — or when a fraud rate, error count, or cost metric crosses a threshold — your team gets a Slack message immediately rather than discovering the problem hours later.

This workflow polls Snowflake on a short schedule, checks against defined limits, and alerts only when action is needed.

<Steps>
  <Step title="Identify Your Threshold Condition" icon="search">
    Before writing the AOP, decide:

    * **Which table and column** holds the metric you want to watch (e.g., `inventory.quantity_on_hand`)
    * **What value triggers an alert** (e.g., less than 100 units, more than 5% error rate)
    * **What context to include** in the alert (e.g., which SKU, which region, current value, historical average)
  </Step>

  <Step title="Paste This AOP" icon="pencil">
    ```
    Every hour, check for inventory levels that require attention.

    Step 1: Run this query in Snowflake:
    SELECT sku, product_name, quantity_on_hand, reorder_point, warehouse_location
    FROM inventory.stock_levels
    WHERE quantity_on_hand < reorder_point
    ORDER BY quantity_on_hand ASC

    Step 2: If the query returns no rows, stop — no action needed.

    Step 3: If any rows are returned:
    - For each row, format a line: "• [product_name] (SKU [sku]) — [quantity_on_hand] units remaining at [warehouse_location] (reorder point: [reorder_point])"
    - Assemble a Slack message:
      "Inventory Alert — [count] SKUs below reorder point:
      [lines from above]

      Action: Check your replenishment queue or place restock orders."

    Step 4: Post the message to the #supply-chain Slack channel.
    Step 5: Do not send a duplicate alert if the same SKUs were already alerted in the last 4 hours.
    ```
  </Step>

  <Step title="Connect Required Integrations" icon="plug">
    Under **Connections**, enable:

    * **Snowflake** — required
    * **Slack** — for posting the alert
  </Step>

  <Step title="Schedule the Agent" icon="calendar">
    1. Go to **Agent Settings** > **Triggers**
    2. Select **Schedule**
    3. Set to **Every hour** (or every 15 minutes for time-critical metrics)
  </Step>
</Steps>

#### Expected Results

* Alerts fire only when a threshold is actually breached — no noise when things are fine
* Each alert names the specific SKUs or records requiring attention
* Your team can act immediately instead of learning about the problem in a weekly report
* The deduplication instruction prevents the same alert from firing repeatedly before anyone has had a chance to act

***

### Use Case 3: Export Query Results to Google Sheets

**Outcome**: A stakeholder needs a fresh data pull from the warehouse — customer list, transaction export, regional breakdown — and it needs to be in a spreadsheet they can filter and share. The agent runs the query and writes the results into a Google Sheet quickly.

This is useful for ad-hoc exports, recurring data pulls that feed downstream tools, or replacing manual "download CSV, clean it up, paste into Sheets" workflows.

<Steps>
  <Step title="Create Your Agent" icon="plus">
    1. Click **"+ Create Agent"** from your dashboard
    2. Select **"Use Agent Builder"**
  </Step>

  <Step title="Paste This AOP" icon="pencil">
    Adapt the query and sheet name to your use case:

    ```
    When started, export a fresh customer account list from Snowflake to Google Sheets.

    Step 1: Run this query in Snowflake:
    SELECT
      account_id,
      account_name,
      industry,
      annual_revenue,
      country,
      account_owner,
      created_date,
      last_activity_date
    FROM crm.accounts
    WHERE status = 'active'
    ORDER BY annual_revenue DESC

    Step 2: Write the results to the "Customer Accounts" Google Sheet:
    - Use the first sheet ("Sheet1")
    - Clear the existing content from row 2 downward (preserve the header row)
    - Write the query results starting from row 2, with one row per account
    - Use these column headers (already in row 1): Account ID, Account Name, Industry, Annual Revenue, Country, Account Owner, Created, Last Activity

    Step 3: Add a note at the top of the sheet (cell A1 comment or a dedicated "last updated" cell):
    "Last refreshed: [current date and time] — [row count] accounts"
    ```
  </Step>

  <Step title="Connect Required Integrations" icon="plug">
    Under **Connections**, enable:

    * **Snowflake** — required
    * **Google Sheets** — for writing results
  </Step>

  <Step title="Run On Demand or Schedule It" icon="play">
    * **On demand**: click **Start Work** whenever you need a fresh pull
    * **Scheduled**: set a daily or weekly trigger under **Agent Settings** > **Triggers** if the sheet needs to stay current automatically
  </Step>
</Steps>

#### Expected Results

* The Google Sheet is populated with fresh data each time the agent runs
* Stakeholders can filter, sort, and share the sheet without touching Snowflake
* The "last refreshed" cell makes it clear how current the data is
* Large result sets are handled automatically — when results are too large to return inline, they may be provided as a CSV that the agent can upload directly to the sheet

***

### Tips for Better Results

**Name your queries in the AOP**: Label each query with what it measures (e.g., "Query 1: weekly revenue"). This makes it easier to refine specific queries without rewriting the entire AOP.

**Use date ranges explicitly**: Rather than `WHERE date = CURRENT_DATE - 7`, write out the range in plain language in your AOP (e.g., "from last Monday to last Sunday") and let the agent calculate the exact dates at runtime. This avoids off-by-one errors from timezone differences.

**Keep queries read-only**: Duvo's Snowflake connection only allows SELECT statements. Design your workflow so any write operations happen via a different connection (Google Sheets, Slack, email) rather than back into Snowflake.

**Add a sanity check**: For reports that feed business decisions, add a line to your AOP like "If the total revenue figure is less than $1,000 or more than $10,000,000, stop and send me a Slack message saying the numbers look unexpected — do not distribute the report." This catches data pipeline issues before they mislead stakeholders.

**Upload schema context to Files**: If your warehouse has many tables or non-obvious column names, upload a data dictionary or schema summary to **Agent Settings** > **Files**. The agent can use it to write more accurate queries.

***

### Troubleshooting

<AccordionGroup>
  <Accordion title="Agent cannot connect to Snowflake" icon="plug-zap">
    * Re-open the Snowflake connection on the [Connections page](https://app.duvo.ai/integrations) and verify the account identifier, username, warehouse, database, schema, and role
    * Check that the RSA public key is still registered in Snowflake under `ALTER USER ... SET RSA_PUBLIC_KEY = '...'`
    * Confirm the Snowflake user's role has USAGE on the warehouse and SELECT on the target tables
  </Accordion>

  <Accordion title="Queries are returning no rows unexpectedly" icon="database">
    * Run the same query manually in Snowflake's worksheet UI to confirm the result
    * Check that the warehouse is not suspended — if it cannot auto-resume (or resume is slow), queries may fail or time out rather than return results
    * Verify that the date range in the AOP is computing correctly; add a line asking the agent to log the computed date range before querying
  </Accordion>

  <Accordion title="Report numbers look wrong" icon="calculator">
    * Check for timezone differences: Snowflake stores timestamps in UTC by default. If your AOP says "last week" without specifying a timezone, add one (e.g., "last Monday to last Sunday, US Eastern time")
    * Look for duplicate rows: if your table has one row per event and the query isn't aggregating correctly, add `SELECT DISTINCT` or a `GROUP BY`
    * Confirm the Snowflake role can see all the rows you expect — row-level security policies can silently filter results
  </Accordion>

  <Accordion title="Large result sets are not appearing in Google Sheets" icon="table">
    * When results are too large to return inline, they may be provided as a CSV file. The agent can upload the CSV directly to Google Sheets — update your AOP to say: "If the query result is a CSV file, upload it to the Google Sheet"
  </Accordion>

  <Accordion title="Scheduled Runs are not running" icon="calendar-x">
    * Confirm the trigger is set to **Active** under **Agent Settings** > **Triggers**
    * Check the agent's Run history to see whether previous scheduled Runs succeeded or failed
    * If Runs are failing, open the failed Run and read the run log to identify the error
  </Accordion>
</AccordionGroup>

***

### Related Resources

<CardGroup cols={2}>
  <Card title="Snowflake Connection" icon="snowflake" href="/user-guide/connections/available-connections/snowflake">
    Configure key-pair authentication and add the connection
  </Card>

  <Card title="Scheduling Agents" icon="calendar" href="/user-guide/assignment-features/scheduling-assignments">
    Run agents on a recurring schedule
  </Card>

  <Card title="Event-Driven Triggers" icon="zap" href="/user-guide/assignment-features/event-driven-triggers">
    Start agents from external events
  </Card>

  <Card title="Google Sheets Connection" icon="table" href="/user-guide/connections/available-connections/google-sheets">
    Write query results to a spreadsheet
  </Card>

  <Card title="Slack Connection" icon="message-square" href="/user-guide/connections/available-connections/slack">
    Post summaries and alerts to channels
  </Card>

  <Card title="Human-in-the-Loop" icon="user-check" href="/user-guide/assignment-features/human-in-the-loop">
    Add approval steps for sensitive actions
  </Card>

  <Card title="Files" icon="folder" href="/user-guide/assignment-features/files">
    Upload schema context for more accurate queries
  </Card>
</CardGroup>
