Agent skill
dr-drilldown
Drill down on a cell in the Datarails Excel Add-in to see underlying detail. Resolves DR.GET formulas (direct or through formula chains), reads hidden "dr control" sheet filters, queries Datarails for breakdown data, and validates totals before presenting results.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/drilldown
SKILL.md
DR.GET Drill-Down
Drill into any cell that contains Datarails data to see the underlying line-item detail. Works with:
- Cells containing a DR.GET formula directly
- Cells containing an Excel formula (SUM, +, -, etc.) whose precedents are DR.GET cells
Requirements: This skill requires Python with openpyxl to read Excel formulas. If openpyxl is not installed, run pip install openpyxl first. This skill works in Claude Code only (not Cowork).
Arguments
| Argument | Description | Default |
|---|---|---|
<cell-reference> |
The cell to drill down on, e.g. B6 or Sheet1!B6 |
Required |
--by <fields> |
Comma-separated list of fields to break down by (e.g. Account Full,Vendor) |
All available fields |
--file <path> |
Path to the .xlsx workbook file |
Ask user |
Verify Connection
If any Datarails tool call fails with an authentication or connection error, tell the user:
The Datarails connector isn't connected. Click the "+" button next to the prompt, select Connectors, find Datarails, and click Connect.
Then STOP — do not retry until the user has reconnected.
Workflow
Phase 0 - Open the Workbook
- If
--filewas provided, use that path. Otherwise ask the user for the workbook path. - Ensure openpyxl is available. If not, install it:
pip install openpyxl. - Read the workbook using Python (openpyxl) via Bash to list sheet names.
- Confirm the target sheet exists (from the cell reference or default to the active sheet).
Phase 1 - Resolve the Cell to DR.GET Parameters
Goal: Determine which DR.GET dimension filters produce the number in the target cell.
Step 1.1 - Read the Target Cell Formula
Use openpyxl with data_only=False to read the formula string from the target cell.
Step 1.2 - Classify the Formula
| Cell Content | Action |
|---|---|
Contains DR.GET |
Direct DR.GET - parse dimension pairs. Go to Step 1.3. |
Other formula starting with = |
Derived formula - find precedent cells, check each for DR.GET. Go to Step 1.4. |
| Static number (no formula) | Tell the user this cell has no formula. Cannot drill down. Stop. |
Step 1.3 - Parse a DR.GET Formula
Extract all dimension/value pairs from the formula string. A DR.GET formula has the pattern:
=DR.GET(Value, "[Dim1]", CellRef1, "[Dim2]", CellRef2, ...)
For each CellRef, resolve it to the actual value in that referenced cell. Open the workbook twice: once with data_only=True (to get cached values for referenced cells) and once with data_only=False (to get formulas).
Use this regex to parse dimension pairs from the formula string:
pattern = r'"\[([^\]]+)\]"\s*,\s*(\$?[A-Z]+\$?\d+)'
For each match, group(1) is the dimension name and group(2) is the cell reference. Strip $ from the cell reference and read the cached value from the data_only=True workbook.
This produces a dict like:
{
"DR_ACC_L1.5": {"ref": "$A6", "value": "Revenues"},
"Scenario": {"ref": "$B$1", "value": "Actuals"},
"Reporting Date": {"ref": "B$5", "value": 46053}
}
Store this as the resolved DR.GET parameters for this cell. Go to Phase 2.
Step 1.4 - Trace a Derived Formula to its DR.GET Precedents
If the cell contains a non-DR.GET formula (e.g. =B6+B7-B8), extract all cell references from the formula and recursively check each one.
Use regex to extract cell references: r'(?<![A-Z])(\$?[A-Z]+\$?\d+)'
For each referenced cell:
- If it contains a DR.GET formula, parse it per Step 1.3 and record it as a leaf node with its cached value.
- If it contains another non-DR.GET formula, recurse into it.
- If it is a static value, skip it.
Build a tree structure where:
- Each leaf is a
drgetnode withparams(resolved dimensions) andcached_value - Each non-leaf is a
derivednode withformulaandchildren - The root is the target cell
Important: When the target is a derived formula, the drill-down will produce one breakdown table per DR.GET leaf. Inform the user which DR.GET sources contribute to the number and show the breakdown for each.
Important: When extracting cell references from SUM ranges like =SUM(C6:C9), expand the range into individual cell references: C6, C7, C8, C9. Do not treat C6:C9 as two separate references.
Phase 2 - Read the "dr control" Hidden Sheet for Global Filters
The Datarails Excel Add-in stores global filters in a hidden worksheet named "dr control" (or similar names like "DR_Control", "drcontrol"). These filters restrict what data DR.GET returns - the drill-down MUST account for them.
Step 2.1 - Find the Control Sheet
Search all sheet names for any containing "control" (case-insensitive). Common names: dr control, DR_Control, drcontrol.
Step 2.2 - Extract Filter JSON
The control sheet stores filter configuration as JSON strings in cells. Scan all cells for JSON content containing FilterStorageValues.
Each cell may contain a JSON array or object. Parse it and look for objects that have a FilterStorageValues key.
Step 2.3 - Parse Filter Definitions
Each filter object has this structure:
{
"Key": "global",
"FilterStorageValues": [
{
"Id": 1646893,
"Name": "Reporting Unit",
"Type": "Text",
"Values": ["Core"],
"AllValues": [null, "###", "Collaborations", "Core", "DNA G", "DNA H", "LAB"],
"IsExcluded": false,
"IncludeNullValues": true
}
]
}
Parse each filter and build a list of active global filters:
| Filter Property | Meaning |
|---|---|
Name |
The field/dimension being filtered |
Values |
Selected values (whitelist) |
AllValues |
All possible values for this field |
IsExcluded |
If true, Values is an exclusion list (blacklist) |
IncludeNullValues |
Whether rows with NULL in this field are included |
If Values equals AllValues (or Values is empty and IsExcluded is false), the filter is not restricting anything - skip it.
If Values is a proper subset of AllValues and IsExcluded is false, this is an active filter:
Active filter: "Reporting Unit" IN ["Core"]
If IsExcluded is true, the filter means everything EXCEPT these values:
Active filter: "Reporting Unit" NOT IN ["DNA G", "DNA H"]
Store all active filters - they must be applied to the drill-down query in Phase 3.
Phase 3 - Query Datarails for the Breakdown
Now build and execute the aggregation query using the resolved DR.GET parameters + global filters from the control sheet.
Step 3.1 - Determine the Table ID
Load the client profile from config/client-profiles/<env>.json and use tables.financials.id. If no profile exists, call list_finance_tables to discover the financials table and ask the user to confirm.
Step 3.2 - Determine Drill-Down Dimensions
If the user supplied --by <fields>:
- Use those fields as the
dimensionsfor the aggregation query.
If no --by was supplied:
- Use the Datarails table schema to find all categorical fields that are NOT already pinned by the DR.GET parameters.
- Common useful drill-down dimensions:
Account Full,Account Name,Report_Field,DR_ACC_L2,Vendor,Department L1,Department L2,Reporting Unit,Entity. - Ask the user which fields they want to break down by, suggesting the most useful ones.
Step 3.3 - Build the Aggregation Query
Combine:
- DR.GET dimension filters (from Phase 1) - these become
filterson the aggregation - Global filters from dr control (from Phase 2) - these become additional
filters - Drill-down dimensions (from Step 3.2) - these become
dimensionson the aggregation - Metric:
SUMonAmount(or the appropriate value field)
Build a filters list:
- For each DR.GET parameter:
{"name": "<dim>", "values": ["<value>"], "is_excluded": false} - For each active global filter:
{"name": "<Name>", "values": <Values>, "is_excluded": <IsExcluded>}
Aggregation rules:
- Date fields (
Reporting Date,Reporting Month, etc.) must ALWAYS go indimensions, never infilters. Date filters silently return empty results. - To limit to a specific period, include the date as a dimension and filter the results client-side after the response.
- Only text fields (
Scenario,Account Group L0, etc.) go infilters.
Then call aggregate_table_data:
aggregate_table_data(
table_id="<financials_table_id>",
dimensions=["<drill-down-field-1>", "<drill-down-field-2>"],
metrics=[{"field": "Amount", "agg": "SUM"}],
filters=<combined_filters>
)
Important: Use aggregate_table_data (not get_records_by_filter or execute_query) because it has NO row limit and returns properly computed totals. The other tools cap at 500-1000 rows and would return incomplete data.
Step 3.4 - Handle Derived Formulas (Multiple DR.GET Sources)
If the target cell was a derived formula (Phase 1, Step 1.4), run a separate aggregation for each DR.GET leaf node. Present each breakdown individually, showing how they combine per the original formula.
Example for =B6-B7 where B6 = DR.GET(Revenues) and B7 = DR.GET(COGS):
- Query 1: Breakdown of Revenues by the requested fields
- Query 2: Breakdown of COGS by the requested fields
- Show both tables with a note: "Gross Profit = Revenues - COGS"
Phase 4 - Validate the Total
This step is CRITICAL. Never skip it.
After receiving the aggregation results:
- Sum all the
Amountvalues in the drill-down result. - Compare this total to the original cell value (cached value from the workbook).
- Check the match:
| Condition | Action |
|---|---|
| Totals match (within rounding tolerance of $1) | Proceed to present results |
| Totals do NOT match | DO NOT present the drill-down. Diagnose the mismatch. |
Diagnosing a Mismatch
Common causes and fixes:
| Cause | Diagnosis | Fix |
|---|---|---|
| Missing global filter | The dr control sheet has a filter you did not apply | Re-read the control sheet, check for additional filter cells or sheets |
| Wrong field mapping | A dimension name in DR.GET does not match the Datarails field name exactly | Use get_table_schema to verify field names; try alternatives (e.g. DR_ACC_L1.5 vs DR_ACC_L1) |
| Date format mismatch | Reporting Date serial number not matching | Verify the date value and format being sent |
| IncludeNullValues not applied | The global filter includes nulls but the query does not | Add a separate query for NULL values in that field and combine |
| Exclusion filter reversed | IsExcluded true was not handled correctly | Double-check: if excluded, the values should be in the exclusion list |
| Multiple control sheet cells | Filters are spread across multiple cells in the control sheet | Scan ALL cells, not just the first match |
If the mismatch cannot be resolved after 2 attempts:
- Tell the user the exact numbers: "The cell shows X but the drill-down totals to Y (difference of Z)."
- Explain what filters were applied.
- Ask the user if they want to see the partial results anyway, clearly flagged as unvalidated.
Phase 5 - Present the Results
For Direct DR.GET Cells
Show a single table with the drill-down data:
Drill-down: Cell B6 = $1,234,567 (Revenues, Actuals, Jan-26)
Active global filters: Reporting Unit = "Core"
| Account Name | Amount |
|------------------------|-------------|
| Subscription Revenue | $1,100,000 |
| Implementation Revenue | $134,567 |
| **Total** | **$1,234,567** |
Total matches cell value.
For Derived Formula Cells
Show each component table plus how they combine:
Drill-down: Cell B8 = $900,000 (Gross Profit = Revenues - COGS)
Component 1: Revenues (Cell B6 = $1,234,567)
| Account Name | Amount |
|------------------------|-------------|
| ... | ... |
Component 2: COGS (Cell B7 = $334,567)
| Account Name | Amount |
|---------------------------|------------|
| ... | ... |
Gross Profit = $1,234,567 - $334,567 = $900,000
Formatting Rules
- Use markdown tables.
- Format numbers with commas and appropriate decimal places.
- Sort rows by absolute amount descending.
- If there are more than 30 rows, show the top 20 and summarize the rest as "Other (N items)".
- Always show the total row at the bottom.
- Always state whether the total matches the original cell value.
Error Handling
| Error | Action |
|---|---|
| Workbook cannot be opened | Ask user to verify path; check file is not open exclusively in Excel |
| openpyxl not installed | Run pip install openpyxl and retry |
| Cell has no formula | Tell user: "This cell contains a static value (no formula). Cannot drill down." |
| No DR.GET found in formula chain | Tell user: "This cell formula does not reference any DR.GET cells. Cannot drill down." |
| No control sheet found | Warn: "No dr control sheet found. Proceeding without global filters - totals may not match if filters are applied in the add-in." |
| Table not found in Datarails | Ask user to run /dr-learn to set up the client profile |
| Total mismatch after retries | Report the mismatch clearly and offer partial results flagged as unvalidated |
Examples
Example 1: Direct DR.GET cell
User: /dr-drilldown B6 --file budget.xlsx
Cell B6 contains =DR.GET(Value, "[DR_ACC_L1.5]", $A6, "[Scenario]", $B$1, "[Reporting Date]", B$5)
- Resolves: DR_ACC_L1.5=Revenues, Scenario=Actuals, Reporting Date=46053
- Reads dr control: Reporting Unit filter = "Core"
- Queries Datarails with all filters, broken down by all available fields
- Validates total, presents full breakdown
Example 2: Drill down by specific field
User: /dr-drilldown B6 --by "Report_Field" --file budget.xlsx
Same resolution, but only breaks down by Report_Field.
Example 3: Derived formula (Gross Profit)
User: /dr-drilldown B8 --file budget.xlsx
Cell B8 contains =B6-B7 where B6 is DR.GET(Revenues) and B7 is DR.GET(COGS).
- Resolves both DR.GET sources
- Runs two separate breakdowns
- Shows both and how they combine to the Gross Profit number
Example 4: SUM of DR.GET cells
User: /dr-drilldown C10 --file model.xlsx
Cell C10 contains =SUM(C6:C9) where C6-C9 are all DR.GET cells.
- Resolves all four DR.GET sources
- Runs aggregation for each
- Shows combined breakdown with validated total
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?