Skip to content

Examples

Real-world prompts showing how an AI agent uses each tool, with full request parameters and response JSON.


Getting Started

Explore a Workbook

"What's in the spreadsheet I have open?"

Step 1 -- The agent discovers the workbook structure:

json
// Tool: get_active_workbook()

// Response
{
  "name": "sales_report_2024.xlsx",
  "path": "C:\\Users\\user\\Documents\\sales_report_2024.xlsx",
  "sheets": [
    { "name": "Revenue", "used_range": "$A$1:$N$45", "rows": 45, "columns": 14 },
    { "name": "Expenses", "used_range": "$A$1:$H$30", "rows": 30, "columns": 8 },
    { "name": "Dashboard", "used_range": "$A$1:$P$25", "rows": 25, "columns": 16 }
  ],
  "active_sheet": "Revenue",
  "selection": {
    "address": "$B$5:$D$10",
    "sheet": "Revenue",
    "data": [["Product", "Q1", "Q2"], ["Widget A", 12500, 13800], ["Widget B", 8400, 9100], ["Widget C", 15200, 16700], ["Widget D", 6300, 7200], ["Widget E", 11000, 12400]],
    "rows": 6,
    "columns": 3
  }
}

The agent now knows there are 3 sheets and can see the currently selected data. It decides to get more detail on the active sheet.

Step 2 -- The agent reads the sheet summary to understand structure:

json
// Tool: read_data()
// Parameters: (none -- omitting cell_range returns a summary)

// Response
{
  "sheet": "Revenue",
  "used_range": "$A$1:$N$45",
  "total_rows": 45,
  "total_columns": 14,
  "headers": ["Region", "Product", "Q1 Sales", "Q2 Sales", "Q3 Sales", "Q4 Sales", "Total", null, "YoY Growth"],
  "merged_cells": [
    { "range": "$A$1:$N$1", "value": "Annual Sales Report 2024", "rows": 1, "columns": 14 },
    { "range": "$A$3:$A$15", "value": "North", "rows": 13, "columns": 1 },
    { "range": "$A$16:$A$28", "value": "South", "rows": 13, "columns": 1 }
  ],
  "regions": [
    { "range": "$A$1:$N$45", "rows": 45, "columns": 14 }
  ]
}

The agent sees merged headers spanning multiple columns, merged region labels down column A, and that the data starts at row 3 with headers in row 2.

Step 3 -- The agent reads the actual data:

json
// Tool: read_data()
// Parameters: { "cell_range": "A2:G20", "merge_info": true }

// Response
{
  "range": "$A$2:$G$20",
  "sheet": "Revenue",
  "rows": 19,
  "columns": 7,
  "headers": ["Region", "Product", "Q1 Sales", "Q2 Sales", "Q3 Sales", "Q4 Sales", "Total"],
  "data": [
    ["North", "Widget A", 12500, 13800, 14200, 15600, 56100],
    ["North", "Widget B", 8400, 9100, 8900, 9800, 36200],
    ["North", "Widget C", 15200, 16700, 17100, 18300, 67300]
  ],
  "merged_ranges": [
    { "range": "$A$3:$A$15", "value": "North" }
  ]
}

With merge_info=true, every row under the merged "North" cell gets the value filled in, so the agent can process the data without null gaps.


Summarize Selected Data

"Summarize the data I've selected in Excel"

json
// Tool: get_active_workbook()

// Response
{
  "name": "budget_2025.xlsx",
  "path": "C:\\Users\\user\\budget_2025.xlsx",
  "sheets": [
    { "name": "Operating", "used_range": "$A$1:$F$50", "rows": 50, "columns": 6 }
  ],
  "active_sheet": "Operating",
  "selection": {
    "address": "$A$1:$F$12",
    "sheet": "Operating",
    "data": [
      ["Category", "Jan", "Feb", "Mar", "Q1 Total", "Budget"],
      ["Payroll", 85000, 85000, 87000, 257000, 260000],
      ["Rent", 12000, 12000, 12000, 36000, 36000],
      ["Utilities", 3200, 3500, 2900, 9600, 10000],
      ["Software", 8500, 8500, 9200, 26200, 25000],
      ["Marketing", 15000, 22000, 18000, 55000, 50000],
      ["Travel", 4500, 6200, 3800, 14500, 15000],
      ["Supplies", 1200, 1400, 1100, 3700, 4000],
      ["Insurance", 5000, 5000, 5000, 15000, 15000],
      ["Training", 2000, 0, 3500, 5500, 8000],
      ["Misc", 800, 1200, 600, 2600, 3000],
      ["Total", 137200, 144800, 143100, 425100, 426000]
    ],
    "rows": 12,
    "columns": 6
  }
}

The selection data is returned directly by get_active_workbook() -- no additional call needed. The agent can immediately summarize: Q1 operating expenses totaled $425,100 against a $426,000 budget, with Marketing ($55,000) exceeding its $50,000 budget while most other categories came in under.


Analyze Sheet Structure

"What tables are in this sheet? It looks complicated."

json
// Tool: read_data()
// Parameters: (none)

// Response
{
  "sheet": "Consolidated",
  "used_range": "$B$2:$T$85",
  "total_rows": 84,
  "total_columns": 19,
  "headers": ["Division", "Account", null, null, "2023 Actual", "2024 Budget", "2024 Actual", "Variance"],
  "merged_cells": [
    { "range": "$B$2:$T$2", "value": "FY2024 Consolidated Financial Summary", "rows": 1, "columns": 19 },
    { "range": "$B$4:$H$4", "value": "Income Statement", "rows": 1, "columns": 7 },
    { "range": "$B$40:$H$40", "value": "Balance Sheet", "rows": 1, "columns": 7 },
    { "range": "$J$4:$T$4", "value": "Cash Flow Statement", "rows": 1, "columns": 11 }
  ],
  "regions": [
    { "range": "$B$4:$H$38", "rows": 35, "columns": 7 },
    { "range": "$B$40:$H$85", "rows": 46, "columns": 7 },
    { "range": "$J$4:$T$60", "rows": 57, "columns": 11 }
  ]
}

