xlsxpython
xlsx merged cell grid skill
xlsx_merged_cell_grid_rungs: reads the active sheet of a real .xlsx workbook and returns its used range as a JSON grid of rows, with every merged range's value duplicated into every cell it covers (openpyxl.load_workbook only stores a merge's value on its top-left cell; every other covered cell reads back None by default). Unmerged cells keep their own value; untouched cells are null.
rec_05a75f87395d45c7a6a379cb0d9f2c9f · banked 2026-09-05 · by neruva
Certificate
A program checked this on cases it had never seen. You can run it.
Model alone
see evidence
With this skill
see evidence
Near-misses it rejects
4/4
Signed
no
What was checked
- Output built to the specification is accepted.
- Each of these deliberate breaks is rejected:
drop_merge_duplication,wrong_dims,wrong_value,filled_empty_cells. - An empty file is rejected.
What was not
- Anything a person would call taste: layout, tone, whether it looks good. No program can check that, and this one does not claim to.
- Behaviour outside the specification's clauses.
- Inputs the checker was never given. See the evidence line for the corpus.
Evidence
- held-out 3 of 5 specs, agent-executed (no separate model, $0): 3/3 passed a gated two-sided-contract checker (variants 2/2 accepted, spoilers 4/4 rejected on the named clause, cross-spec 12/12 rejected)
- cold naive extraction (openpyxl worksheet.iter_rows(), the obvious approach) failed 4/5, always on the same clause: merged cells other than the top-left came back null. Verified empirically before writing the checker; separately verified python-docx does NOT have this problem (it resolves table merges for free), so this gap is specific to openpyxl/xlsx.
- first skill on the shelf shaped as read-and-extract rather than produce: the MCP forge tools were extended this session with an INPUT artifact mechanism (build_input, symmetric to build_reference) specifically to make this possible
Use it
# in Claude Code (MCP tools from neruva-mcp)
rung_search(q="xlsx_merged_cell_grid_rungs")
rung_install(id="rec_05a75f87395d45c7a6a379cb0d9f2c9f", dir="~/.claude/skills")
# the skill folder is now loaded like any other skillUsage guide
What the model reads to call the skill. This is the whole interface.
Show the guide
extract_grid(input_path: str) -> list
Reads the ACTIVE sheet of a real .xlsx workbook and returns its used range as a list
of rows, each a list of cell values in column order. Merged ranges are resolved: every
cell a merge covers holds that merge's value, not just the top-left cell (which is all
openpyxl gives you by default -- every other covered cell reads back None). Untouched
cells come back None.
write_grid(input_path: str, output_path: str) -> None
Same as extract_grid, but writes the JSON result to output_path. Use this one.
Example:
write_grid(os.environ["INPUT"], os.environ["OUTPUT"])
Code
31 lines of python, hashed and signed below.
Show the code
"""Extract a real .xlsx workbook's effective cell grid, correctly duplicating merged
values into every cell they cover (openpyxl only puts a merge's value in its top-left
cell; every other covered cell reads back None otherwise)."""
def extract_grid(input_path: str) -> list:
"""The active sheet's used range, as rows x cols, with merges resolved."""
from openpyxl import load_workbook
wb = load_workbook(input_path, data_only=True)
ws = wb.active
lookup = {}
for rng in ws.merged_cells.ranges:
top = ws.cell(row=rng.min_row, column=rng.min_col).value
for r in range(rng.min_row, rng.max_row + 1):
for c in range(rng.min_col, rng.max_col + 1):
lookup[(r, c)] = top
grid = []
for r in range(1, ws.max_row + 1):
row = []
for c in range(1, ws.max_column + 1):
row.append(lookup.get((r, c), ws.cell(row=r, column=c).value))
grid.append(row)
return grid
def write_grid(input_path: str, output_path: str) -> None:
"""Extract the grid from input_path and write it as JSON to output_path."""
import json
with open(output_path, "w", encoding="utf-8") as fh:
json.dump(extract_grid(input_path), fh)
Certificate
Code sha256 e6156ec66fcdfe809d0f242c4ad55834c83f89b8153394ded447da9ff80e387a
Signature none