Enginatics AI Skills

Blitz Report Excel Add-in Skills / Getting Started

Run Blitz Reports in Excel

br-run-reports

Find, run, and analyze Oracle EBS Blitz Reports in Excel (GL, AP, AR, INV, PO, WIP, FA, HR and concurrent-program data).

When to use

Use when the user wants to run or analyze an Oracle/EBS report.

Install

Download br-run-reports.zip

Claude in Excel: upload the zip under Customize > Skills > Create skill. Microsoft 365 Copilot in Excel: copy the skill folder into Documents/Copilot/Microsoft Excel/Skills in your OneDrive. Or install blitz-report-excel-addin-ai-skills in Claude Code and run /blitz-report-excel-addin-ai-skills:excel-skills-setup.

Requires Blitz Report and the Blitz Report Excel add-in, connected to your Oracle EBS instance.

Blitz Reports used

View source on GitHub

Skill contents

SKILL.mdreferences/run-mechanics.md

SKILL.md

# Run Blitz Reports in Excel

You can run Oracle EBS **Blitz Reports** directly in this workbook through the custom `br_*`
worksheet functions provided by the Blitz Report Excel add-in (the "Blitz Report" ribbon in
Excel). Write a formula such as `=br_report_list_external("...")` into a cell and read the
spilled result - that is the only way to pull Oracle EBS data here; there is no separate data
connection to look for. The add-in must be loaded and connected to an environment (the user does
this once via the ribbon): `#BLITZ_NOT_CONNECTED` means ask the user to connect first, and
`#NAME?` means the add-in is not loaded.

Financial statements, account balances by period, or explaining a balance down to its journals:
use the **br-run-fsg** skill instead - it builds live statements rather than running a report.

**Read `references/run-mechanics.md` BEFORE your first run.** It carries the full workflow
detail: environment and responsibility selection, parameter and template rules, LOV value
lookups, run monitoring and recovery, error handling, worked examples, and the complete function
reference. This file is only the summary.

## Workflow summary

1. **Find the report** (skip when you already have the exact name):
   `=br_report_list_external("<search words>")` on a helper sheet named `blitz_`.
2. **Inspect parameters**: `=br_report_params_external("<Report Name>")` - set every
   `Must Set? = Yes` parameter and any filters you want; treat everything else as optional (the
   server computes defaults, including ones whose Default column shows blank).
3. **Run it**: `=br_run_report_external("<Report Name>","Name=Value; Name2=A,B,C")` (dates as
   `YYYY-MM-DD`). The cell returns `BLITZ_RUNNING:` and the data populates a NEW sheet.
   **Write the formula and read the cell back in the SAME operation batch, then immediately
   replace that cell with plain text in your next operation** - a separate read of the
   still-present formula can force a second evaluation and start a duplicate run before you
   replace it. Never re-enter the run formula to "check on" a run; poll only `_blitz_run_status`.
4. **Wait**: poll `=_blitz_run_status` (a workbook name) for `DONE: <n> rows on sheet '<name>'`
   or `ERROR: <message>` - one lightweight check per turn, generously spaced, per the reference
   file's monitoring guidance. A status read BEFORE you triggered anything is a stale leftover
   from an earlier run - ignore it and start your run; only values appearing after your trigger
   are yours.
5. **Analyze** the new sheet. The layout is fixed: row 1 = title banner, row 2 = the column
   headers, row 3 onward = the data. Never treat row 1 as headers, and never fabricate values -
   read them from the sheet.

## Core rules (full list in the reference)

- Use report and parameter names EXACTLY as the discovery functions return them.
- Keep every helper formula on `blitz_`; never activate that sheet; delete it when finished. The
  report data lands on its own new sheet - that is the user's deliverable, leave it visible.
- Once a report has produced a data sheet, do not run it again (a second run creates a duplicate
  sheet). `ERROR:` while a populated sheet exists means the data is good and only
  post-processing complained - use the data and note the warning. The same applies when an
  add-in error dialog appears AFTER the sheet populated with the expected rows: a stray
  duplicate run collided with the finished one - the data on the sheet is complete; tell the
  user to dismiss the dialog, and do not re-run.
