Build a BA Dashboard Investigator Skill

Author a custom Antigravity agent skill that fixes dashboard SQL queries.

Introduction

30 Second Summary

Every time you ask an AI assistant the same kind of question, it starts from scratch. It has no memory of the best approach, the right steps, or the domain-specific knowledge you rely on daily.

In this project, you will build a custom Google Antigravity skill that teaches the AI agent how to help Business Analysts investigate and fix dashboard queries with missing data columns.

What You'll Build

A fully functional Agent Skill called ba-dashboard-investigator that activates when you ask the agent to investigate missing dashboard columns or fix SQL queries.

By the end of this project, you'll have:

  • A complete SKILL.md file with proper YAML frontmatter and structured Markdown instructions that the agent follows step by step.
  • A references/ directory containing a SQL JOIN guide and an examples/ directory with a worked scenario the agent uses as a template.
  • A tested, working skill that the Antigravity CLI discovers, activates on relevant prompts, and uses to walk you through a JOIN decision tree.
  • Secret Mission: Extend your skill to handle KPI reporting prompts by adding a second example file and updating the skill description.

Are there any prerequisites?

You need Google Antigravity installed with a premium subscription (both the IDE and CLI). No prior Markdown, YAML, or SQL experience is required.

Create Your Skill Workspace

Every Antigravity skill lives inside a specific folder structure that the agent knows to scan at startup.

Before writing any skill content, you need to create this folder hierarchy in the right location. In this step, you will build the project directory, set up the skill folder structure, and confirm that the Antigravity CLI can detect your workspace.

In this step, get ready to:
  • Create the skill folder structure with all required subdirectories.
  • Verify the folders were created correctly.
  • Confirm the Antigravity CLI starts and detects your workspace.
Create the skill folder structure

Antigravity discovers workspace-scoped skills from a .agents/skills/ directory at the root of your project. Each skill is its own folder, and the folder name becomes the skill's identifier.

  • Open the built-in terminal in the Antigravity IDE.
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project directory and skill folder structure by running these commands:
mkdir -p ba-skills-project/.agents/skills/ba-dashboard-investigator/references
mkdir -p ba-skills-project/.agents/skills/ba-dashboard-investigator/examples
cd ba-skills-project

What do these directories do?

  • ba-skills-project/ is your project root.
  • .agents/skills/ is where Antigravity looks for workspace-scoped skills.
  • ba-dashboard-investigator/ is the skill folder. This name must match the name field you will set in SKILL.md later.
  • references/ holds detailed guides the agent loads on demand.
  • examples/ holds worked scenarios that improve agent output quality.

Seeing a permission denied error?

Make sure you are running the command from your Desktop and not from a system-protected directory. Try running pwd to check your current location.

help me fix a permission denied error when creating directories on macOS

Verify the folder structure
  • Confirm your directories were created correctly by running:
find .agents

You should see output that includes these paths:

.agents/skills/ba-dashboard-investigator/references
.agents/skills/ba-dashboard-investigator/examples

Don't see the expected output?

Make sure your terminal is inside the ba-skills-project directory. Run pwd to check. If it does not end with ba-skills-project, run cd ~/Desktop/ba-skills-project and try again.

help me troubleshoot my skill folder structure

Verify the Antigravity CLI is working

The Antigravity CLI is what you will use to interact with your skill once it is complete. A quick check now confirms your workspace is ready before you start writing content.

  • Start the Antigravity CLI by running:
agy
  • Once the CLI session starts, type /skills and press Enter.

You should see a list with no workspace skills yet. This is expected since you have not added a SKILL.md file.

  • Type /exit and press Enter to close the session.

What did /skills show?

The /skills command lists every skill the agent has discovered in your workspace. Right now the list is empty because you have not created a SKILL.md yet.

Once you add your SKILL.md in the next step, the agent will detect ba-dashboard-investigator here automatically.

CLI won't start?

Make sure you are running agy from inside the ba-skills-project directory. Also confirm that your Antigravity premium subscription is active and the CLI was installed as part of your Antigravity setup.

help me troubleshoot the Antigravity CLI not starting

Your workspace is ready. Next up, you will write the SKILL.md file that teaches the agent exactly how to investigate dashboard queries.

Write the SKILL.md File

Your skill folder structure is ready. Now it is time to fill it with the content that actually teaches the agent what to do.

The SKILL.md file is the heart of every Antigravity skill. It contains metadata (so the agent knows when to activate) and structured instructions (so the agent knows what to do once activated).

In this step, get ready to:
  • Create the YAML frontmatter that tells the agent when to activate your skill.
  • Write the instruction body with a step-by-step process and JOIN decision tree.
  • Review the complete skill file structure.
Create the SKILL.md with YAML frontmatter

Every SKILL.md starts with YAML frontmatter. This is a metadata block between two --- delimiters that tells the agent your skill's name and when to use it.

  • Create a new file called SKILL.md inside the .agents/skills/ba-dashboard-investigator/ folder.
  • Add the following YAML frontmatter at the top of the file:
---
name: ba-dashboard-investigator
description: Investigates dashboard SQL queries that are missing data columns and guides the user through fixing them. Helps identify the source table, choose the correct JOIN strategy (JOIN, LEFT JOIN, CTE, or enrichment step), and write the SQL to pull missing columns using a shared identifier. Use when a Business Analyst needs to add columns to an existing dashboard query, fix incomplete reports, or investigate why data is missing from a dashboard.
---