The agent identifies three distinct tables: an Income Statement (B4:H38), a Balance Sheet (B40:H85), and a Cash Flow Statement (J4:T60). The merged cells at row 2 and row 4 serve as the report title and table headers respectively.


Reading and Analysis

Batch Read All Sheets

"Give me a summary of every sheet in this workbook"

json
// Tool: read_data()
// Parameters: { "sheet": "*" }

// Response
{
  "sheet_count": 4,
  "sheets": {
    "Revenue": {
      "sheet": "Revenue",
      "used_range": "$A$1:$N$45",
      "total_rows": 45,
      "total_columns": 14,
      "headers": ["Region", "Product", "Q1 Sales", "Q2 Sales", "Q3 Sales", "Q4 Sales", "Total"]
    },
    "Expenses": {
      "sheet": "Expenses",
      "used_range": "$A$1:$H$30",
      "total_rows": 30,
      "total_columns": 8,
      "headers": ["Department", "Category", "Amount", "Approved", "Paid", "Remaining"]
    },
    "Headcount": {
      "sheet": "Headcount",
      "used_range": "$A$1:$E$120",
      "total_rows": 120,
      "total_columns": 5,
      "headers": ["Employee ID", "Name", "Department", "Title", "Start Date"]
    },
    "Dashboard": {
      "sheet": "Dashboard",
      "used_range": "$A$1:$P$25",
      "total_rows": 25,
      "total_columns": 16,
      "headers": ["KPI", "Target", "Actual", "Status"]
    }
  }
}

A single call with sheet="*" returns structure summaries for all 4 sheets. The agent can now decide which sheets need deeper reading.


Read Data with Merged Cells

"Read the project schedule table -- the phase names are merged across multiple rows"

json
// Tool: read_data()
// Parameters: { "cell_range": "B5:F18", "merge_info": true }

// Response
{
  "range": "$B$5:$F$18",
  "sheet": "Schedule",
  "rows": 14,
  "columns": 5,
  "headers": ["Phase", "Task", "Owner", "Start", "End"],
  "data": [
    ["Planning", "Requirements gathering", "Kim", "2024-01-08", "2024-01-19"],
    ["Planning", "Stakeholder review", "Park", "2024-01-22", "2024-01-26"],
    ["Planning", "Scope finalization", "Kim", "2024-01-29", "2024-02-02"],
    ["Development", "Backend API", "Lee", "2024-02-05", "2024-03-15"],
    ["Development", "Frontend UI", "Choi", "2024-02-12", "2024-03-22"],
    ["Development", "Integration", "Lee", "2024-03-25", "2024-04-05"],
    ["Testing", "QA testing", "Jung", "2024-04-08", "2024-04-26"],
    ["Testing", "UAT", "Park", "2024-04-29", "2024-05-10"],
    ["Deployment", "Staging release", "Lee", "2024-05-13", "2024-05-17"],
    ["Deployment", "Production release", "Lee", "2024-05-20", "2024-05-24"]
  ],
  "merged_ranges": [
    { "range": "$B$6:$B$8", "value": "Planning" },
    { "range": "$B$9:$B$11", "value": "Development" },
    { "range": "$B$12:$B$13", "value": "Testing" },
    { "range": "$B$14:$B$15", "value": "Deployment" }
  ]
}

Without merge_info=true, the Phase column would show "Planning" only in the first merged row and null for the rest. With it enabled, every row gets the correct phase label.


Handle Non-Standard Header Positions

"This sheet has a title block at the top. The actual column headers are on row 4."

json
// Tool: read_data()
// Parameters: { "cell_range": "A1:H20", "header_row": 4 }

// Response
{
  "range": "$A$1:$H$20",
  "sheet": "Inventory",
  "rows": 20,
  "columns": 8,
  "headers": ["SKU", "Product Name", "Category", "Warehouse", "Qty On Hand", "Reorder Point", "Unit Cost", "Total Value"],
  "data": [
    ["SKU-001", "Industrial Valve 2in", "Plumbing", "Warehouse A", 340, 100, 45.50, 15470.00],
    ["SKU-002", "Copper Pipe 1in x 10ft", "Plumbing", "Warehouse A", 1200, 500, 12.75, 15300.00],
    ["SKU-003", "Circuit Breaker 20A", "Electrical", "Warehouse B", 85, 50, 28.90, 2456.50],
    ["SKU-004", "LED Panel Light 2x4", "Electrical", "Warehouse B", 210, 75, 62.00, 13020.00],
    ["SKU-005", "HVAC Filter 20x25", "HVAC", "Warehouse C", 450, 200, 8.50, 3825.00]
  ]
}

When a spreadsheet has a company logo, title, or metadata in rows 1-3, setting header_row=4 tells the tool to treat row 4 as the column header row. Data is returned starting from row 5 onward with proper header labels.


Find All Formulas

"Show me all formulas in the Revenue sheet so I can audit the calculations"

json
// Tool: get_formulas()
// Parameters: { "cell_range": "A1:N45", "sheet": "Revenue", "values_too": true }

// Response
{
  "formulas": [
    { "cell": "G3", "formula": "=SUM(C3:F3)", "value": 56100 },
    { "cell": "G4", "formula": "=SUM(C4:F4)", "value": 36200 },
    { "cell": "G5", "formula": "=SUM(C5:F5)", "value": 67300 },
    { "cell": "G15", "formula": "=SUM(G3:G14)", "value": 382400 },
    { "cell": "G28", "formula": "=SUM(G16:G27)", "value": 298700 },
    { "cell": "G30", "formula": "=G15+G28", "value": 681100 },
    { "cell": "H3", "formula": "=(G3-N3)/N3", "value": 0.0842 },
    { "cell": "H4", "formula": "=(G4-N4)/N4", "value": -0.0156 },
    { "cell": "N3", "formula": "='2023 Data'!G3", "value": 51740 }
  ],
  "total_formula_cells": 9,
  "range": "$A$1:$N$45",
  "sheet": "Revenue"
}

The agent finds SUM formulas for row totals (column G), growth-rate calculations referencing prior-year data (column H), and cross-sheet references pulling from the "2023 Data" sheet (column N). This gives a complete picture of the calculation logic.


Identify Formatting Patterns with Styles

"I need to understand the visual structure of this sheet. Which cells are headers vs data vs totals?"

