agentsclimarketplace

Libreoffice calc

Skill dfk1352/LibreOffice-skills/skills/libreoffice-calc

Deterministic python skill suite for LibreOffice designed for AI agents

Install
npx -y skills add dfk1352/LibreOffice-skills --skill libreoffice-calc

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 6 stars6 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when creating, editing, formatting, exporting, or extracting LibreOffice Calc (.ods) spreadsheets via UNO, including session-based cell and range edits, sheets, named ranges, validation, charts, patch workflows, and snapshots.

SKILL.md

11.3 KB, as published. Nobody here has run it

LibreOffice Calc

Use the bundled calc modules for UNO-backed Calc spreadsheet work. All paths must be absolute. Bundled modules live under scripts/ in this skill directory, so set PYTHONPATH=<skill_base_dir>/scripts. If setup or runtime issues appear, check references/troubleshooting.md.

API Surface

# Non-session utilities
create_spreadsheet(path, source=None)              # source: path to .json or .xml file to import
export_spreadsheet(path, output_path, export_format)   # formats: "pdf", "xlsx", "csv"
snapshot_area(doc_path, output_path, sheet="Sheet1", row=0, col=0, width=None, height=None, dpi=150)

# Session (primary editing API)
CalcSession(path) -> context manager

CalcSession methods:
  read_cell(target: CalcTarget) -> dict[str, object]
  write_cell(target: CalcTarget, value, value_type="auto")
  read_range(target: CalcTarget) -> list[list[dict[str, object]]]
  write_range(target: CalcTarget, data)
  format_range(target: CalcTarget, formatting: CellFormatting)
  list_sheets() -> list[dict[str, object]]
  add_sheet(name, index=None)
  rename_sheet(target: CalcTarget, new_name)
  delete_sheet(target: CalcTarget)
  define_named_range(name, target: CalcTarget)
  get_named_range(target: CalcTarget) -> dict[str, object]
  delete_named_range(target: CalcTarget)
  set_validation(target: CalcTarget, rule: ValidationRule)
  clear_validation(target: CalcTarget)
  create_chart(target: CalcTarget, spec: ChartSpec)
  update_chart(target: CalcTarget, spec: ChartSpec)
  delete_chart(target: CalcTarget)
  recalculate()
  patch(patch_text, mode="atomic") -> PatchApplyResult
  export(output_path, export_format)
  reset()
  close(save=True)

# Standalone patch utility
patch(path, patch_text, mode="atomic") -> PatchApplyResult

Structured Targets: CalcTarget

from calc import CalcTarget

CalcTarget(
    kind="cell" | "range" | "sheet" | "named_range" | "chart",
    sheet=None,
    sheet_index=None,
    row=None,
    col=None,
    end_row=None,
    end_col=None,
    name=None,
    index=None,
)

Target kinds

KindSupported fieldsUse
cellsheet or sheet_index, row, colRead or write one cell
rangesheet or sheet_index, row, col, end_row, end_colRead, write, format, validate, or chart a rectangular range
sheetsheet or sheet_indexRename or delete one sheet
named_rangenameInspect or delete one named range
chartsheet or sheet_index, plus name or indexUpdate or delete one chart

Resolution rules

  • Coordinates are zero-based and must be non-negative.
  • sheet and sheet_index are mutually exclusive.
  • name and index are mutually exclusive.
  • Range targets must keep end_row >= row and end_col >= col.
  • Chart targets must identify one sheet plus one chart selector.
  • Calc does not auto-convert a one-cell range into a cell target; keep those shapes explicit.

Cell Read Results

read_cell() and read_range() return cell dictionaries with the same shape:

{
    "value": 100.0,
    "formula": None,
    "error": None,
    "type": "number",
    "raw": 100.0,
}

Empty cells return type="empty" with value=None:

{"value": None, "formula": None, "error": None, "type": "empty", "raw": None}

Formula cells use type="formula"; when Calc reports a formula error, error is populated and value becomes None.

Boolean values (True/False) are stored as numeric 1.0/0.0. Reading back a cell written with a Python bool returns type="number" with value=1.0 or value=0.0, not a text string.

Formatting Payload: CellFormatting

from calc import CellFormatting

CellFormatting(
    bold=None,
    italic=None,
    font_name=None,
    font_size=None,
    color=None,          # named color or integer
    number_format=None,  # "currency" | "percentage" | "date" | "time"
)

Notes:

  • At least one formatting field must be set.
  • color accepts a named color or 0xRRGGBB integer.
  • format_range() works for both a cell target and a rectangular range target.

Validation Payload: ValidationRule

from calc import ValidationRule

ValidationRule(
    type="whole",
    condition="between",
    value1=1,
    value2=10,
    show_error=True,
    error_message="Enter a value from 1 to 10.",
    show_input=True,
    input_title="Allowed values",
    input_message="Only integers from 1 to 10 are valid.",
    ignore_blank=True,
    error_style=0,
)

Supported type values:

  • any
  • whole
  • decimal
  • date
  • time
  • text_length
  • list

Supported condition values:

  • between
  • not_between
  • equal
  • not_equal
  • greater_than
  • less_than
  • greater_or_equal
  • less_or_equal

Chart Payload: ChartSpec

from calc import CalcTarget, ChartSpec

ChartSpec(
    chart_type="line",
    data_range=CalcTarget(
        kind="range",
        sheet="Data",
        row=0,
        col=0,
        end_row=5,
        end_col=1,
    ),
    anchor_row=7,
    anchor_col=0,
    width=10000,
    height=7000,
    title="Revenue Trend",
)

Notes:

  • chart_type must be one of bar, line, pie, or scatter.
  • width and height use Calc chart rectangle units (the same units the packaged API already accepts).
  • Create charts by targeting a sheet; update or delete charts by targeting a chart.