What does this frontmatter do?

The name field is your skill's unique identifier. It must be lowercase, use hyphens for spaces, be 1-64 characters, and match the folder name.

The description field is the most important part. The agent reads it at startup to decide whether your skill is relevant to a user's prompt. Include action verbs and scenario keywords so the agent can match accurately.

  • Save SKILL.md.
  • Confirm the file exists by running:
ls .agents/skills/ba-dashboard-investigator/

You should see SKILL.md listed alongside the references and examples directories.

Don't see SKILL.md?

Make sure you saved the file inside the correct folder (.agents/skills/ba-dashboard-investigator/). If it ended up in the project root, move it to the skill folder.

Also check that the filename is exactly SKILL.md (all caps for SKILL, lowercase for .md).

Help me find where my SKILL.md file ended up

Write the instruction body

The body of your SKILL.md is the content that gets injected into the agent's context when your skill activates. This is where you encode your BA workflow and the JOIN decision tree.

  • Below the closing --- of your frontmatter, add the following Markdown body:

# BA Dashboard Investigator

## Goal

Help a Business Analyst identify and fix missing columns in an existing dashboard query by determining the correct data source and SQL join strategy.

## When to Use This Skill

- A dashboard or report is missing one or more data columns
- The user needs to pull additional fields from a related table
- The user needs guidance on which type of JOIN to use
- The user has a shared identifier (key) between tables but is unsure how to connect them

## Step-by-Step Process

### Step 1: Clarify What Is Missing

Ask the user:
1. What columns are missing from the current dashboard?
2. What table or query currently powers the dashboard?
3. Do you know which table contains the missing columns?

If the user does not know where the missing data lives, help them reason about it by asking what the data represents (e.g., "customer email" likely lives in a customers or users table).

### Step 2: Identify the Shared Identifier

Ask the user:
1. What column exists in BOTH the current dashboard query AND the table containing the missing data?
2. This shared column is called a "key" or "identifier" - common examples include: customer_id, order_id, user_id, product_sku

If unsure, suggest they check both tables for columns with similar names ending in _id.

### Step 3: Choose the JOIN Strategy

Use this decision tree to recommend the correct approach:

**Use INNER JOIN when:**
- You only want rows that exist in BOTH tables
- It is acceptable to lose rows from the dashboard if they do not have a match in the other table
- Example: "Show me only customers who have placed orders"

**Use LEFT JOIN when:**
- You want to KEEP all existing dashboard rows, even if some do not have matching data in the other table
- Missing matches will show as NULL values
- This is the MOST COMMON choice for adding columns to an existing dashboard
- Example: "Add email to my orders dashboard - but keep orders even if we do not have the customer email"

**Use a CTE (Common Table Expression) when:**
- The missing data requires calculation or aggregation before joining (e.g., "total orders per customer" or "most recent login date")
- You need to pre-filter or transform the data before combining it
- Example: "Add each customer's total lifetime spend to the dashboard"

**Use an enrichment step (subquery or staging table) when:**
- The data comes from a different database or system entirely
- The join would be too expensive to run in real-time
- The data needs to be refreshed on a schedule rather than queried live
- Example: "Add CRM data that lives in Salesforce to our BigQuery dashboard"

### Step 4: Write the SQL

After determining the strategy, write the SQL for the user. Always:
1. Start with the existing query (ask to see it if not provided)
2. Add the JOIN clause with the shared identifier
3. Add the new columns to the SELECT statement
4. Explain each part of the new SQL in plain language

### Step 5: Validate

Ask the user to verify:
1. Does the row count match expectations? (LEFT JOIN should keep the same count; INNER JOIN may reduce it)
2. Are the new columns showing the expected data?
3. Are there unexpected NULL values that need investigation?

## Reference Materials

- See `references/sql-join-guide.md` for detailed SQL syntax and common mistakes
- See `examples/missing-columns-fix.md` for a complete worked example of adding missing columns to a dashboard query

## Constraints

- Do NOT suggest DELETE, UPDATE, INSERT, or DROP statements. This skill is read-only.
- Always explain WHY a specific JOIN type was chosen, not just what to write.
- If the user's scenario does not fit neatly into one strategy, explain the trade-offs of each option and let them decide.
- Keep SQL examples simple and well-commented.

What does this instruction body do?

The body follows a clear pattern that guides the agent through a structured workflow:

  • Goal tells the agent the overall purpose of this skill in one sentence.
  • When to Use This Skill lists trigger conditions so the agent only activates when appropriate.
  • Step-by-Step Process gives the agent explicit logic to follow, including the JOIN decision tree in Step 3.
  • Reference Materials points the agent to files it can load on demand for deeper detail.
  • Constraints sets boundaries (read-only SQL, always explain why) so the agent does not overstep.

Why a decision tree instead of a simple list?

Without the decision tree, the agent would guess which JOIN type to suggest. The tree gives it explicit branching logic: if the user wants all rows kept, use LEFT JOIN. If the data needs aggregation first, use a CTE.

This is what makes a skill more powerful than a plain prompt. You are encoding repeatable decision-making that the agent follows consistently every time.

  • Save SKILL.md.