json
// Tool: get_cell_styles()
// Parameters: { "cell_range": "A1:H30", "sheet": "PnL", "properties": ["bold", "bg_color", "font_color", "font_size"] }

// Response
{
  "range": "$A$1:$H$30",
  "sheet": "PnL",
  "styles": [
    { "cell": "A1", "bold": true, "bg_color": "#1B3A5C", "font_color": "#FFFFFF", "font_size": 14 },
    { "cell": "B1", "bold": true, "bg_color": "#1B3A5C", "font_color": "#FFFFFF", "font_size": 14 },
    { "cell": "C1", "bold": true, "bg_color": "#1B3A5C", "font_color": "#FFFFFF", "font_size": 14 },
    { "cell": "A2", "bold": true, "bg_color": "#D6E4F0" },
    { "cell": "B2", "bold": true, "bg_color": "#D6E4F0" },
    { "cell": "A10", "bold": true, "bg_color": "#E2EFDA" },
    { "cell": "A15", "bold": true, "font_color": "#C00000" },
    { "cell": "A20", "bold": true, "bg_color": "#FFF2CC" },
    { "cell": "A25", "bold": true, "bg_color": "#1B3A5C", "font_color": "#FFFFFF" }
  ]
}

The agent can now deduce the visual hierarchy: dark blue background (#1B3A5C) with white text = top-level headers, light blue (#D6E4F0) = section headers, green (#E2EFDA) = subtotal rows, red font (#C00000) = negative/loss indicators, and yellow (#FFF2CC) = highlight rows. Only cells with non-default styling are returned, keeping the response compact.


Combining Styles and Data to Understand Structure

"Read the P&L sheet and help me figure out which rows are section headers vs data rows"

Step 1 -- Read styles to identify header rows:

json
// Tool: get_cell_styles()
// Parameters: { "cell_range": "A1:A30", "sheet": "PnL", "properties": ["bold", "bg_color"] }

// Response
{
  "range": "$A$1:$A$30",
  "sheet": "PnL",
  "styles": [
    { "cell": "A1", "bold": true, "bg_color": "#1B3A5C" },
    { "cell": "A2", "bold": true, "bg_color": "#D6E4F0" },
    { "cell": "A8", "bold": true, "bg_color": "#D6E4F0" },
    { "cell": "A14", "bold": true },
    { "cell": "A15", "bold": true, "bg_color": "#D6E4F0" },
    { "cell": "A22", "bold": true },
    { "cell": "A25", "bold": true, "bg_color": "#E2EFDA" }
  ]
}

Step 2 -- Read the actual data in column A to see the labels:

json
// Tool: read_data()
// Parameters: { "cell_range": "A1:H30", "sheet": "PnL" }

// Response
{
  "range": "$A$1:$H$30",
  "sheet": "PnL",
  "rows": 30,
  "columns": 8,
  "headers": ["Account", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "H1 Total"],
  "data": [
    ["Revenue", null, null, null, null, null, null, null],
    ["Product Sales", 125000, 132000, 128000, 141000, 138000, 145000, 809000],
    ["Service Revenue", 45000, 47000, 46000, 48000, 49000, 51000, 286000],
    ["License Fees", 18000, 18000, 18000, 18000, 18000, 18000, 108000],
    ["Other Income", 3200, 2800, 4100, 3600, 2900, 3800, 20400],
    ["Total Revenue", 191200, 199800, 196100, 210600, 207900, 217800, 1223400],
    ["Cost of Goods Sold", null, null, null, null, null, null, null],
    ["Direct Materials", 42000, 44500, 43200, 47800, 46500, 49000, 273000],
    ["Direct Labor", 31000, 31000, 31500, 32000, 32000, 33000, 190500],
    ["Manufacturing Overhead", 15000, 15200, 15100, 15800, 15600, 16000, 92700],
    ["Total COGS", 88000, 90700, 89800, 95600, 94100, 98000, 556200],
    ["Gross Profit", 103200, 109100, 106300, 115000, 113800, 119800, 667200],
    ["Operating Expenses", null, null, null, null, null, null, null]
  ]
}

By cross-referencing styles and data: rows with bg_color=#D6E4F0 (A2, A8, A15) are section headers ("Revenue", "Cost of Goods Sold", "Operating Expenses"). Rows that are bold-only (A14, A22) are subtotals ("Total Revenue", "Total COGS"). Rows with green background (A25) are grand totals. Plain rows are data entries.


Discover Dashboard Charts and Objects

"What charts and images are on the Dashboard sheet?"

json
// Tool: get_objects()
// Parameters: { "sheet": "Dashboard" }

// Response
{
  "sheet": "Dashboard",
  "charts": [
    {
      "name": "Chart 1",
      "top_left_cell": "$B$2",
      "width": 520,
      "height": 320,
      "chart_type": "5",
      "title": "Monthly Revenue Trend"
    },
    {
      "name": "Chart 2",
      "top_left_cell": "$J$2",
      "width": 400,
      "height": 320,
      "chart_type": "70",
      "title": "Revenue by Region"
    },
    {
      "name": "Chart 3",
      "top_left_cell": "$B$20",
      "width": 520,
      "height": 300,
      "chart_type": "51",
      "title": "Budget vs Actual"
    }
  ],
  "images": [
    { "name": "Picture 1", "top_left_cell": "$A$1", "width": 180, "height": 60 }
  ],
  "shapes": [
    { "name": "TextBox 1", "top_left_cell": "$J$20", "width": 400, "height": 40 }
  ]
}

The agent finds 3 charts (a line chart for revenue trend, a pie chart for regional breakdown, and a bar chart for budget comparison), a company logo image at A1, and a text box annotation. This helps the agent understand the dashboard layout and describe it to the user without needing to "see" the visuals.


Writing and Formatting

Write Data to a Range

"Create a summary table in the Summary sheet starting at A1"

json
// Tool: write_data()
// Parameters:
{
  "start_cell": "A1",
  "sheet": "Summary",
  "data": [
    ["Metric", "Q1", "Q2", "Q3", "Q4", "Annual"],
    ["Revenue", 580000, 625000, 610000, 695000, 2510000],
    ["COGS", 261000, 281000, 274000, 312000, 1128000],
    ["Gross Profit", 319000, 344000, 336000, 383000, 1382000],
    ["Operating Expenses", 195000, 202000, 198000, 215000, 810000],
    ["Net Income", 124000, 142000, 138000, 168000, 572000]
  ]
}

// Response
{
  "message": "Data written successfully to Summary",
  "start_cell": "A1",
  "written_range": "$A$1:$F$6",
  "rows": 6,
  "columns": 6
}

The 2D array is written starting from A1. The first sub-array becomes the header row.


Write Formulas

"Add SUM formulas to total each column, and a margin percentage formula"

json
// Tool: write_data()
// Parameters: { "start_cell": "B7", "sheet": "Summary", "formula": "=SUM(B2:B6)" }

// Response
{
  "cell": "$B$7",
  "sheet": "Summary",
  "formula": "=SUM(B2:B6)",
  "calculated_value": 1479000
}
json
// Tool: write_data()
// Parameters: { "start_cell": "B8", "sheet": "Summary", "formula": "=B6/B2" }

// Response
{
  "cell": "$B$8",
  "sheet": "Summary",
  "formula": "=B6/B2",
  "calculated_value": 0.2138
}

The calculated value is returned immediately so the agent can verify the formula is correct. The margin is 21.4% -- the agent can confirm this matches expectations.


Format a Header Row

"Make the header row bold, centered, with dark blue background and white text"

json
// Tool: format_range()
// Parameters:
{
  "cell_range": "A1:F1",
  "sheet": "Summary",
  "bold": true,
  "alignment": "center",
  "bg_color": "#1B3A5C",
  "font_color": "#FFFFFF",
  "font_size": 11
}

// Response
{
  "range": "$A$1:$F$1",
  "sheet": "Summary",
  "applied": ["bold=True", "alignment=center", "bg_color=#1B3A5C", "font_color=#FFFFFF", "font_size=11"]
}

Format Numbers and Apply Borders

"Format the currency columns with comma separators and add borders to the whole table"

json
// Tool: format_range()
// Parameters:
{
  "cell_range": "B2:F6",
  "sheet": "Summary",
  "number_format": "#,##0",
  "border": true
}

// Response
{
  "range": "$B$2:$F$6",
  "sheet": "Summary",
  "applied": ["number_format=#,##0", "border=True"]
}
json
// Tool: format_range()
// Parameters:
{
  "cell_range": "B8:F8",
  "sheet": "Summary",
  "number_format": "0.0%",
  "italic": true
}

// Response
{
  "range": "$B$8:$F$8",
  "sheet": "Summary",
  "applied": ["number_format=0.0%", "italic=True"]
}

The data cells get comma-separated number formatting and thin borders. The margin row gets percentage formatting with italics to visually distinguish it.


Insert Rows

"Insert 3 blank rows above row 5 to add a new expense category"

json
// Tool: manage_sheets()
// Parameters: { "action": "insert_rows", "sheet": "Summary", "position": 5, "count": 3 }

// Response
{
  "message": "Inserted 3 row(s) at row 5.",
  "sheet": "Summary"
}

Three blank rows are inserted at row 5, pushing existing rows 5+ downward. Formulas referencing those rows are automatically adjusted by Excel.


Search and Management

Find and Replace

"Replace all instances of 'FY2024' with 'FY2025' in the report"

json
// Tool: find_replace()
// Parameters: { "find": "FY2024", "replace": "FY2025" }

// Response
{
  "matches": [
    { "cell": "$A$1", "value": "FY2025 Annual Report", "sheet": "Cover" },
    { "cell": "$B$2", "value": "FY2025 Consolidated Financial Summary", "sheet": "Consolidated" },
    { "cell": "$A$1", "value": "FY2025 Revenue Detail", "sheet": "Revenue" },
    { "cell": "$D$3", "value": "FY2025 Budget", "sheet": "Budget" }
  ],
  "count": 4,
  "replaced": true
}

All 4 occurrences across multiple sheets were found and replaced. The response shows the updated values after replacement.


Search Only (No Replace)

"Find all cells that mention 'depreciation'"

json
// Tool: find_replace()
// Parameters: { "find": "depreciation" }

// Response
{
  "matches": [
    { "cell": "$A$18", "value": "Depreciation & Amortization", "sheet": "PnL" },
    { "cell": "$B$5", "value": "Accumulated Depreciation", "sheet": "Balance Sheet" },
    { "cell": "$A$12", "value": "Depreciation", "sheet": "Cash Flow" }
  ],
  "count": 3
}

Omitting the replace parameter performs a search-only operation. The agent now knows exactly where depreciation appears.


Manage Sheets

"Create a new sheet called 'Q1 Report' and rename the old 'Sheet1' to 'Raw Data'"

json
// Tool: manage_sheets()
// Parameters: { "action": "add", "new_name": "Q1 Report" }

// Response
{
  "message": "Sheet 'Q1 Report' added.",
  "sheet": "Q1 Report"
}
json
// Tool: manage_sheets()
// Parameters: { "action": "rename", "sheet": "Sheet1", "new_name": "Raw Data" }

// Response
{
  "message": "Sheet 'Sheet1' renamed to 'Raw Data'.",
  "sheet": "Raw Data"
}

Run a VBA Macro

"Run the RefreshPivotTables macro to update all pivot tables"

json
// Tool: run_macro()
// Parameters: { "macro_name": "RefreshPivotTables" }

// Response
{
  "message": "Macro 'RefreshPivotTables' executed successfully.",
  "return_value": "3 pivot tables refreshed"
}

The macro ran and returned a status message. If the macro accepts arguments, pass them via the args parameter as an array.


Work with Multiple Workbooks

"Copy the Q1 actuals from report.xlsx into the budget tracker"

Step 1 -- Read data from the source workbook:

json
// Tool: read_data()
// Parameters: { "workbook": "report.xlsx", "sheet": "Q1", "cell_range": "A1:E15" }

// Response
{
  "range": "$A$1:$E$15",
  "sheet": "Q1",
  "rows": 15,
  "columns": 5,
  "headers": ["Account", "Jan Actual", "Feb Actual", "Mar Actual", "Q1 Total"],
  "data": [
    ["Revenue", 191200, 199800, 196100, 587100],
    ["COGS", 88000, 90700, 89800, 268500],
    ["Gross Profit", 103200, 109100, 106300, 318600],
    ["SG&A", 62000, 65000, 63500, 190500],
    ["R&D", 28000, 29000, 28500, 85500],
    ["EBITDA", 13200, 15100, 14300, 42600]
  ]
}

Step 2 -- Write to the destination workbook:

json
// Tool: write_data()
// Parameters:
{
  "workbook": "budget_tracker.xlsx",
  "sheet": "Actuals",
  "start_cell": "A1",
  "data": [
    ["Account", "Jan Actual", "Feb Actual", "Mar Actual", "Q1 Total"],
    ["Revenue", 191200, 199800, 196100, 587100],
    ["COGS", 88000, 90700, 89800, 268500],
    ["Gross Profit", 103200, 109100, 106300, 318600],
    ["SG&A", 62000, 65000, 63500, 190500],
    ["R&D", 28000, 29000, 28500, 85500],
    ["EBITDA", 13200, 15100, 14300, 42600]
  ]
}

// Response
{
  "message": "Data written successfully to Actuals",
  "start_cell": "A1",
  "written_range": "$A$1:$E$7",
  "rows": 7,
  "columns": 5
}

The agent reads from one workbook and writes to another by specifying the workbook parameter. Both workbooks must be open in Excel.


Real-World Workflows

Workflow 1: Financial Statement Analysis

"Analyze this business feasibility spreadsheet and extract the key financial metrics"

A complex Excel workbook with 5 sheets, merged headers, multi-level sections, and cross-sheet formulas. Here is how the agent processes it step-by-step.

Step 1 -- Discover the workbook structure:

json
// Tool: get_active_workbook()

// Response
{
  "name": "feasibility_study_2024.xlsx",
  "path": "C:\\Users\\user\\Documents\\feasibility_study_2024.xlsx",
  "sheets": [
    { "name": "사업개요", "used_range": "$A$1:$L$35", "rows": 35, "columns": 12 },
    { "name": "매출계획", "used_range": "$A$1:$U$50", "rows": 50, "columns": 21 },
    { "name": "원가분석", "used_range": "$A$1:$N$40", "rows": 40, "columns": 14 },
    { "name": "손익계산", "used_range": "$A$1:$H$60", "rows": 60, "columns": 8 },
    { "name": "투자수익", "used_range": "$A$1:$F$25", "rows": 25, "columns": 6 }
  ],
  "active_sheet": "사업개요",
  "selection": {
    "address": "$A$1",
    "sheet": "사업개요",
    "data": [["사업 타당성 분석 보고서"]],
    "rows": 1,
    "columns": 1
  }
}

The agent sees 5 sheets: Business Overview (사업개요), Revenue Plan (매출계획), Cost Analysis (원가분석), P&L Statement (손익계산), and Investment Returns (투자수익). The Revenue Plan sheet is the largest at 50 rows x 21 columns.

Step 2 -- Batch overview of all sheets:

json
// Tool: read_data()
// Parameters: { "sheet": "*" }

// Response
{
  "sheet_count": 5,
  "sheets": {
    "사업개요": {
      "sheet": "사업개요",
      "used_range": "$A$1:$L$35",
      "total_rows": 35,
      "total_columns": 12,
      "headers": ["항목", "내용", null, null, "비고"],
      "merged_cells": [
        { "range": "$A$1:$L$1", "value": "사업 타당성 분석 보고서", "rows": 1, "columns": 12 },
        { "range": "$A$3:$B$3", "value": "사업명", "rows": 1, "columns": 2 }
      ],
      "regions": [
        { "range": "$A$1:$L$35", "rows": 35, "columns": 12 }
      ]
    },
    "매출계획": {
      "sheet": "매출계획",
      "used_range": "$A$1:$U$50",
      "total_rows": 50,
      "total_columns": 21,
      "headers": ["구분", "단위", "면적(m2)", null, "분양가(만원)", null, "분양금액(백만원)"],
      "merged_cells": [
        { "range": "$A$1:$U$1", "value": "매출 계획표", "rows": 1, "columns": 21 },
        { "range": "$A$3:$A$4", "value": "구분", "rows": 2, "columns": 1 },
        { "range": "$A$6:$A$19", "value": "건축 계획", "rows": 14, "columns": 1 },
        { "range": "$A$20:$A$35", "value": "분양 수입", "rows": 16, "columns": 1 }
      ],
      "regions": [
        { "range": "$A$1:$U$50", "rows": 50, "columns": 21 }
      ]
    },
    "원가분석": {
      "sheet": "원가분석",
      "used_range": "$A$1:$N$40",
      "total_rows": 40,
      "total_columns": 14,
      "headers": ["비용항목", "산출근거", "금액(백만원)", "비율(%)"]
    },
    "손익계산": {
      "sheet": "손익계산",
      "used_range": "$A$1:$H$60",
      "total_rows": 60,
      "total_columns": 8,
      "headers": ["항목", "1차년도", "2차년도", "3차년도", "4차년도", "5차년도", "합계"]
    },
    "투자수익": {
      "sheet": "투자수익",
      "used_range": "$A$1:$F$25",
      "total_rows": 25,
      "total_columns": 6,
      "headers": ["지표", "값", "기준", "판정"]
    }
  }
}

The agent now has a map of the entire workbook. The Revenue Plan (매출계획) has multi-level merged headers with "건축 계획" (Building Plan) and "분양 수입" (Sales Revenue) spanning many rows. The P&L (손익계산) has a 5-year projection. The agent decides to examine the Revenue Plan headers first.

Step 3 -- Understand the Revenue Plan header structure:

json
// Tool: read_data()
// Parameters: { "sheet": "매출계획", "cell_range": "A1:U5", "merge_info": true }

// Response
{
  "range": "$A$1:$U$5",
  "sheet": "매출계획",
  "rows": 5,
  "columns": 21,
  "headers": ["매출 계획표", "매출 계획표", "매출 계획표", "매출 계획표", "매출 계획표"],
  "data": [
    [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
    ["구분", "세부항목", "단위", "수량", "면적(m2)", "전용면적", "공용면적", "분양가(만원/m2)", "분양가(만원/평)", "분양금액(백만원)", "비율(%)", null, null, null, null, null, null, null, null, null, null],
    ["구분", "세부항목", "단위", "수량", "면적(m2)", "전용면적", "공용면적", "분양가(만원/m2)", "분양가(만원/평)", "분양금액(백만원)", "비율(%)", null, null, null, null, null, null, null, null, null, null]
  ],
  "merged_ranges": [
    { "range": "$A$1:$U$1", "value": "매출 계획표" },
    { "range": "$A$3:$A$4", "value": "구분" },
    { "range": "$B$3:$B$4", "value": "세부항목" }
  ]
}

The agent sees that rows 3-4 form a two-level header (구분/세부항목 span two rows). The actual data starts at row 5. Column layout: Category, Sub-item, Unit, Quantity, Area(m2), Exclusive Area, Common Area, Price per m2, Price per pyeong, Sales Amount, Ratio.

Step 4 -- Find all formulas to understand calculation logic:

json
// Tool: get_formulas()
// Parameters: { "sheet": "매출계획", "cell_range": "A1:U50", "values_too": true }

// Response
{
  "formulas": [
    { "cell": "F6", "formula": "=D6*E6*0.75", "value": 5625.00 },
    { "cell": "G6", "formula": "=D6*E6*0.25", "value": 1875.00 },
    { "cell": "J6", "formula": "=D6*H6*E6/100", "value": 37828 },
    { "cell": "K6", "formula": "=J6/$J$36", "value": 0.3739 },
    { "cell": "J19", "formula": "=SUM(J6:J18)", "value": 101150 },
    { "cell": "J35", "formula": "=SUM(J20:J34)", "value": 28450 },
    { "cell": "J36", "formula": "=J19+J35", "value": 129600 },
    { "cell": "K36", "formula": "=J36/J36", "value": 1.0 }
  ],
  "total_formula_cells": 8,
  "range": "$A$1:$U$50",
  "sheet": "매출계획"
}

Key insights: Exclusive area is 75% of total (F6), common area is 25% (G6). Sales amounts are calculated as quantity x price x area (J6). Each line item's ratio is relative to the grand total at J36. Building plan subtotal is 101,150M won, other revenue is 28,450M won, for a grand total of 129,600M won (about 129.6 billion won).

Step 5 -- Identify section structure via formatting:

json
// Tool: get_cell_styles()
// Parameters: { "sheet": "매출계획", "cell_range": "A1:A50", "properties": ["bold", "bg_color", "font_size"] }

// Response
{
  "range": "$A$1:$A$50",
  "sheet": "매출계획",
  "styles": [
    { "cell": "A1", "bold": true, "bg_color": "#1B3A5C", "font_size": 14 },
    { "cell": "A3", "bold": true, "bg_color": "#D6E4F0" },
    { "cell": "A6", "bold": true, "bg_color": "#F2F2F2" },
    { "cell": "A19", "bold": true, "bg_color": "#E2EFDA" },
    { "cell": "A20", "bold": true, "bg_color": "#F2F2F2" },
    { "cell": "A35", "bold": true, "bg_color": "#E2EFDA" },
    { "cell": "A36", "bold": true, "bg_color": "#1B3A5C" }
  ]
}

The formatting reveals the hierarchy: dark blue (#1B3A5C) = title and grand total rows, light blue (#D6E4F0) = column headers, light gray (#F2F2F2) = section start rows (건축 계획 at A6, 분양 수입 at A20), and green (#E2EFDA) = subtotal rows (A19, A35). Grand total at A36.

Step 6 -- Extract the main data table:

json
// Tool: read_data()
// Parameters: { "sheet": "매출계획", "cell_range": "A5:K36", "header_row": 2, "merge_info": true }

// Response
{
  "range": "$A$5:$K$36",
  "sheet": "매출계획",
  "rows": 32,
  "columns": 11,
  "headers": ["구분", "세부항목", "단위", "수량", "면적(m2)", "전용면적", "공용면적", "분양가(만원/m2)", "분양가(만원/평)", "분양금액(백만원)", "비율(%)"],
  "data": [
    ["건축 계획", "아파트 59m2", "세대", 120, 59.0, 44.25, 14.75, 850, 2805, 37828, 0.3739],
    ["건축 계획", "아파트 84m2", "세대", 80, 84.0, 63.00, 21.00, 920, 3036, 30912, 0.2385],
    ["건축 계획", "아파트 115m2", "세대", 30, 115.0, 86.25, 28.75, 1050, 3465, 18113, 0.1397],
    ["건축 계획", "오피스텔 33m2", "실", 50, 33.0, 24.75, 8.25, 780, 2574, 6435, 0.0497],
    ["건축 계획", "상가 1층", "호", 15, 45.0, 33.75, 11.25, 1800, 5940, 6075, 0.0469],
    ["건축 계획", "상가 2층", "호", 10, 40.0, 30.00, 10.00, 950, 3135, 1900, 0.0147],
    ["건축 계획", "소계", null, null, null, null, null, null, null, 101150, 0.7806],
    ["분양 수입", "발코니 확장", "세대", 200, null, null, null, null, null, 10000, 0.0772],
    ["분양 수입", "시스템 에어컨", "세대", 150, null, null, null, null, null, 4500, 0.0347],
    ["분양 수입", "주차장 수입", "면", 350, null, null, null, null, null, 8750, 0.0675],
    ["분양 수입", "기타 수입", null, null, null, null, null, null, null, 5200, 0.0401],
    ["분양 수입", "소계", null, null, null, null, null, null, null, 28450, 0.2195],
    ["합계", null, null, null, null, null, null, null, null, 129600, 1.0]
  ]
}

Using header_row=2 correctly maps row 3-4's merged headers. With merge_info=true, the "건축 계획" and "분양 수입" merged labels fill every row. The agent now has the complete revenue plan: total projected sales of 129,600M won (~129.6 billion won), with 78% from building sales and 22% from ancillary revenue.

Step 7 -- Read the Investment Returns sheet for key metrics:

json
// Tool: read_data()
// Parameters: { "sheet": "투자수익", "cell_range": "A1:F25" }

// Response
{
  "range": "$A$1:$F$25",
  "sheet": "투자수익",
  "rows": 25,
  "columns": 6,
  "headers": ["지표", "값", "기준", "판정"],
  "data": [
    ["총 사업비", "118,500백만원", null, null],
    ["총 분양수입", "129,600백만원", null, null],
    ["사업이익", "11,100백만원", null, null],
    ["사업이익률", "9.37%", "8% 이상", "적합"],
    ["IRR (내부수익률)", "12.8%", "10% 이상", "적합"],
    ["NPV (순현재가치)", "8,520백만원", "0 이상", "적합"],
    ["투자회수기간", "3.2년", "5년 이내", "적합"],
    ["손익분기점", "78.5%", "85% 이하", "적합"],
    ["자기자본수익률(ROE)", "18.6%", "15% 이상", "적합"]
  ]
}

The agent can now provide a comprehensive summary: Total project cost is 118.5B won with projected revenue of 129.6B won, yielding an 11.1B won profit (9.37% margin). All investment metrics pass their thresholds -- IRR of 12.8%, NPV of 8.52B won, payback period of 3.2 years, break-even at 78.5% occupancy, and ROE of 18.6%.


Workflow 2: Multi-Workbook Data Consolidation

"I have Q1, Q2, and Q3 sales reports in separate workbooks. Consolidate them into a yearly summary workbook."

The agent needs to read from three source workbooks and write a consolidated summary into a fourth. All four workbooks must be open in Excel.

Step 1 -- List open workbooks:

json
// Tool: manage_workbooks()
// Parameters: { "action": "list" }

// Response
[
  {
    "name": "sales_q1.xlsx",
    "path": "C:\\Users\\user\\Reports\\sales_q1.xlsx",
    "sheets": [{ "name": "Sales", "used_range": "$A$1:$F$25", "rows": 25, "columns": 6 }]
  },
  {
    "name": "sales_q2.xlsx",
    "path": "C:\\Users\\user\\Reports\\sales_q2.xlsx",
    "sheets": [{ "name": "Sales", "used_range": "$A$1:$F$25", "rows": 25, "columns": 6 }]
  },
  {
    "name": "sales_q3.xlsx",
    "path": "C:\\Users\\user\\Reports\\sales_q3.xlsx",
    "sheets": [{ "name": "Sales", "used_range": "$A$1:$F$25", "rows": 25, "columns": 6 }]
  },
  {
    "name": "annual_summary.xlsx",
    "path": "C:\\Users\\user\\Reports\\annual_summary.xlsx",
    "sheets": [{ "name": "Summary", "used_range": "$A$1", "rows": 1, "columns": 1 }]
  }
]

All four workbooks are open. Each quarterly report has the same structure (25 rows, 6 columns).

Step 2 -- Read Q1 data:

json
// Tool: read_data()
// Parameters: { "workbook": "sales_q1.xlsx", "sheet": "Sales", "cell_range": "A1:F25" }

// Response
{
  "range": "$A$1:$F$25",
  "sheet": "Sales",
  "rows": 25,
  "columns": 6,
  "headers": ["Region", "Product", "Units Sold", "Revenue", "Cost", "Profit"],
  "data": [
    ["North", "Widget A", 1250, 312500, 187500, 125000],
    ["North", "Widget B", 840, 168000, 100800, 67200],
    ["North", "Widget C", 1520, 456000, 273600, 182400],
    ["South", "Widget A", 980, 245000, 147000, 98000],
    ["South", "Widget B", 1100, 220000, 132000, 88000],
    ["South", "Widget C", 760, 228000, 136800, 91200],
    ["East", "Widget A", 1350, 337500, 202500, 135000],
    ["East", "Widget B", 920, 184000, 110400, 73600],
    ["East", "Widget C", 1180, 354000, 212400, 141600],
    ["West", "Widget A", 1050, 262500, 157500, 105000],
    ["West", "Widget B", 680, 136000, 81600, 54400],
    ["West", "Widget C", 890, 267000, 160200, 106800]
  ]
}

Step 3 -- Read Q2 and Q3 data:

json
// Tool: read_data()
// Parameters: { "workbook": "sales_q2.xlsx", "sheet": "Sales", "cell_range": "A1:F25" }

// Response
{
  "range": "$A$1:$F$25",
  "sheet": "Sales",
  "rows": 25,
  "columns": 6,
  "headers": ["Region", "Product", "Units Sold", "Revenue", "Cost", "Profit"],
  "data": [
    ["North", "Widget A", 1380, 345000, 207000, 138000],
    ["North", "Widget B", 910, 182000, 109200, 72800],
    ["North", "Widget C", 1670, 501000, 300600, 200400],
    ["South", "Widget A", 1050, 262500, 157500, 105000],
    ["South", "Widget B", 1200, 240000, 144000, 96000],
    ["South", "Widget C", 820, 246000, 147600, 98400],
    ["East", "Widget A", 1420, 355000, 213000, 142000],
    ["East", "Widget B", 980, 196000, 117600, 78400],
    ["East", "Widget C", 1250, 375000, 225000, 150000],
    ["West", "Widget A", 1120, 280000, 168000, 112000],
    ["West", "Widget B", 720, 144000, 86400, 57600],
    ["West", "Widget C", 950, 285000, 171000, 114000]
  ]
}
json
// Tool: read_data()
// Parameters: { "workbook": "sales_q3.xlsx", "sheet": "Sales", "cell_range": "A1:F25" }

// Response
{
  "range": "$A$1:$F$25",
  "sheet": "Sales",
  "rows": 25,
  "columns": 6,
  "headers": ["Region", "Product", "Units Sold", "Revenue", "Cost", "Profit"],
  "data": [
    ["North", "Widget A", 1420, 355000, 213000, 142000],
    ["North", "Widget B", 890, 178000, 106800, 71200],
    ["North", "Widget C", 1710, 513000, 307800, 205200],
    ["South", "Widget A", 1080, 270000, 162000, 108000],
    ["South", "Widget B", 1150, 230000, 138000, 92000],
    ["South", "Widget C", 850, 255000, 153000, 102000],
    ["East", "Widget A", 1480, 370000, 222000, 148000],
    ["East", "Widget B", 1010, 202000, 121200, 80800],
    ["East", "Widget C", 1300, 390000, 234000, 156000],
    ["West", "Widget A", 1150, 287500, 172500, 115000],
    ["West", "Widget B", 750, 150000, 90000, 60000],
    ["West", "Widget C", 980, 294000, 176400, 117600]
  ]
}

The agent now has all three quarters of data. It aggregates by region and product, computing totals.

Step 4 -- Write the consolidated summary with headers:

json
// Tool: write_data()
// Parameters:
{
  "workbook": "annual_summary.xlsx",
  "sheet": "Summary",
  "start_cell": "A1",
  "data": [
    ["Region", "Product", "Q1 Units", "Q2 Units", "Q3 Units", "YTD Units", "Q1 Revenue", "Q2 Revenue", "Q3 Revenue", "YTD Revenue", "YTD Profit", "Profit Margin"],
    ["North", "Widget A", 1250, 1380, 1420, 4050, 312500, 345000, 355000, 1012500, 405000, "40.0%"],
    ["North", "Widget B", 840, 910, 890, 2640, 168000, 182000, 178000, 528000, 211200, "40.0%"],
    ["North", "Widget C", 1520, 1670, 1710, 4900, 456000, 501000, 513000, 1470000, 588000, "40.0%"],
    ["South", "Widget A", 980, 1050, 1080, 3110, 245000, 262500, 270000, 777500, 311000, "40.0%"],
    ["South", "Widget B", 1100, 1200, 1150, 3450, 220000, 240000, 230000, 690000, 276000, "40.0%"],
    ["South", "Widget C", 760, 820, 850, 2430, 228000, 246000, 255000, 729000, 291600, "40.0%"],
    ["East", "Widget A", 1350, 1420, 1480, 4250, 337500, 355000, 370000, 1062500, 425000, "40.0%"],
    ["East", "Widget B", 920, 980, 1010, 2910, 184000, 196000, 202000, 582000, 232800, "40.0%"],
    ["East", "Widget C", 1180, 1250, 1300, 3730, 354000, 375000, 390000, 1119000, 447600, "40.0%"],
    ["West", "Widget A", 1050, 1120, 1150, 3320, 262500, 280000, 287500, 830000, 332000, "40.0%"],
    ["West", "Widget B", 680, 720, 750, 2150, 136000, 144000, 150000, 430000, 172000, "40.0%"],
    ["West", "Widget C", 890, 950, 980, 2820, 267000, 285000, 294000, 846000, 338400, "40.0%"]
  ]
}

// Response
{
  "message": "Data written successfully to Summary",
  "start_cell": "A1",
  "written_range": "$A$1:$L$13",
  "rows": 13,
  "columns": 12
}

Step 5 -- Add a totals row with formulas:

json
// Tool: write_data()
// Parameters:
{
  "workbook": "annual_summary.xlsx",
  "sheet": "Summary",
  "start_cell": "A14",
  "data": [["Grand Total"]]
}

// Response
{
  "message": "Data written successfully to Summary",
  "start_cell": "A14",
  "written_range": "$A$14:$A$14",
  "rows": 1,
  "columns": 1
}
json
// Tool: write_data()
// Parameters: { "workbook": "annual_summary.xlsx", "sheet": "Summary", "start_cell": "F14", "formula": "=SUM(F2:F13)" }

// Response
{
  "cell": "$F$14",
  "sheet": "Summary",
  "formula": "=SUM(F2:F13)",
  "calculated_value": 39760
}
json
// Tool: write_data()
// Parameters: { "workbook": "annual_summary.xlsx", "sheet": "Summary", "start_cell": "J14", "formula": "=SUM(J2:J13)" }

// Response
{
  "cell": "$J$14",
  "sheet": "Summary",
  "formula": "=SUM(J2:J13)",
  "calculated_value": 10076500
}
json
// Tool: write_data()
// Parameters: { "workbook": "annual_summary.xlsx", "sheet": "Summary", "start_cell": "K14", "formula": "=SUM(K2:K13)" }

// Response
{
  "cell": "$K$14",
  "sheet": "Summary",
  "formula": "=SUM(K2:K13)",
  "calculated_value": 4030600
}

Step 6 -- Format the summary table:

json
// Tool: format_range()
// Parameters:
{
  "workbook": "annual_summary.xlsx",
  "sheet": "Summary",
  "cell_range": "A1:L1",
  "bold": true,
  "alignment": "center",
  "bg_color": "#1B3A5C",
  "font_color": "#FFFFFF",
  "wrap_text": true
}

// Response
{
  "range": "$A$1:$L$1",
  "sheet": "Summary",
  "applied": ["bold=True", "alignment=center", "bg_color=#1B3A5C", "font_color=#FFFFFF", "wrap_text=True"]
}
json
// Tool: format_range()
// Parameters:
{
  "workbook": "annual_summary.xlsx",
  "sheet": "Summary",
  "cell_range": "G2:K14",
  "number_format": "#,##0"
}

// Response
{
  "range": "$G$2:$K$14",
  "sheet": "Summary",
  "applied": ["number_format=#,##0"]
}
json
// Tool: format_range()
// Parameters:
{
  "workbook": "annual_summary.xlsx",
  "sheet": "Summary",
  "cell_range": "A14:L14",
  "bold": true,
  "bg_color": "#E2EFDA",
  "border": true
}

// Response
{
  "range": "$A$14:$L$14",
  "sheet": "Summary",
  "applied": ["bold=True", "bg_color=#E2EFDA", "border=True"]
}

Step 7 -- Save the result:

json
// Tool: manage_workbooks()
// Parameters: { "action": "save", "workbook": "annual_summary.xlsx" }

// Response
{
  "message": "Workbook 'annual_summary.xlsx' saved.",
  "path": "C:\\Users\\user\\Reports\\annual_summary.xlsx"
}

The consolidation is complete. Data from three quarterly workbooks has been aggregated into a formatted summary with 12 product-region combinations, YTD totals of 39,760 units and $10,076,500 in revenue, and a consistent 40% profit margin across all product lines. The summary includes SUM formulas so it stays correct if individual values are updated.

Released under the MIT License.