- Talk to the user in their language ("I'm running the AR Aging report for you"), never in
  function names - the `br_*` functions and `blitz_` are internal plumbing.

references/run-mechanics.md

# br-run-reports — full run mechanics

# Run Blitz Reports in Excel

## 🚨 Blitz data comes from WORKSHEET UDFs — never from tools or connectors (read this first)

The `br_*` functions are **Excel worksheet functions (UDFs)** provided by the Blitz Report **Excel add-in** (the "Blitz Report" ribbon in Excel). Use them by **writing `=br_...()` into a cell** (via `execute_office_js` / `set_cell_range`) and reading the spilled result. They are the **only** way to pull Oracle EBS data here.

They are **NOT** MCP tools and **NOT** an MCP connector. So whenever you need Blitz data you must **never**:
- `tool_search` / look in the tool list for `br_*` — they are worksheet functions and will never appear as tools;
- call `refresh_mcp_connectors`, or look for / ask the user to add an "Oracle EBS" or "Blitz" connector — the add-in is an Excel add-in, not a connector, so it will **never** appear in the connector list, and its absence there is **expected**;
- conclude "the data source isn't connected" or "no connector is set up".

**Your first extraction action is always to write a `br_` UDF into a cell** (e.g. `=br_report_list_external("...")`, `=br_run_report_external(...)`). The only genuine "unavailable" signals are a `br_` UDF **returning** `#BLITZ_NOT_CONNECTED` (add-in loaded — the user picks an environment on the Blitz Report ribbon) or `#NAME?` (add-in not installed). A missing MCP connector is **never** a blocker.


You can run Oracle EBS **Blitz Reports** directly in this workbook through the custom add-in
functions below. You handle the language, discovery, and analysis; the Blitz Report add-in handles
authentication, execution, and deterministic full-fidelity cell population.

The Blitz Report add-in must be loaded and **connected to an environment** (the user does this once
via the Blitz Report ribbon). If a function returns `#BLITZ_NOT_CONNECTED`, ask the user to open the
Blitz Report ribbon and connect first.

## Choosing the environment and responsibility (optional)
The add-in can be connected to **several environments**, each with **several responsibilities**.
Every discovery/run function below takes an optional trailing **`environment`** and
**`responsibility`** argument; omit them to use whatever the add-in is currently on.
- See what's available: `=br_environments_external()` → `Environment | Connected | Current | URL`,
  and `=br_responsibilities_external("<Environment>")` → `Responsibility | Current`.
- Only environments showing **`Connected = Yes`** can be targeted — a UDF cannot log in. If the user
  names one that isn't connected (you get `#BLITZ_ENV_NOT_CONNECTED`), ask them to select it under
  Environments on the Blitz Report ribbon, which logs them in to it. `#BLITZ_RESP_NOT_FOUND` means that responsibility isn't available in
  the chosen environment — list them with `br_responsibilities_external` and pick a valid one.
- Selection is **sticky**: passing `environment`/`responsibility` switches the session to it for that
  call and subsequent calls, so you can set it once (e.g. on the run) or repeat it on each call.
- When the user names an environment/responsibility, pass the SAME values to the parameter-inspection
  AND the run, so the parameters/LOVs you see match where the report will actually run.