You will not see a visible change yet. In Step 5, you will launch the CLI and confirm the agent discovers and activates your skill.

Worried about the description references to files that do not exist yet?

The Reference Materials section mentions references/sql-join-guide.md and examples/missing-columns-fix.md. These files do not exist yet, and that is fine. You will create them in the next two steps. The agent only loads them on demand when it needs deeper detail.

Help me understand how the agent handles missing reference files

Review what you wrote

Read through your SKILL.md from top to bottom. Notice how it follows a deliberate progression.

  • The frontmatter handles discovery. The agent reads name and description at startup (~100 tokens) to decide relevance.
  • The body handles activation. When triggered, the agent loads the full instructions (recommended under 5000 tokens).
  • The reference files handle depth. The agent loads them only when it needs additional detail for a user's question.

What is progressive disclosure?

This three-level loading pattern is called progressive disclosure. Level 1 is metadata (loaded at startup for all skills). Level 2 is the full instruction body (loaded on activation). Level 3 is resource files (loaded on demand).

This keeps token usage low. The agent only pays the cost of detailed SQL guides when a user actually needs that depth.

✔️ Awesome, I've got everything!

Great. Double check you have saved your file before moving on.

ⓧ I'd like to double check the full code

Here is the complete SKILL.md file. Make sure yours matches exactly:

---
name: ba-dashboard-investigator
description: Investigates dashboard SQL queries that are missing data columns and guides the user through fixing them. Helps identify the source table, choose the correct JOIN strategy (JOIN, LEFT JOIN, CTE, or enrichment step), and write the SQL to pull missing columns using a shared identifier. Use when a Business Analyst needs to add columns to an existing dashboard query, fix incomplete reports, or investigate why data is missing from a dashboard.
---

# BA Dashboard Investigator

## Goal

Help a Business Analyst identify and fix missing columns in an existing dashboard query by determining the correct data source and SQL join strategy.

## When to Use This Skill

- A dashboard or report is missing one or more data columns
- The user needs to pull additional fields from a related table
- The user needs guidance on which type of JOIN to use
- The user has a shared identifier (key) between tables but is unsure how to connect them

## Step-by-Step Process

### Step 1: Clarify What Is Missing

Ask the user:
1. What columns are missing from the current dashboard?
2. What table or query currently powers the dashboard?
3. Do you know which table contains the missing columns?

If the user does not know where the missing data lives, help them reason about it by asking what the data represents (e.g., "customer email" likely lives in a customers or users table).

### Step 2: Identify the Shared Identifier

Ask the user:
1. What column exists in BOTH the current dashboard query AND the table containing the missing data?
2. This shared column is called a "key" or "identifier" - common examples include: customer_id, order_id, user_id, product_sku

If unsure, suggest they check both tables for columns with similar names ending in _id.

### Step 3: Choose the JOIN Strategy

Use this decision tree to recommend the correct approach:

**Use INNER JOIN when:**
- You only want rows that exist in BOTH tables
- It is acceptable to lose rows from the dashboard if they do not have a match in the other table
- Example: "Show me only customers who have placed orders"

**Use LEFT JOIN when:**
- You want to KEEP all existing dashboard rows, even if some do not have matching data in the other table
- Missing matches will show as NULL values
- This is the MOST COMMON choice for adding columns to an existing dashboard
- Example: "Add email to my orders dashboard - but keep orders even if we do not have the customer email"

**Use a CTE (Common Table Expression) when:**
- The missing data requires calculation or aggregation before joining (e.g., "total orders per customer" or "most recent login date")
- You need to pre-filter or transform the data before combining it
- Example: "Add each customer's total lifetime spend to the dashboard"

**Use an enrichment step (subquery or staging table) when:**
- The data comes from a different database or system entirely
- The join would be too expensive to run in real-time
- The data needs to be refreshed on a schedule rather than queried live
- Example: "Add CRM data that lives in Salesforce to our BigQuery dashboard"

### Step 4: Write the SQL

After determining the strategy, write the SQL for the user. Always:
1. Start with the existing query (ask to see it if not provided)
2. Add the JOIN clause with the shared identifier
3. Add the new columns to the SELECT statement
4. Explain each part of the new SQL in plain language

### Step 5: Validate

Ask the user to verify:
1. Does the row count match expectations? (LEFT JOIN should keep the same count; INNER JOIN may reduce it)
2. Are the new columns showing the expected data?
3. Are there unexpected NULL values that need investigation?

## Reference Materials

- See `references/sql-join-guide.md` for detailed SQL syntax and common mistakes
- See `examples/missing-columns-fix.md` for a complete worked example of adding missing columns to a dashboard query

## Constraints

- Do NOT suggest DELETE, UPDATE, INSERT, or DROP statements. This skill is read-only.
- Always explain WHY a specific JOIN type was chosen, not just what to write.
- If the user's scenario does not fit neatly into one strategy, explain the trade-offs of each option and let them decide.
- Keep SQL examples simple and well-commented.

Your skill now has a complete set of instructions. Next, you will create the SQL JOIN reference guide that gives the agent deeper technical detail to draw from when users need more explanation.

Create the SQL JOIN Reference Guide

Your SKILL.md file is complete with a decision tree that teaches the agent how to choose between JOIN strategies.

