Read, inspect, edit, or create Microsoft Excel `.xlsx` workbooks, including structured data extraction, formula-aware cell edits, and workbook generation from rows.
Work with .xlsx workbooks. The format is OOXML SpreadsheetML — a zip
container of XML parts. Treat each cell as a typed value: a number, a string,
a datetime, or a formula. Mixing the four causes Excel to flag the workbook
or compute incorrect totals.
| You have | Goal | Path |
|---|---|---|
Existing .xlsx | Read sheets and cells | A. Inspect |
Existing .xlsx | Modify specific cells | B. Edit-in-place |
| Nothing or a brief | Build a new workbook | C. Create from scratch |
If the user provides a workbook to update, default to path B and treat the input as the formatting baseline. Choose path C only when the user says "start fresh".
Use execute_code with the Python examples below when it is available. Keep
all input and output files in the active workspace, then call
publish_artifact(path="out.xlsx") to deliver the finished workbook.
In a restricted channel, use openpyxl directly; the shell commands below
are optional shortcuts for sessions that expose exec_command. Do not use
Python subprocesses to bypass an unavailable shell tool or request host
execution when the sandbox fails. If execution or a required library is
unavailable, report that limitation and keep the session read-only.
With execute_code:
from openpyxl import load_workbook
wb = load_workbook("book.xlsx", data_only=False)
for ws in wb.worksheets:
print(ws.title, list(ws.values))
wb.close()python {baseDir}/scripts/inspect_xlsx.py /path/to/book.xlsxOutput:
{
"sheets": [
{
"name": "Q3",
"max_row": 10,
"max_col": 5,
"rows": [
[
{"value": "Metric", "type": "s"},
{"value": "Value", "type": "s"}
],
[
{"value": "Revenue", "type": "s"},
{"value": 2100000, "type": "n"}
]
]
}
]
}type follows openpyxl conventions: n (number), s (string), d
(datetime), f (formula), b (bool), e (error), inlineStr (inline
string). The helper script reads with data_only=False so formula expressions
are returned literally; pass --data-only to get the cached computed result
instead.
With execute_code:
from openpyxl import load_workbook
wb = load_workbook("book.xlsx")
wb["Q3"]["B2"] = "=SUM(B3:B10)"
wb.save("edited.xlsx")
wb.close()python {baseDir}/scripts/edit_xlsx.py book.xlsx ops.json --out edited.xlsxops.json:
[
{"op": "set_cell", "sheet": "Q3", "row": 2, "col": 2, "value": "=SUM(B3:B10)"},
{"op": "set_cell", "sheet": "Q3", "row": 5, "col": 1, "value": "Net margin"},
{"op": "rename_sheet", "old": "Sheet1", "new": "Summary"}
]Rules:
= are written as formulas (cell.value = "=..."),
matching openpyxl behavior. To write a literal =hello use '=hello
(Excel's leading-apostrophe escape) or pass an explicit as_text: true."2026-05-06T09:00:00"); the helper
parses them back to datetime objects so Excel renders the cell with date
format.python {baseDir}/scripts/create_xlsx.py spec.json --out out.xlsxSpec:
{
"sheets": [
{
"name": "Sales",
"rows": [
["Region", "Revenue", "Growth"],
["NA", 1200000, "=B2/SUM($B$2:$B$4)"],
["EU", 850000, "=B3/SUM($B$2:$B$4)"]
],
"merged": [{"range": "A1:C1"}],
"freeze": "A2"
}
]
}For programmatic use:
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
ws.title = "Sales"
ws.append(["Region", "Revenue"])
ws.append(["NA", 1_200_000])
ws["C2"] = "=B2*1.05" # formula
ws.merge_cells("A1:B1")
ws.freeze_panes = "A2"
wb.save("out.xlsx")See references/openpyxl.md for styles, conditional formatting, charts, and formula references.
| Symptom | Cause | Fix |
|---|---|---|
Cell shows =SUM(...) as text, not the result | Wrote the string with as_text: true or workbook lacks cached values | Open in Excel and save once; or use a calc engine |
| Date renders as a serial number (45000) | Wrote int instead of datetime | Pass an ISO string and let the helper parse; or set cell.number_format |
| Merged range loses borders | Borders apply to the top-left cell only after merge | Apply border to the top-left cell post-merge |
| Workbook breaks Excel after edit | Removed a defined name without updating dependent formulas | Audit defined_names before delete |
| Pivot tables disappear | openpyxl drops pivot caches on save | Edit pivots in Excel; programmatic edit is not supported |
.xlsx (OOXML SpreadsheetML). It does not handle
.xls (legacy binary), .xlsm (macro-enabled), or Google Sheets. Convert
via Excel or LibreOffice export first.to_excel with the xlsxwriter engine; openpyxl loads the whole workbook
into memory.943b784
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.