Patch DSL

Use patch() or session.patch() to apply ordered spreadsheet operations.

[operation]
type = write_range
target.kind = range
target.sheet = Revenue Data
target.row = 0
target.col = 0
target.end_row = 2
target.end_col = 1
data <<JSON
[["Label", "Value"], ["Revenue", 100], ["Cost", 80]]
JSON

[operation]
type = format_range
target.kind = range
target.sheet = Revenue Data
target.row = 1
target.col = 1
target.end_row = 2
target.end_col = 1
format.number_format = currency
format.bold = true

[operation]
type = create_chart
target.kind = sheet
target.sheet = Revenue Data
chart.chart_type = line
chart.data_range.kind = range
chart.data_range.sheet = Revenue Data
chart.data_range.row = 0
chart.data_range.col = 0
chart.data_range.end_row = 2
chart.data_range.end_col = 1
chart.anchor_row = 5
chart.anchor_col = 0
chart.width = 9000
chart.height = 6000
chart.title = Revenue Trend

Supported operation types

  • write_cell
  • write_range
  • format_range
  • add_sheet
  • rename_sheet
  • delete_sheet
  • define_named_range
  • delete_named_range
  • set_validation
  • clear_validation
  • create_chart
  • update_chart
  • delete_chart
  • recalculate

Patch value rules

  • Use target.* fields for the primary target.
  • Use format.* fields for CellFormatting.
  • Use rule.* fields for ValidationRule.
  • Use chart.* fields for ChartSpec; chart source ranges use chart.data_range.*.
  • data must be valid JSON.
  • Heredoc blocks are supported with <<TAG ... TAG for multiline JSON or text.

Modes

  • atomic stops on first failure, resets the session, and persists nothing.
  • best_effort keeps successful earlier operations and records failures.

PatchApplyResult fields:

  • mode
  • overall_status = "ok" | "partial" | "failed"
  • operations = list of PatchOperationResult
  • document_persisted

For standalone patch(path, ...), document_persisted means the changes were saved to disk. For session.patch(...), it means the patch produced successful mutations in the current open session state.

Example: Build a Spreadsheet in Session

from pathlib import Path

from calc import (
    CalcSession,
    CalcTarget,
    CellFormatting,
    ChartSpec,
    ValidationRule,
)
from calc.core import create_spreadsheet

output = str(Path("test-output/revenue-report.ods").resolve())
create_spreadsheet(output)

with CalcSession(output) as session:
    session.rename_sheet(CalcTarget(kind="sheet", sheet="Sheet1"), "Revenue Data")
    session.add_sheet("Summary")
    session.write_range(
        CalcTarget(kind="range", sheet="Revenue Data", row=0, col=0, end_row=2, end_col=1),
        [["Label", "Value"], ["Revenue", 100], ["Cost", 80]],
    )
    session.format_range(
        CalcTarget(kind="range", sheet="Revenue Data", row=1, col=1, end_row=2, end_col=1),
        CellFormatting(number_format="currency", bold=True),
    )
    session.define_named_range(
        "RevenueValues",
        CalcTarget(kind="range", sheet="Revenue Data", row=1, col=1, end_row=2, end_col=1),
    )
    session.set_validation(
        CalcTarget(kind="range", sheet="Revenue Data", row=1, col=1, end_row=2, end_col=1),
        ValidationRule(type="whole", condition="greater_than", value1=0),
    )
    session.create_chart(
        CalcTarget(kind="sheet", sheet="Revenue Data"),
        ChartSpec(
            chart_type="line",
            data_range=CalcTarget(
                kind="range",
                sheet="Revenue Data",
                row=0,
                col=0,
                end_row=2,
                end_col=1,
            ),
            anchor_row=5,
            anchor_col=0,
            width=9000,
            height=6000,
            title="Revenue Trend",
        ),
    )
    session.recalculate()

Example: Patch an Existing Spreadsheet

from calc import patch

result = patch(
    "/abs/path/revenue-report.ods",
    """
    [operation]
    type = write_cell
    target.kind = cell
    target.sheet = Summary
    target.row = 1
    target.col = 1
    value = Ready
    value_type = text

    [operation]
    type = format_range
    target.kind = cell
    target.sheet = Summary
    target.row = 1
    target.col = 1
    format.bold = true

    [operation]
    type = recalculate
    """,
    mode="best_effort",
)

print(result.overall_status)

Snapshots

from pathlib import Path
from calc import snapshot_area

result = snapshot_area(doc_path, "/tmp/revenue.png", sheet="Revenue Data", row=0, col=0, dpi=150)
print(result.file_path, result.width, result.height)
Path(result.file_path).unlink(missing_ok=True)   # clean up used snapshots

Use snapshots to verify chart placement, formatting, and sheet layout before delivery.

  • snapshot_area() output dimensions can differ slightly from the requested size; treat small pixel differences as normal.

Common Mistakes

  • Passing a relative path; UNO-facing Calc APIs expect absolute file paths.
  • Mixing up cell and range targets; Calc keeps them distinct even for one-cell selections.
  • Using one-based coordinates; rows and columns are zero-based.
  • Assuming create_chart() picks a random later target name; when title is set, targeting the chart by that same name is the safest follow-up pattern.
  • The packaged API does not expose chart-listing or validation-inspection helpers; deeper verification may require direct UNO inspection in advanced workflows.
  • Forgetting chart.data_range.* fields when patching chart operations.
  • Expecting exact requested PNG dimensions from snapshot_area(); Calc export can differ by a small amount.
  • Forgetting to clean up captured snapshots after inspection.
  • Calling session methods after session.close().
  • JSON / XML import requires LibreOffice 26.2+.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.