However, that decision tree gives the agent logic for choosing. It does not give detailed SQL syntax or common pitfalls. In this step, you will create a dedicated reference file that the agent can load on demand when a user needs deeper technical detail.

In this step, get ready to:
  • Create a SQL JOIN reference guide with syntax examples for each strategy.
  • Understand how progressive disclosure keeps your skill efficient.
Create the SQL JOIN reference file

The references/ directory holds detailed technical content that would bloat the main SKILL.md if included inline. The agent loads these files only when it needs extra depth.

  • Create the file .agents/skills/ba-dashboard-investigator/references/sql-join-guide.md and paste in the following content:
# SQL JOIN Reference for Business Analysts

## What is a JOIN?

A JOIN combines rows from two or more tables based on a related column (the "key" or "shared identifier"). Think of it like matching rows in two spreadsheets using a common column like customer_id.

## JOIN Types Explained

### INNER JOIN

Returns only rows that have a match in BOTH tables.

```sql
SELECT orders.order_id, orders.amount, customers.email
FROM orders
INNER JOIN customers ON orders.customer_id = customers.customer_id
```

Result: Only orders where we have a matching customer record. Orders without a customer match are dropped.

### LEFT JOIN

Returns ALL rows from the left table (the one in FROM), plus matching data from the right table. Non-matches show NULL.

```sql
SELECT orders.order_id, orders.amount, customers.email
FROM orders
LEFT JOIN customers ON orders.customer_id = customers.customer_id
```

Result: All orders are kept. If a customer record is missing, email shows as NULL.

### CTE (Common Table Expression)

A temporary named result set defined within a query. Used when you need to calculate or transform data before joining it.

```sql
WITH customer_totals AS (
    SELECT customer_id, SUM(amount) AS lifetime_spend
    FROM orders
    GROUP BY customer_id
)
SELECT d.*, ct.lifetime_spend
FROM dashboard_query d
LEFT JOIN customer_totals ct ON d.customer_id = ct.customer_id
```

Result: Each dashboard row gets an additional calculated column (lifetime_spend) without modifying the original query structure.

## When to Use Each (Quick Reference)

| Scenario | Recommended | Reason |
|----------|-------------|--------|
| Add columns, keep all rows | LEFT JOIN | Preserves existing data |
| Add columns, only matched rows | INNER JOIN | Filters to complete data |
| Add calculated/aggregated columns | CTE + LEFT JOIN | Pre-compute then join |
| Data from another system | Enrichment step | Cannot query cross-system live |

## Common Mistakes

1. Using INNER JOIN when you meant LEFT JOIN (accidentally losing dashboard rows)
2. Forgetting to add new columns to the SELECT statement after writing the JOIN
3. Joining on the wrong column (always verify the shared identifier matches in both tables)
4. Not checking for duplicate rows after joining (a one-to-many relationship can multiply your rows)

What does this file cover?

This reference guide gives the agent ready-made SQL examples for three JOIN strategies: INNER JOIN, LEFT JOIN, and CTE. Each example shows the syntax and explains what the result looks like.

The quick-reference table at the bottom maps real scenarios to the recommended approach. The Common Mistakes section helps the agent warn users about pitfalls before they happen.

  • Save sql-join-guide.md.
  • Confirm the file exists by running:
ls .agents/skills/ba-dashboard-investigator/references/

You should see sql-join-guide.md listed in the output.

Don't see the file?

Make sure you created the file inside the references/ subdirectory, not directly in the ba-dashboard-investigator/ folder. The path from your project root should be .agents/skills/ba-dashboard-investigator/references/sql-join-guide.md.

Also check that the filename is exactly sql-join-guide.md with hyphens, not underscores or spaces.

Help me find where my reference file ended up

✔️ Awesome, I've got everything!

Great. Double check you have saved your file before moving on.

ⓧ I'd like to double check the full code

Here is the complete references/sql-join-guide.md file for comparison:

# SQL JOIN Reference for Business Analysts

## What is a JOIN?

A JOIN combines rows from two or more tables based on a related column (the "key" or "shared identifier"). Think of it like matching rows in two spreadsheets using a common column like customer_id.

## JOIN Types Explained

### INNER JOIN

Returns only rows that have a match in BOTH tables.

```sql
SELECT orders.order_id, orders.amount, customers.email
FROM orders
INNER JOIN customers ON orders.customer_id = customers.customer_id
```

Result: Only orders where we have a matching customer record. Orders without a customer match are dropped.

### LEFT JOIN

Returns ALL rows from the left table (the one in FROM), plus matching data from the right table. Non-matches show NULL.

```sql
SELECT orders.order_id, orders.amount, customers.email
FROM orders
LEFT JOIN customers ON orders.customer_id = customers.customer_id
```

Result: All orders are kept. If a customer record is missing, email shows as NULL.

### CTE (Common Table Expression)

A temporary named result set defined within a query. Used when you need to calculate or transform data before joining it.

```sql
WITH customer_totals AS (
    SELECT customer_id, SUM(amount) AS lifetime_spend
    FROM orders
    GROUP BY customer_id
)
SELECT d.*, ct.lifetime_spend
FROM dashboard_query d
LEFT JOIN customer_totals ct ON d.customer_id = ct.customer_id
```