## Keep the workbook tidy — use a throwaway helper sheet
Do all discovery (`br_report_list_external`, `br_report_params_external`), the run trigger, the
status check, and any intermediate/helper formulas on a dedicated helper sheet named
**`blitz_`** (create it if it doesn't exist). Read the values you need from it, then
**delete `blitz_` when you're done** so the user's workbook stays clean.
- You must read a spill **while the sheet is visible** — so clean up *afterwards*, not before. (A
  permanently hidden sheet can't be read, which is why we delete rather than hide.)
- **Talk to the user in their language, never in function names.** The `br_*` functions, `blitz_`
  and `_blitz_run_status` are your plumbing — say "I'm running the AR Aging report for you", not
  "I'll call `br_run_report_external()` and poll `_blitz_run_status`". Report and column names are
  fine; the add-in's internals stay behind the curtain.
- **Visible does NOT mean active — never call `activate()` on `blitz_`.** Writing formulas to it and
  reading them back works perfectly well while the user stays on their own sheet; activating it just
  drops the user onto a scratch sheet. Leave the user's report/upload sheet active throughout.
- The report DATA lands on its **own new sheet** created by `br_run_report_external` — leave that
  visible; that's the deliverable.
- Keep the user's original/active sheet untouched, and present findings in the chat.

## Workflow — always follow these steps in order

### Fast path — when you already know the exact report name
If a calling skill or the user gives you the **exact** report name (e.g. "AP Period Close
Exceptions"), **skip Step 1 (discovery)** — do not run `br_report_list_external`. Go straight to
Step 3 (run) with that name (inspect params via Step 2 only if you need an exact LOV value). The run
function validates the name server-side, so a wrong name just returns `#BLITZ_REPORT_NOT_FOUND`
instantly without executing anything. **Only on that error** fall back to Step 1 to find the closest
matching name, then re-run. Step 1 below is for when you do NOT already have the name.

1. **Find the report.** On the `blitz_` helper sheet, in an empty cell write:
   `=br_report_list_external("<search words>")`
   It spills a table: `Report Name | Category | Type | Description`. Read it and choose the exact
   `Report Name`. (Search matches both name and description, so refine if too broad.)

2. **Inspect its parameters.** On `blitz_`, in an empty cell write:
   `=br_report_params_external("<Report Name>")`
   It spills: `Parameter | Type | Required | Must Set? | Multiple | Default | Has LOV | Depends On | Description`.
   - The **`Must Set?`** column is the authority on what you must provide (`Yes` = required with no
     server default at all). **Set every `Must Set? = Yes` parameter; treat everything else as
     optional** — the run fills defaults automatically, including ones the `Default` column shows as
     **blank**. A blank `Default` does NOT mean "no default": many defaults are computed at run from
     other values (e.g. `Ledger Currency` is derived from the ledger → `USD`; a ledger id is derived
     from the ledger name). If `Must Set? = ""`, omit it and let the server compute it — do not try
     to guess or enumerate it. So a `Must Set?=Yes` whose LOV returns no rows is the *only* case you
     should ask the user about; a `Must Set?=""` empty LOV just means "leave it to the server".
   - **A non-empty `Default` is applied when you omit the parameter.** E.g. if `Ledger` shows a
     default of `Vision Operations (USA)`, omitting it runs for *that* ledger — not "all ledgers".
     To scope differently (a specific value, or to broaden), set the parameter explicitly.
   - Also set any other parameters you want to filter or restrict on.
   - `Multiple = Y` means the parameter accepts a list (comma-separated values).
   - **Dependencies (`Depends On`):** a dependent parameter's valid values depend on its parent(s).
     Both the run and `br_param_values_external` **auto-apply the parent's default**, so by default a
     dependent LOV resolves under the default parent (e.g. `Period` under the default `Ledger`) — you
     do NOT have to pass the parent. To scope to a *different* parent, set that parent explicitly in
     the run, and pass it to the values lookup so the list is filtered to it:
     `=br_param_values_external("<Report Name>","<Parameter>","<Parent=Value; …>")`
     → spills `Value | ID | Description`; pass the chosen `Value` to the run.
   - You usually don't need to enumerate a parameter's values just to set it — common formats are
     obvious (periods are `Mon-YY` e.g. `Jan-08`, dates `YYYY-MM-DD`). **If the user already gave you
     the value (e.g. they said "Jan-08"), just use it — do not look it up.** Use
     `br_param_values_external` only when you need the exact spelling of an LOV value you don't know.
   - **An empty or erroring `br_param_values_external` is NOT a blocker — never abort the run over
     it.** Some `Must Set?=Yes` LOVs (e.g. `Period` on GL ledger reports) are computed at **run time**
     from values not yet resolved during a standalone lookup (a hidden ledger id), so the lookup
     returns nothing even though the report runs fine. When a lookup is empty/errors: use the value
     you already have (or the obvious format), run the report, and let the server validate it. Only
     ask the user when it's a `Must Set?=Yes` value you genuinely cannot infer **and** the lookup
     gave you nothing. Put each lookup in its **own clear cell with empty space below/right** so the
     spilled list doesn't collide (`#SPILL!`) with other helper formulas.

3. **Run it.** On `blitz_`, in an empty cell write:
   `=br_run_report_external("<Report Name>","<params>")`
   - To run against a specific environment/responsibility, add them as trailing args:
     `=br_run_report_external("<Report Name>","<params>","<template or blank>","<Environment>","<Responsibility>")`
   - `params` format: `"Name=Value; Name2=A,B,C"` — `;` separates parameters, `,` separates
     multiple values for one parameter. Dates as `YYYY-MM-DD`.
   - **Templates control the column set.** `=br_report_templates_external("<Report Name>")` lists them
     (`Template | Default? | Description`). Pass the exact name as the 3rd argument when the user asks
     for a specific layout; if several plausibly match their wording, ask rather than guess. Omit it
     and the report runs with its **default** template (the `Default?` = `Yes` row), same as the
     ribbon — pass a template explicitly if you need a different column set.
   - The cell returns `BLITZ_RUNNING: ...`. The add-in authenticates, runs the report, and creates a
     **new sheet** named after the report, populated with the data.
   - **Write the run formula and read its `BLITZ_RUNNING` return in the SAME operation batch, then
     immediately replace that formula cell's content with a plain text note (or clear it) in your
     next operation.** A separate read of the still-present formula can itself force a second
     evaluation — i.e. start a *duplicate* run — before your replace lands (seen live: the ghost
     run collided with the finished one and popped an add-in error dialog after the data had
     already landed; the data was complete). Then poll only `_blitz_run_status` (a workbook name —
     independent of the cell); never re-read or re-enter the run formula to check progress.

4. **Wait for completion — patiently, with minimal workbook activity.** On `blitz_`, read the
   workbook name with a formula: `=_blitz_run_status` → `RUNNING: ...`, then `DONE: <n> rows on
   sheet '<sheet name>'`, or `ERROR: <message>`.
   - **A status value that predates YOUR run is STALE — never act on it.** `_blitz_run_status`
     persists in the workbook across runs and sessions, so an `ERROR:` (including the bare
     `ERROR: ERROR`) read BEFORE you have triggered anything is leftover from an earlier run —
     it is not a reason to abort, retry, adapt parameters, or report failure. Start your run;
     the add-in overwrites the name with `RUNNING:` at trigger time, and only values that
     appear after that belong to you.
   - The add-in writes the result sheet in a background step (`Sheets.Add` + bulk write). Other
     workbook operations issued while it is writing can conflict with it and make the write fail
     (Excel error 1004) — the sheet then never appears and the status name is never published, so
     polling only ever shows `#NAME?`. **After triggering the run, pause your other workbook
     edits:** do ONE lightweight status check, then wait. Space the checks out generously.
   - Timer functions are not available to you here, so never wait inside a single call — do one
     quick check per turn and let the natural gap between turns give the write a clean window.
   - A **missing name / `#NAME?`** early just means the status isn't published yet — keep waiting.
   - **If it seems stuck:** when after a few patient checks there is still **no new report sheet**
     AND the status is missing/`#NAME?`, the background write likely failed. **Run the report once
     more** (the one exception to "never run a report twice" — it applies only because NO data
     sheet was created), then check once and wait. If it still never lands, explain to the user
     that the add-in's background write and this automation can interfere (a known add-in
     limitation) rather than polling forever.
   Wait until it says `DONE` before reading results.

5. **Analyze.** Open the new sheet and read the data. **The sheet layout is fixed and
   deterministic — do not probe for it:**
   - **Row 1** = a title/info banner (the report name and the run formula) — *not* data, *not* headers.
   - **Row 2** = the column headers.
   - **Row 3 onward** = the data rows, starting at column A.

   So read headers from **row 2** and data from **row 3 down**; never treat row 1 as the header row.
   Then answer the user's question (summaries, top-N, totals, trends, anomalies, etc.). Never
   fabricate values — read them from the sheet.

## Rules
- Use report and parameter names **exactly** as returned by the discovery functions (or exactly as a calling skill supplied them).
- Only pass parameters you have values for; respect `Required`.
- `#BLITZ_NOT_CONNECTED` → tell the user to open the Blitz Report ribbon and connect to an environment first.
- `#BLITZ_REPORT_NOT_FOUND` → the name didn't match; re-check with `br_report_list_external` (this is the fast-path fallback — search for the closest matching name, then re-run).
- `#BLITZ_ENV_NOT_CONNECTED` / `#BLITZ_ENV_NOT_FOUND` → the named environment isn't connected/known; the add-in can't log in from a formula, so ask the user to select it under Environments on the Blitz Report ribbon (check `br_environments_external()`).
- `#BLITZ_RESP_NOT_FOUND` → that responsibility isn't available in the chosen environment; pick one from `br_responsibilities_external("<Environment>")`.
- `_blitz_run_status` = `ERROR: ...` → report the message to the user; do not invent data. In
  particular `ERROR: Please set required parameter(s): X` means a mandatory parameter with no default
  was omitted — set it (use `br_param_values_external` for its valid values) and run again.
- **Never re-run a report that already produced a data sheet.** A second `br_run_report_external` call
  (or a recalc of the formula cell) creates a duplicate `<Report> (1)` sheet and can collide with the
  first run. If `_blitz_run_status` shows `ERROR:` **but a new sheet with data rows exists**, the data
  populated and the error is only in post-processing — **use that data, note the warning, and do NOT
  re-run.** Treat `ERROR:` as a true failure only when no populated sheet was created.
- A report can return many rows; read what you need for the analysis rather than echoing the whole sheet.

## Worked example
User: "Show me the slowest concurrent programs from the last day."
1. `=br_report_list_external("concurrent requests")` → choose `FND Concurrent Requests`.
2. `=br_report_params_external("FND Concurrent Requests")` → note `Started within Days` (Number).
3. `=br_run_report_external("FND Concurrent Requests","Started within Days=1")` → a new sheet appears.
4. `=_blitz_run_status` → `DONE: <n> rows on sheet 'FND Concurrent Requests'`.
5. Open that sheet, sort by the run-duration column, and report the slowest programs.

## Multi-value / date example
`=br_run_report_external("AR Aging","Operating Unit=Vision Operations; As of Date=2012-12-31; Phase=Completed,Running")`
- `Operating Unit` = single value; `As of Date` = ISO date; `Phase` = two values (multi-value).

## The functions (reference)
| Function | Purpose | Returns |
|---|---|---|
| `br_environments_external()` | list connected environments | spilled table: Environment, Connected, Current, URL |
| `br_responsibilities_external([environment])` | list responsibilities in an environment (current if omitted) | spilled table: Responsibility, Current |
| `br_report_list_external([search], [environment], [responsibility])` | discover reports | spilled table: Report Name, Category, Type, Description |
| `br_report_params_external(report_name, [environment], [responsibility])` | discover a report's parameters | spilled table: Parameter, Type, Required, Must Set?, Multiple, Default, Has LOV, Depends On, Description |
| `br_param_values_external(report_name, parameter, [parent=value;…], [environment], [responsibility])` | valid values for an LOV / dependent parameter (parent-filtered) | spilled table: Value, ID, Description |
| `br_run_report_external(report_name, [params], [template], [environment], [responsibility])` | run a report (blank template = the report's default template) | `BLITZ_RUNNING: ...`; data populates a new sheet; `_blitz_run_status` set to `DONE`/`ERROR` |
| `br_report_templates_external(report_name, [environment], [responsibility])` | list a report's templates (the column set) | `Template \| Default? \| Description` |
| `_blitz_run_status` (workbook name) | run completion signal | `RUNNING:` / `DONE: <n> rows on sheet '<name>'` / `ERROR: <message>` |