Behavioral Rules¶
These rules ensure efficient and reliable Excel automation. AI assistants should follow these guidelines when executing Excel operations.
System Prompt Rules (LLM-Validated)¶
These rules are validated by automated LLM tests and MUST be followed:
- Execute tasks immediately without asking for confirmation
- Never ask clarifying questions - make reasonable assumptions and proceed
- Ask the user whether they want Excel visible or hidden when starting multi-step tasks
- When the user asks to "show Excel" or "watch" the work, use
window(show)+window(arrange)to position it - Format Excel files professionally (proper column widths, headers, number formats)
- Always format data ranges as Excel Tables (not plain ranges)
- Always end with a text summary - never end on just a tool call or command
CRITICAL: No Clarification Questions¶
STOP. If you are about to ask "Which file?", "What table?", "Where should I put this?" - DON'T.
Instead, discover the information yourself:
| Bad (Asking) | Good (Discovering) |
|---|---|
| "Which Excel file should I use?" | file(list) → use the open session |
| "What's the table name?" | table(list) → discover tables |
| "Which sheet has the data?" | worksheet(list) → check all sheets |
| "Should I create a PivotTable?" | YES - create it on a new sheet |
| "What values should I filter?" | Read the data first, then filter appropriately |
You have tools to answer your own questions. USE THEM.
Core Execution Rules¶
Execute Immediately¶
Do NOT ask clarifying questions for standard operations. Proceed with reasonable defaults:
- File creation: Create the file and report the path
- Data operations: Execute the operation and report results
- Formatting: Apply formatting and confirm completion
When to ask: Only when the request is genuinely ambiguous (e.g., "update the data" without specifying what data or which file).
Ask About Excel Visibility¶
When starting a multi-step task, ask the user whether they want Excel visible or hidden. Present two clear action card choices:
Watch me work — Show Excel side-by-side so you see every change live. Operations run slightly slower because Excel renders each update on screen.
Work in background — Keep Excel hidden for maximum speed. You won't see changes until the task is done, but operations complete faster.
Skip asking when the user has already stated a preference: - User says "show me Excel", "let me watch", "I want to see it" → Show immediately - User says "just do it", "work in background" → Keep hidden - Simple one-shot operations (e.g., "what's in A1?") → Keep hidden, no need to ask
If the user doesn't respond, keep Excel hidden.
How to show Excel:
1. window(action: 'show') → Make visible
2. window(action: 'arrange', preset: 'left-half') → Position for side-by-side
Do NOT: - Show Excel without the user choosing to see it - Tell users to look at Excel windows unless Excel is visible - Reference Excel UI elements when Excel is hidden - Suggest manual Excel interactions
Format Professionally¶
When creating or modifying Excel files:
- Set appropriate column widths for content
- Apply header formatting (bold, filters)
- Use proper number formats (currency, dates, percentages) with
range set-number-format - Auto-fit variable-width data with
range_format auto-fit-columnsorrange_format auto-fit-rows - Format data as Excel Tables (not plain ranges)
- When the same visual styling applies to multiple disjoint ranges on one sheet, use
range_format format-ranges
Tool split to remember: - range owns number display formats such as dates, currency, percentages, and text display - range_format owns visual styling, validation, auto-fit, and explicit width/height changes
Use set-style for semantic status labels and document structure: - Good / Bad / Neutral — colour-coded status cells (green/red/yellow fills, theme-aware) - Heading 1 / Heading 2 / Title — document hierarchy - Normal — reset all formatting
Use format-range for visual layout (header rows, custom colours) — ALL properties in ONE call: - set-style('Heading 1') does NOT apply a fill colour; if you want a coloured header row use format-range - Pass bold, fill_color, font_color, and alignment together in a single call — do not call format-range multiple times for the same range - If the same formatting payload repeats across multiple non-contiguous ranges, prefer one format-ranges call over repeated format-range calls
Apply each formatting operation once — do not reapply the same properties to the same range unless a later step explicitly changes them.
Format Cells by Data Type (CRITICAL)¶
Always apply number formats after setting values. Without formatting: - Dates appear as serial numbers (45678 instead of 2025-01-22) - Currency appears as plain numbers (1234.56 instead of $1,234.56) - Percentages appear as decimals (0.15 instead of 15%)
Common format codes (US locale, auto-translated):
| Data Type | Format Code | Result (en-US) |
|---|---|---|
| USD | $#,##0.00 | $1,234.56 |
| EUR | €#,##0.00 | €1,234.56 |
| Number | #,##0.00 | 1,234.56 |
| Percent | 0.00% | 15.00% |
| Date (ISO) | yyyy-mm-dd | 2025-01-22 |
| Date (US) | mm/dd/yyyy | 01/22/2025 |
Rendered output is locale-dependent. The Result column assumes en-US regional settings. Excel interprets , and . in a format code according to the user's locale, so $#,##0.00 displays as $1,234.56 on en-US but $1.234,56 on de-DE — same code, different separators. Always write the US form (it is auto-translated), never promise a literal rendering, and never "correct" a format code because a screenshot shows swapped separators.
Workflow:
1. range set-values (data is now in cells)
2. range set-number-format (apply format to range)
3. range_format auto-fit-columns (widen columns to fit — formatted dates and
long numbers render as ##### at the default column width)
Format Tabular Data as Excel Tables¶
Always convert tabular data to Excel Tables (ListObjects):
1. range set-values (write data including headers)
2. table(action: 'create', table_name: 'SalesData', range_address: 'A1:D100')
Why Tables over plain ranges: - Structured references: =SUM(Sales[Amount]) instead of =SUM(B2:B100) - Auto-expand when rows are added - Built-in filtering, sorting, and banded rows - Required for add-to-data-model action (Data Model/DAX) - Named reference for Power Query: Excel.CurrentWorkbook(){[Name="SalesData"]}
When NOT to use Tables: - Single-cell parameters (use named ranges instead) - Layout areas with merged cells - Print-formatted reports with specific spacing
Named range listing: namedrange list returns visible user-defined names. Hidden/internal Excel names, including Power Query ExternalData_* and AutoFilter names, are omitted before value inspection. Large named ranges return metadata without a value preview; use namedrange read or range get-values when the actual value is needed.
Report Results¶
After completing operations, report:
- What was created/modified
- File path (for new files)
- Any relevant statistics (row counts, etc.)
CRITICAL: Always End With a Text Response¶
NEVER end your turn with only a tool call or command execution. After all operations are complete, you MUST provide a text message summarizing what was accomplished.
| Bad (Silent completion) | Good (Text summary) |
|---|---|
| (tool call with no text) | "Created PivotTable 'SalesPivot' with tabular layout on the Analysis sheet." |
| (just runs a command) | "Set the PivotTable to compact layout (row fields in a single indented column)." |
Why: Users and automation expect a text confirmation. A silent tool call or command with no follow-up text is an incomplete response.
Session Lifecycle¶
Use file(action: 'test') or excelcli -q session test <path> before opening when access or information protection is uncertain. The shared result reports canOpen, isIrmProtected, willOpenReadOnly, and requiresVisibleSession. IRM/AIP files report canOpen:false until the required interactive Excel authentication occurs; open them with a visible session.
Always close sessions when done:
1. file(action: 'open', path: '...') → sessionId
2. All operations use `session_id`
3. file(action: 'close', session_id: '...', save: true) → saves and closes
Why: Unclosed sessions leave Excel processes running, consuming memory and locking files.
Format Results as Tables¶
When presenting data to users, format as Markdown tables:
| Column A | Column B | Column C |
|----------|----------|----------|
| Value 1 | Value 2 | Value 3 |
NOT as raw JSON arrays: [["Column A","Column B"],["Value 1","Value 2"]]
Data Model Output Rules¶
Choose the Right Display Method¶
When displaying Data Model data:
| Scenario | Use | NOT |
|---|---|---|
| Show DAX query results | table create-from-dax | PivotTable |
| Static report/snapshot | table create-from-dax | PivotTable |
| Data needed in formulas | table create-from-dax | PivotTable |
| User needs interactive filtering | pivottable | DAX table |
| Cross-tabulation layout | pivottable | DAX table |
Why: PivotTables add UI complexity (field panes, refresh prompts) that's unnecessary for simple data display. DAX-backed tables are cleaner for presenting query results.
Chart Data Model Data Directly¶
When creating charts from Data Model:
- Use:
chart create-from-pivottable(creates and verifies a live PivotChart) - NOT: Create a regular chart from the PivotTable's displayed cell range
Why: The verified PivotLayout link keeps field changes and refreshes live.
Data Modification Rules¶
Verify Before Delete¶
Before deleting tables, worksheets, or named ranges:
- List existing items first
- Confirm the exact name exists
- Delete the specified item
Why: Delete operations cannot be undone. Verification prevents accidental data loss.
Targeted Updates Over Wholesale Replace¶
When updating data:
- Prefer:
set-valueson specific range (e.g.,A5:C5for row 5) - Avoid: Deleting and recreating entire structures
Why: Targeted updates preserve formatting, formulas, and references that wholesale replacement destroys.
Save Explicitly¶
Call file(action: 'close', save: true) to persist changes:
- Operations modify the in-memory workbook
- Changes are NOT automatically saved to disk
- Session termination WITHOUT save loses all changes
Workflow Sequencing Rules¶
Data Model Prerequisites¶
DAX operations require tables in the Data Model:
Step 1: Create or import data → Table exists
Step 2: table(action: 'add-to-data-model') → Table in Data Model
Step 3: datamodel(action: 'create-measure') → NOW this works
Skipping Step 2 causes DAX operations to fail with "table not found".
Power Query Load Destinations¶
Choose load destination based on workflow:
| Destination | When to Use |
|---|---|
worksheet / load-to-table | View data, simple analysis |
data-model / load-to-data-model | DAX measures, PivotTables, relationships |
both / load-to-both | View data AND use in DAX |
connection-only | Data staging, intermediate queries |
Values are case-insensitive. Unknown enum values and parameters that do not belong to the selected action are rejected instead of being defaulted or ignored.
Canonical Public Inputs¶
- Public timeouts are integer seconds: MCP uses
timeout_seconds, CLI uses--timeout, and batch JSON usestimeout. Do not send TimeSpan strings or numeric strings. - Session open/create accepts 10-3600 seconds. Its operation timeout controls workbook startup and operations that do not provide a dedicated data-operation timeout.
- Power Query refresh/refresh-all accepts 0-2147483; omitted or
0uses the 30-minute data-operation default. Connection, Data Model, PivotTable, and VBA timeouts accept 1-2147483. - Power Query refresh/refresh-all use their data-operation timeout instead of layering the session operation timeout.
load-tohas no caller timeout and uses the fixed 30-minute data-operation timeout; create/update/evaluate use the session operation timeout. - For required generated inline/file pairs, supply exactly one form. Optional pairs may omit both, but inline and file forms are always mutually exclusive. Batch aliases are
mCodeFile,vbaCodeFile,daxFormulaFile,daxQueryFile,dmvQueryFile,schemaFile, andxmlDataFile; MCP uses snake_case and CLI uses kebab-case. The file must exist and be readable.
Refresh After Create¶
powerquery(action: 'create') imports the M code but does NOT execute it:
Step 1: powerquery(action: 'create', ...) → Query created
Step 2: powerquery(action: 'refresh', query_name: '...') → Data loaded
Without refresh, the query exists but contains no data.
Error Handling Rules¶
Interpret Error Messages¶
Excel MCP errors include actionable context:
{
"success": false,
"errorMessage": "Table 'Sales' not found in Data Model",
"suggestedNextActions": ["table(action: 'add-to-data-model', table_name: 'Sales')"]
}
Follow suggestedNextActions when provided.
Use the structured errorCategory when it is present. For InvalidInput, NotFound, or Conflict, correct the named input or workbook state before retrying. For SessionNotFound, reopen the workbook once and continue with the new session ID. A timeout, cancellation, or dead Excel process can invalidate and close the session; reopen it instead of retrying against the old session.
Retry with Corrections¶
If an operation fails:
- Read the error message carefully
- Check prerequisites (session, table in Data Model, etc.)
- Retry with corrected parameters
Do NOT immediately re-run the same failing command.
Report Failures Clearly¶
When operations fail:
- State what was attempted
- Explain what went wrong
- Suggest the corrective action
Good: "Failed to add DAX measure: Table 'Sales' is not in the Data Model. Use table(action: 'add-to-data-model') first."
Bad: "An error occurred."