Result: Each dashboard row gets an additional calculated column (lifetime_spend) without modifying the original query structure.

## When to Use Each (Quick Reference)

| Scenario | Recommended | Reason |
|----------|-------------|--------|
| Add columns, keep all rows | LEFT JOIN | Preserves existing data |
| Add columns, only matched rows | INNER JOIN | Filters to complete data |
| Add calculated/aggregated columns | CTE + LEFT JOIN | Pre-compute then join |
| Data from another system | Enrichment step | Cannot query cross-system live |

## Common Mistakes

1. Using INNER JOIN when you meant LEFT JOIN (accidentally losing dashboard rows)
2. Forgetting to add new columns to the SELECT statement after writing the JOIN
3. Joining on the wrong column (always verify the shared identifier matches in both tables)
4. Not checking for duplicate rows after joining (a one-to-many relationship can multiply your rows)
Understand progressive disclosure

Your sql-join-guide.md is a "Level 3" resource in the skill system. The agent does not load it at startup. It only pulls it in when the conversation needs deeper SQL detail.

What is progressive disclosure?

Antigravity loads skill content in three levels to minimize token usage:

  • Level 1 (Metadata): The agent reads ONLY the name and description fields at startup. This costs roughly 100 tokens per skill.
  • Level 2 (Instructions): The agent loads the full SKILL.md body when it decides your skill is relevant. The recommended maximum is 5000 tokens.
  • Level 3 (Resources): The agent loads files from references/, examples/, or scripts/ ONLY when it needs additional detail during the conversation.

This means your SKILL.md can reference the guide ("See references/sql-join-guide.md for detailed SQL syntax") and the agent will only pull it in if the user needs deeper explanation.

Why not put everything in SKILL.md?

If you packed the full SQL reference into your main file, the agent would load all of that content every single time the skill activates. Most conversations only need the decision tree logic, not the full syntax guide.

Splitting into separate files keeps your skill fast and focused. The agent loads the minimum it needs, then reaches for more only when the conversation goes deeper.

Your skill now has a solid reference guide the agent can reach for when users need SQL syntax help. Next, you will create a worked example that shows the agent exactly how to walk through a real BA scenario from start to finish.

Create the Worked Example File

Your skill now has structured instructions and a reference guide. The agent knows what to do and has deeper SQL documentation to draw from.

In this step, you will give the agent a worked example. Few-shot examples dramatically improve agent output quality because the agent can pattern-match against a real scenario instead of reasoning from abstract instructions alone.

In this step, get ready to:
  • Create a worked example showing how to fix missing dashboard columns.
  • Confirm the complete skill folder structure with all three files.
Create the missing-columns example file

The examples/ directory gives the agent a concrete worked scenario to follow. Instead of reasoning purely from your Step-by-Step Process instructions, the agent can see a complete end-to-end case and pattern-match against it.

  • Create the file examples/missing-columns-fix.md inside your ba-dashboard-investigator skill folder and paste the following content:
# Example: Adding Missing Columns to a Dashboard Query

## Scenario

A Business Analyst reports: "My customer orders dashboard is missing the customer email and signup date columns. I need these for a marketing segmentation report."

## Current Dashboard Query

```sql
SELECT
    o.order_id,
    o.order_date,
    o.amount,
    o.customer_id
FROM orders o
WHERE o.order_date >= '2025-01-01'
```

## Investigation

**What is missing?** Two columns: customer email and signup date.

**Where does the data live?** These are customer attributes, so they likely live in a `customers` table.

**What is the shared identifier?** Both tables have `customer_id`.

**Which JOIN strategy?** LEFT JOIN, because:
- We want to keep ALL orders in the dashboard (even if a customer record is somehow missing)
- The data does not require calculation or aggregation
- Both tables are in the same database

## Solution

```sql
SELECT
    o.order_id,
    o.order_date,
    o.amount,
    o.customer_id,
    c.email,
    c.signup_date
FROM orders o
LEFT JOIN customers c ON o.customer_id = c.customer_id
WHERE o.order_date >= '2025-01-01'
```

## Explanation for the Business Analyst

1. We added `c.email` and `c.signup_date` to the SELECT (the columns you needed)
2. We used LEFT JOIN to connect the `customers` table using `customer_id` as the shared key
3. We chose LEFT JOIN (not INNER JOIN) so that ALL orders remain in the dashboard, even if a customer record is missing. Those rows will show NULL for email and signup_date.
4. The alias `c` refers to the customers table, and `o` refers to orders (these short names keep the query readable)

## Validation Checks

- Row count should be the SAME as before (LEFT JOIN preserves all left-table rows)
- Check for NULLs in email/signup_date columns. These indicate orders where no matching customer was found.
- If row count INCREASED, investigate whether customer_id is duplicated in the customers table (one-to-many issue)

What does this example teach the agent?

This example walks through a complete BA interaction. It starts with the problem ("my dashboard is missing columns"), works through the investigation questions, and arrives at a LEFT JOIN solution with clear reasoning.

The Validation Checks section is especially important. It teaches the agent to always remind Business Analysts to verify their results after applying the fix.

  • Save missing-columns-fix.md.

Your SKILL.md already references this file

If you open your SKILL.md and scroll to the Reference Materials section, you will see a line pointing to examples/missing-columns-fix.md. The agent uses this path to locate and load the example on demand.

