xlsx

Create, read, edit Excel .xlsx workbooks and CSVs.

  • excel
  • spreadsheet
  • xlsx
  • csv
  • openpyxl
  • productivity

Declared platforms: linux · macos · windows

Install
npx skills add 'https://github.com/NousResearch/hermes-agent/tree/main/skills/productivity/xlsx'
Download bundle ↓
main · 24fd22bScanned 2026-09-15

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗
View on GitHub
← Back to SKILL.md
#!/usr/bin/env python3"""Create an .xlsx workbook from a JSON spec. Spec (JSON object):  {    "full_calc_on_load": true,          # force recalculation on open (optional)    "defined_names": {"Rates": "'Data'!$B$2:$B$4"},   # workbook scope    "sheets": [      {        "name": "Data",        "rows": [["Header", 1, true], ...],   # scalars or cell objects (see below)        "cells": {"A1": {"value": 5, "format": "0.00%"}},  # sparse overrides        "column_widths": {"A": 22, "B": 12},        "row_heights": {"1": 24},        "merges": ["A1:C1"],        "freeze_panes": "A2",        "autofilter": "A1:C10",        "conditional_formats": [          {"range": "B2:B9", "type": "cell_is", "operator": "greaterThan",           "formula": ["100"], "fill": "FFC7CE"},          {"range": "C2:C9", "type": "color_scale"}        ],        "charts": [          {"type": "bar", "title": "Sales", "anchor": "F2",           "data": "B1:B5", "categories": "A2:A5"}        ],        "validations": [          {"range": "D2:D9", "type": "list", "formula1": "\"Yes,No,Maybe\""}        ],        "tables": [          {"name": "Sales", "range": "A1:C4",           "style": "TableStyleMedium9"}        # native Excel table        ],        "protection": {"password": "your-password",   # NOT security --                       "unlock": ["B2:B9"]}           # see SKILL.md Pitfalls      }    ]  } Cell object keys (all optional except value/formula):  value          scalar; JSON true/false -> bool, numbers stay numeric  type           "date" or "datetime" -> value parsed from ISO string  formula        e.g. "=SUM(A2:A9)" (leading '=' optional)  hyperlink      URL; value becomes the display text  note           cell note text (or {"text": ..., "author": ...})  format         Excel number format, e.g. "$#,##0.00", "0.0%", "yyyy-mm-dd"  bold, italic   booleans  font_size      points  font_color     hex RGB like "FF0000"  fill           solid fill hex RGB like "DDEBF7"  border         "thin" | "medium" | "thick" (all four sides)  align          "left" | "center" | "right"  valign         "top" | "center" | "bottom"  wrap           boolean (wrap text) Usage:  xlsx_create.py spec.json out.xlsx  xlsx_create.py - out.xlsx   (spec on stdin) Prints a JSON summary to stdout; exits non-zero on failure."""from __future__ import annotations import argparseimport jsonimport sysfrom datetime import date, datetime from openpyxl import Workbookfrom openpyxl.chart import BarChart, LineChart, PieChart, Referencefrom openpyxl.comments import Commentfrom openpyxl.formatting.rule import CellIsRule, ColorScaleRulefrom openpyxl.styles import (Alignment, Border, Font, PatternFill,                             Protection, Side)from openpyxl.utils import column_index_from_string, range_boundariesfrom openpyxl.workbook.defined_name import DefinedNamefrom openpyxl.worksheet.datavalidation import DataValidationfrom openpyxl.worksheet.table import Table, TableStyleInfo  def parse_typed(value, type_hint=None):    if type_hint == "date" and isinstance(value, str):        return date.fromisoformat(value)    if type_hint == "datetime" and isinstance(value, str):        return datetime.fromisoformat(value)    return value  def apply_cell(ws, coord, spec):    cell = ws[coord]    if isinstance(spec, dict):        if "formula" in spec:            f = spec["formula"]            cell.value = f if f.startswith("=") else "=" + f        elif "value" in spec:            cell.value = parse_typed(spec["value"], spec.get("type"))        if "hyperlink" in spec:            cell.hyperlink = spec["hyperlink"]            if cell.value is None:                cell.value = spec["hyperlink"]            cell.style = "Hyperlink"        if "note" in spec:            note = spec["note"]            if isinstance(note, dict):                cell.comment = Comment(note.get("text", ""),                                       note.get("author", "xlsx-skill"))            else:                cell.comment = Comment(str(note), "xlsx-skill")        if "format" in spec:            cell.number_format = spec["format"]        font_kw = {}        if spec.get("bold"):            font_kw["bold"] = True        if spec.get("italic"):            font_kw["italic"] = True        if "font_size" in spec:            font_kw["size"] = spec["font_size"]        if "font_color" in spec:            font_kw["color"] = spec["font_color"]        if font_kw:            cell.font = Font(**font_kw)        if "fill" in spec:            cell.fill = PatternFill("solid", fgColor=spec["fill"])        if "border" in spec:            side = Side(style=spec["border"])            cell.border = Border(left=side, right=side, top=side, bottom=side)        align_kw = {}        if "align" in spec:            align_kw["horizontal"] = spec["align"]        if "valign" in spec:            align_kw["vertical"] = spec["valign"]        if spec.get("wrap"):            align_kw["wrap_text"] = True        if align_kw:            cell.alignment = Alignment(**align_kw)    else:        cell.value = spec  def ref_from_range(ws, rng):    min_col, min_row, max_col, max_row = range_boundaries(rng)    return Reference(ws, min_col=min_col, min_row=min_row,                     max_col=max_col, max_row=max_row)  def add_chart(ws, spec):    kind = spec.get("type", "bar")    chart = {"bar": BarChart, "line": LineChart, "pie": PieChart}[kind]()    if "title" in spec:        chart.title = spec["title"]    data = ref_from_range(ws, spec["data"])    chart.add_data(data, titles_from_data=spec.get("titles_from_data", True))    if "categories" in spec:        chart.set_categories(ref_from_range(ws, spec["categories"]))    ws.add_chart(chart, spec.get("anchor", "H2"))  def add_conditional(ws, spec):    rng = spec["range"]    kind = spec.get("type", "cell_is")    if kind == "color_scale":        rule = ColorScaleRule(            start_type="min", start_color=spec.get("start_color", "FFF8696B"),            end_type="max", end_color=spec.get("end_color", "FF63BE7B"))    else:        fill = PatternFill("solid", fgColor=spec.get("fill", "FFC7CE"))        rule = CellIsRule(operator=spec.get("operator", "greaterThan"),                          formula=spec.get("formula", ["0"]), fill=fill)    ws.conditional_formatting.add(rng, rule)  def build_sheet(ws, spec):    for row in spec.get("rows", []):        values, styled = [], []        for item in row:            if isinstance(item, dict):                values.append(None)                styled.append(item)            else:                values.append(item)                styled.append(None)        ws.append(values)        r = ws.max_row        for idx, item in enumerate(styled, start=1):            if item is not None:                apply_cell(ws, ws.cell(row=r, column=idx).coordinate, item)    for coord, cell_spec in spec.get("cells", {}).items():        apply_cell(ws, coord, cell_spec)    for col, width in spec.get("column_widths", {}).items():        ws.column_dimensions[col].width = width    for row, height in spec.get("row_heights", {}).items():        ws.row_dimensions[int(row)].height = height    for rng in spec.get("merges", []):        ws.merge_cells(rng)    if spec.get("freeze_panes"):        ws.freeze_panes = spec["freeze_panes"]    if spec.get("autofilter"):        ws.auto_filter.ref = spec["autofilter"]    for cf in spec.get("conditional_formats", []):        add_conditional(ws, cf)    for ch in spec.get("charts", []):        add_chart(ws, ch)    for dv_spec in spec.get("validations", []):        dv = DataValidation(type=dv_spec.get("type", "list"),                            formula1=dv_spec["formula1"],                            allow_blank=dv_spec.get("allow_blank", True))        dv.add(dv_spec["range"])        ws.add_data_validation(dv)    for t_spec in spec.get("tables", []):        table = Table(displayName=t_spec["name"], ref=t_spec["range"])        table.tableStyleInfo = TableStyleInfo(            name=t_spec.get("style", "TableStyleMedium9"),            showRowStripes=t_spec.get("row_stripes", True),            showColumnStripes=t_spec.get("column_stripes", False))        ws.add_table(table)    prot = spec.get("protection")    if prot:        for rng in prot.get("unlock", []):            for row in ws[rng]:                for cell in row:                    cell.protection = Protection(locked=False)        if prot.get("password"):            ws.protection.password = prot["password"]        ws.protection.sheet = True  def main(argv=None):    ap = argparse.ArgumentParser(description="Create .xlsx from a JSON spec.")    ap.add_argument("spec", help="path to JSON spec, or '-' for stdin")    ap.add_argument("output", help="output .xlsx path")    args = ap.parse_args(argv)     if args.spec == "-":        spec = json.load(sys.stdin)    else:        with open(args.spec, encoding="utf-8") as fh:            spec = json.load(fh)     wb = Workbook()    wb.remove(wb.active)    for sheet_spec in spec.get("sheets", []):        ws = wb.create_sheet(sheet_spec.get("name", "Sheet1"))        build_sheet(ws, sheet_spec)    for name, ref in spec.get("defined_names", {}).items():        wb.defined_names[name] = DefinedName(name, attr_text=ref)    if spec.get("full_calc_on_load"):        wb.calculation.fullCalcOnLoad = True    wb.save(args.output)    print(json.dumps({"ok": True, "output": args.output,                      "sheets": wb.sheetnames}, ensure_ascii=False))    return 0  if __name__ == "__main__":    try:        sys.exit(main())    except Exception as exc:  # noqa: BLE001        print(json.dumps({"ok": False, "error": str(exc)}), file=sys.stderr)        sys.exit(1) 
Referenced from SKILL.md