File not saving?

Make sure you are saving to the correct path: .agents/skills/ba-dashboard-investigator/examples/missing-columns-fix.md. The examples/ directory was created in Step 1. If it is missing, create it with mkdir -p .agents/skills/ba-dashboard-investigator/examples.

Help me troubleshoot file creation in my Antigravity skill folder.

Verify the complete skill folder structure

Your skill now has all three files: the main instructions, a reference guide, and a worked example. This matches the progressive disclosure pattern that Antigravity uses to load skill content efficiently.

  • Confirm all three files exist by running this command:
find .agents
  • You should see this output:
.agents/skills/ba-dashboard-investigator/SKILL.md
.agents/skills/ba-dashboard-investigator/references/sql-join-guide.md
.agents/skills/ba-dashboard-investigator/examples/missing-columns-fix.md

How progressive disclosure works here

Level 1 (Metadata): The agent reads ONLY the name and description fields at startup (~100 tokens). Level 2 (Instructions): The agent loads the full SKILL.md body when activated. Level 3 (Resources): The agent loads files from references/ and examples/ ONLY when it needs additional detail.

This means your skill stays lightweight at startup. The agent only pulls in the reference guide or worked example when the user's question needs that depth.

Missing a file in the output?

Make sure you are running find .agents from the ba-skills-project/ directory. If you see only two files, double check that you saved missing-columns-fix.md in the examples/ directory and not the references/ directory.

Help me figure out why my skill folder is missing a file.

✔️ Awesome, I've got everything!

Great. Make sure all your files are saved before moving on.

ⓧ I'd like to double check the full code

Here is the complete content of each file in your skill folder.

SKILL.md:

---
name: ba-dashboard-investigator
description: Investigates dashboard SQL queries that are missing data columns and guides the user through fixing them. Helps identify the source table, choose the correct JOIN strategy (JOIN, LEFT JOIN, CTE, or enrichment step), and write the SQL to pull missing columns using a shared identifier. Use when a Business Analyst needs to add columns to an existing dashboard query, fix incomplete reports, or investigate why data is missing from a dashboard.
---

# BA Dashboard Investigator

## Goal

Help a Business Analyst identify and fix missing columns in an existing dashboard query by determining the correct data source and SQL join strategy.

## When to Use This Skill

- A dashboard or report is missing one or more data columns
- The user needs to pull additional fields from a related table
- The user needs guidance on which type of JOIN to use
- The user has a shared identifier (key) between tables but is unsure how to connect them

## Step-by-Step Process

### Step 1: Clarify What Is Missing

Ask the user:
1. What columns are missing from the current dashboard?
2. What table or query currently powers the dashboard?
3. Do you know which table contains the missing columns?

If the user does not know where the missing data lives, help them reason about it by asking what the data represents (e.g., "customer email" likely lives in a customers or users table).

### Step 2: Identify the Shared Identifier

Ask the user:
1. What column exists in BOTH the current dashboard query AND the table containing the missing data?
2. This shared column is called a "key" or "identifier" - common examples include: customer_id, order_id, user_id, product_sku

If unsure, suggest they check both tables for columns with similar names ending in _id.

### Step 3: Choose the JOIN Strategy

Use this decision tree to recommend the correct approach:

**Use INNER JOIN when:**
- You only want rows that exist in BOTH tables
- It is acceptable to lose rows from the dashboard if they do not have a match in the other table
- Example: "Show me only customers who have placed orders"

**Use LEFT JOIN when:**
- You want to KEEP all existing dashboard rows, even if some do not have matching data in the other table
- Missing matches will show as NULL values
- This is the MOST COMMON choice for adding columns to an existing dashboard
- Example: "Add email to my orders dashboard - but keep orders even if we do not have the customer email"

**Use a CTE (Common Table Expression) when:**
- The missing data requires calculation or aggregation before joining (e.g., "total orders per customer" or "most recent login date")
- You need to pre-filter or transform the data before combining it
- Example: "Add each customer's total lifetime spend to the dashboard"

**Use an enrichment step (subquery or staging table) when:**
- The data comes from a different database or system entirely
- The join would be too expensive to run in real-time
- The data needs to be refreshed on a schedule rather than queried live
- Example: "Add CRM data that lives in Salesforce to our BigQuery dashboard"

### Step 4: Write the SQL

After determining the strategy, write the SQL for the user. Always:
1. Start with the existing query (ask to see it if not provided)
2. Add the JOIN clause with the shared identifier
3. Add the new columns to the SELECT statement
4. Explain each part of the new SQL in plain language

### Step 5: Validate

Ask the user to verify:
1. Does the row count match expectations? (LEFT JOIN should keep the same count; INNER JOIN may reduce it)
2. Are the new columns showing the expected data?
3. Are there unexpected NULL values that need investigation?

## Reference Materials

- See `references/sql-join-guide.md` for detailed SQL syntax and common mistakes
- See `examples/missing-columns-fix.md` for a complete worked example of adding missing columns to a dashboard query

## Constraints

- Do NOT suggest DELETE, UPDATE, INSERT, or DROP statements. This skill is read-only.
- Always explain WHY a specific JOIN type was chosen, not just what to write.
- If the user's scenario does not fit neatly into one strategy, explain the trade-offs of each option and let them decide.
- Keep SQL examples simple and well-commented.

references/sql-join-guide.md:

# SQL JOIN Reference for Business Analysts

## What is a JOIN?

A JOIN combines rows from two or more tables based on a related column (the "key" or "shared identifier"). Think of it like matching rows in two spreadsheets using a common column like customer_id.

## JOIN Types Explained

### INNER JOIN

Returns only rows that have a match in BOTH tables.

```sql
SELECT orders.order_id, orders.amount, customers.email
FROM orders
INNER JOIN customers ON orders.customer_id = customers.customer_id
```

Result: Only orders where we have a matching customer record. Orders without a customer match are dropped.

### LEFT JOIN

Returns ALL rows from the left table (the one in FROM), plus matching data from the right table. Non-matches show NULL.

```sql
SELECT orders.order_id, orders.amount, customers.email
FROM orders
LEFT JOIN customers ON orders.customer_id = customers.customer_id
```

Result: All orders are kept. If a customer record is missing, email shows as NULL.

### CTE (Common Table Expression)

A temporary named result set defined within a query. Used when you need to calculate or transform data before joining it.

```sql
WITH customer_totals AS (
    SELECT customer_id, SUM(amount) AS lifetime_spend
    FROM orders
    GROUP BY customer_id
)
SELECT d.*, ct.lifetime_spend
FROM dashboard_query d
LEFT JOIN customer_totals ct ON d.customer_id = ct.customer_id
```

Result: Each dashboard row gets an additional calculated column (lifetime_spend) without modifying the original query structure.

## When to Use Each (Quick Reference)

| Scenario | Recommended | Reason |
|----------|-------------|--------|
| Add columns, keep all rows | LEFT JOIN | Preserves existing data |
| Add columns, only matched rows | INNER JOIN | Filters to complete data |
| Add calculated/aggregated columns | CTE + LEFT JOIN | Pre-compute then join |
| Data from another system | Enrichment step | Cannot query cross-system live |

## Common Mistakes

1. Using INNER JOIN when you meant LEFT JOIN (accidentally losing dashboard rows)
2. Forgetting to add new columns to the SELECT statement after writing the JOIN
3. Joining on the wrong column (always verify the shared identifier matches in both tables)
4. Not checking for duplicate rows after joining (a one-to-many relationship can multiply your rows)

examples/missing-columns-fix.md:

# Example: Adding Missing Columns to a Dashboard Query

## Scenario

A Business Analyst reports: "My customer orders dashboard is missing the customer email and signup date columns. I need these for a marketing segmentation report."

## Current Dashboard Query

```sql
SELECT
    o.order_id,
    o.order_date,
    o.amount,
    o.customer_id
FROM orders o
WHERE o.order_date >= '2025-01-01'
```

## Investigation

**What is missing?** Two columns: customer email and signup date.

**Where does the data live?** These are customer attributes, so they likely live in a `customers` table.

**What is the shared identifier?** Both tables have `customer_id`.

**Which JOIN strategy?** LEFT JOIN, because:
- We want to keep ALL orders in the dashboard (even if a customer record is somehow missing)
- The data does not require calculation or aggregation
- Both tables are in the same database

## Solution

```sql
SELECT
    o.order_id,
    o.order_date,
    o.amount,
    o.customer_id,
    c.email,
    c.signup_date
FROM orders o
LEFT JOIN customers c ON o.customer_id = c.customer_id
WHERE o.order_date >= '2025-01-01'
```

## Explanation for the Business Analyst

1. We added `c.email` and `c.signup_date` to the SELECT (the columns you needed)
2. We used LEFT JOIN to connect the `customers` table using `customer_id` as the shared key
3. We chose LEFT JOIN (not INNER JOIN) so that ALL orders remain in the dashboard, even if a customer record is missing. Those rows will show NULL for email and signup_date.
4. The alias `c` refers to the customers table, and `o` refers to orders (these short names keep the query readable)

## Validation Checks

- Row count should be the SAME as before (LEFT JOIN preserves all left-table rows)
- Check for NULLs in email/signup_date columns. These indicate orders where no matching customer was found.
- If row count INCREASED, investigate whether customer_id is duplicated in the customers table (one-to-many issue)

Your skill folder is complete with instructions, a reference guide, and a worked example. Next up, you will test the skill live in the Antigravity CLI and watch the agent discover and follow your custom instructions.

Test Your Skill in the Antigravity CLI

You have built a complete skill with structured instructions, a reference guide, and a worked example. Now it is time to see it in action.

In this step, you will launch the Antigravity CLI and test whether the agent can discover your skill, activate it on a relevant prompt, and follow the decision tree you wrote.

In this step, get ready to:
  • Launch the CLI and confirm the agent sees your skill.
  • Trigger the skill with a realistic Business Analyst prompt.
  • Test a different branch of the JOIN decision tree.
Launch the CLI and verify skill discovery

Before testing a prompt, you need to confirm the agent can find your skill at startup. This is Level 1 discovery, where the agent reads the name and description from your SKILL.md frontmatter.

  • Start the Antigravity CLI from your ba-skills-project/ directory by running this command:
agy
  • Once the CLI session starts, type the following command to list available skills:
/skills

You should see ba-dashboard-investigator appear in the list along with its description.

What does /skills show?

The /skills command lists every skill the agent has discovered from your workspace's .agents/skills/ directory. If your skill appears here, the agent has successfully read its metadata and can activate it when a relevant prompt comes in.

Skill not showing up?

Make sure you launched agy from inside the ba-skills-project/ directory. The CLI looks for skills relative to your current working directory.

Check that your skill folder is named exactly ba-dashboard-investigator and that it contains a file named SKILL.md (case-sensitive).

Verify that the YAML frontmatter in your SKILL.md has both opening and closing --- delimiters.

help me debug why my skill isn't appearing in the /skills list

Trigger the skill with a realistic BA prompt

The real test of a skill is whether the agent activates it automatically based on your prompt. The agent matches the words in your message against the skill's description field to decide whether to load it.

  • Type this prompt into the CLI session:
My orders dashboard is missing the customer email and signup date columns. Can you help me fix the query?
  • Watch how the agent responds. It should follow the step-by-step process from your SKILL.md.

The agent should ask you clarifying questions about the current query, identify the shared identifier, and recommend a LEFT JOIN since you are adding columns without any aggregation.

What if the agent does not use my skill?

If the agent gives a generic response without following your step-by-step process, you can explicitly reference the skill by name in your prompt. Try saying: "Use the ba-dashboard-investigator skill to help me fix my dashboard query."

The agent uses semantic matching between your prompt and the skill's description. If your prompt does not contain enough keywords that overlap with the description, the agent might not activate it automatically.

Test the decision tree with an aggregation prompt

Your skill's decision tree covers four different JOIN strategies. The first prompt tested the LEFT JOIN path. Now you will test the CTE path by asking about data that requires aggregation before joining.

  • Type this follow-up prompt into the CLI:
I need to add each customer's total lifetime order amount to my dashboard. The data is in the same orders table but needs to be summed up first.
  • Watch for the agent to recommend a CTE approach. It should explain that the data requires aggregation (summing order amounts) before it can be joined.

This confirms the agent is reading and following the decision tree logic you wrote in Step 3 of your SKILL.md.

  • Type /context to see how many tokens the skill used during this session.
  • Type /exit to close the CLI session.

Why check /context?

The /context command shows you how many tokens the agent consumed. This helps you understand how much of your skill got loaded.

Remember the progressive disclosure levels: Level 1 (metadata) is about 100 tokens at startup. Level 2 (full SKILL.md body) loads when activated. Level 3 (references and examples) loads only when the agent needs additional detail.

Agent recommended the wrong JOIN type?

If the agent suggested a LEFT JOIN instead of a CTE for the aggregation prompt, check that your SKILL.md decision tree clearly states the CTE criteria: "The missing data requires calculation or aggregation before joining."

Make sure the aggregation prompt explicitly mentions that data "needs to be summed up first." This language should trigger the CTE branch.

help me understand why the agent picked the wrong JOIN strategy

Secret mission

Extend to KPI Reporting

Your skill currently handles one type of BA request: fixing missing dashboard columns. But Business Analysts also need help building KPI reports from scratch. Can you extend your skill to handle both scenarios and prove the agent picks the right approach for each?

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally within your Antigravity IDE, so there are no ongoing costs or cloud resources to worry about.

Decide whether to keep your skill files for future use, or delete them entirely.

Resources you used:

  • Local project folder: ba-skills-project/ (contains your skill files in .agents/skills/ba-dashboard-investigator/).

Keep everything running

No action needed. Choose this if you plan to keep developing your skill or want to reference it later.

  • Your ba-skills-project/ folder stays on your machine.
  • The skill remains available in any Antigravity CLI session started from that directory.
  • There are no ongoing costs since the skill runs locally within your existing Antigravity subscription.

Pause - I'll come back to this later

Since this project is entirely local files, there is nothing to pause. Your skill files sit quietly on disk and consume no resources when the CLI is not running.

  • Close any open Antigravity CLI sessions by typing /exit.
  • Your files will be exactly as you left them when you return.

Delete - I don't want to use this again

Remove the entire project folder to start fresh.

  • Close any open Antigravity CLI sessions by typing /exit.
  • Navigate out of the project folder and delete it by running these commands:

macOS

cd ..
rm -rf ba-skills-project

Windows

cd ..
rmdir /s /q ba-skills-project
  • Confirm the folder is gone by running ls (macOS) or dir (Windows). You should no longer see ba-skills-project in the output.

Nice Work!

Nice Work!

You just built a fully functional Google Antigravity skill from scratch. Your ba-dashboard-investigator skill now teaches the AI agent how to help Business Analysts investigate and fix dashboard queries using structured decision logic.

You've learned how to:

  • Built a complete Antigravity skill with proper YAML frontmatter, a structured Markdown instruction body, a references/ directory for detailed guides, and an examples/ directory for worked scenarios.
  • Wrote a SQL JOIN decision tree that teaches the agent to choose between INNER JOIN, LEFT JOIN, CTE, and enrichment steps based on the user's scenario.
  • Tested the skill live in the Antigravity CLI and verified the agent discovers, activates, and follows your custom instructions using progressive disclosure (Level 1/2/3 loading).
  • Secret Mission: Extended the skill to handle KPI reporting prompts with a second example file and an updated skill description.

Ready to quiz yourself?