A typesafe F# DSL for building and reading Excel workbooks, with round-trip read/write and F# code generation.
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Documented (README)
git clone https://github.com/Kookerella-Ltd/Kookerella.FsOpenXmlDslResumen de Tools
# Kookerella.FsOpenXmlDsl
A typesafe F# DSL for building Excel workbooks, interpreted into calls against the
[DocumentFormat.OpenXml](https://github.com/dotnet/Open-XML-SDK) SDK. The DSL is a plain
data model (records/DUs with structural equality) — the interpreter (`Writer`) compiles it
to OOXML, and the reverse transform (`Reader`) parses an existing `.xlsx` back into the
same DSL.
See [MAPPING.md](MAPPING.md) for exactly which SpreadsheetML features map 1:1, which are
approximated, and which aren't modeled yet.
## Layout
- `src/Kookerella.FsOpenXmlDsl` — the library.
- `Reference.fs` — `CellRef` and `"A1"`-style address conversions.
- `Styles.fs` — cell formatting: `Color`, `FontStyle`, `FillStyle`, `BorderStyle`,
`AlignmentStyle`, `NumberFormat`, `CellProtection`, `CellStyle`.
- `Validation.fs` — conditional formatting and data validation: `ComparisonOperator`
(shared by both), `ConditionalFormatRule`, `ValidationKind`, `ValidationAlert`, and the
`ConditionalFormatEntry`/`DataValidationEntry` records stored on `Worksheet`.
- `Hyperlinks.fs` — `HyperlinkTarget` (external URL/`mailto:` vs. internal same-workbook
reference) and the `HyperlinkEntry` record stored on `Worksheet`.
- `Comments.fs` — `CommentEntry` (classic cell comments, i.e. current Excel's "Notes" -
see MAPPING.md for the modern threaded-comments gap).
- `Protection.fs` — `SheetProtection`, the sheet-level protection flags stored on
`Worksheet` (pairs with `CellStyle.Protection` for per-cell locking), and
`WorkbookProtection`, the workbook-level structure/window protection flags stored on
`Workbook`.
- `DefinedNames.fs` — `DefinedNameScope`/`DefinedNameEntry`, stored on `Workbook` rather
than `Worksheet` - the one DSL concept that's genuinely workbook-level.
- `PageSetup.fs` — print settings: `PageOrientation`, `PaperSize`, `PrintScaling`,
`PageMargins`, and the `PageSetup` record stored on `Worksheet`.
- `Tables.fs` — Excel Tables: `TableColumn`, `TableStyle`, and the `TableEntry` record
stored as a list on `Worksheet` (a sheet can have several).
- `Sparklines.fs` — in-cell mini-charts: `SparklineType`, `SparklineStyle`,
`SparklineCell`, and the `SparklineGroupEntry` record stored as a list on `Worksheet`
(a sheet can have several independently-styled groups).
- `Charts.fs` — column/bar/line/pie charts: `ChartType`, `ChartSeries`, and the
`ChartEntry` record stored as a list on `Worksheet` (a sheet can have several).
- `Images.fs` — raster images: `ImageFormat` and the `ImageEntry` record (raw file
bytes plus a cell-range anchor) stored as a list on `Worksheet`.
- `PivotTables.fs` — `PivotAggregation` and the `PivotTableEntry` record (source range,
row/column/value fields, an anchor cell) stored as a list on `Worksheet`.
- `Model.fs` — `CellValue`, `Cell`, `Worksheet`, `Workbook` (including `Workbook.
VbaProject`, a macro-enabled workbook's raw `vbaProject.bin` bytes - see its own doc
comment; there's no dedicated `Macros.fs` since it's a single opaque field, not a new
type).
- `Builders.fs` — ergonomic helpers: plain functional constructors (`cellA1`, ...) for
the canonical model, plus the `SheetItem`/`CellEntry` types (each a single simple DU
case with optional fields) and the `sheet` fold function - a small tree-shaped "AST
for building a sheet" (rows of cells, plus sheet-level facts like column widths,
merges, conditional formats, data validations, hyperlinks, comments, autofilter, and
sheet protection) that mirrors how SpreadsheetML itself nests. `SheetDsl` is what you
actually write against: `cell`/`row`/`autoFilter`/`conditionalFormat`/
`dataValidation`/`hyperlink`/`comment` members with real optional parameters (`?col`,
`?style`, `?index`, the data validation alert fields, `?tooltip`, `?author`) - no
builder objects, no separate "styled" function, no `None`-noise for the common case.
(`Protect` is the one `SheetItem` case with no smart constructor - `SheetProtection`
is a plain record you build the usual F# way, `{ SheetProtection.Default with ... }`.)
- `Interpreter/StyleRegistry.fs` — interns fonts/fills/borders/number formats into a
shared OOXML stylesheet (internal).
- `Interpreter/ChartWriter.fs` / `ChartReader.fs` — charts' own DSL ↔ DrawingML/ChartML
translation, split out from `Writer.fs`/`Reader.fs` given how much larger that one
feature's OOXML surface is than everything else combined (internal).
- `Interpreter/ImageWriter.fs` / `ImageReader.fs` — images' own DSL ↔ DrawingML
translation (internal).
- `Interpreter/DrawingWriter.fs` / `DrawingReader.fs` — own the one `DrawingsPart`/
`<drawing>` relationship a worksheet gets when it has charts and/or images, since both
features share that one drawing canvas rather than each managing their own (internal).
- `Interpreter/PivotTableWriter.fs` / `PivotTableReader.fs` — pivot tables' own group-by
+ aggregate engine plus DSL ↔ OOXML translation (`pivotCacheDefinition`/
`pivotCacheRecords`/`pivotTableDefinition`), split out from `Writer.fs`/`Reader.fs` the
same way charts and images are (internal).
- `Interpreter/Writer.fs` — DSL → OOXML (internal).
- `Interpreter/Reader.fs` — OOXML → DSL, the reverse transform (internal).
- `Interpreter/CodeGen.fs` — DSL → F# *source text*: renders a `Workbook` back out as a
self-contained `.fsx` script that rebuilds an equivalent file when run (internal).
- `Api.fs` — the public `Workbook.save` / `saveToStream` / `load` / `loadFromStream` /
`generateScript` entry points.
- `tests/Kookerella.FsOpenXmlDsl.Tests` — one test per feature, each validating the produced file
against the OOXML schema (`DocumentFormat.OpenXml.Validation.OpenXmlValidator`) and
asserting an exact round trip back through the DSL. Each test also writes the workbook
it builds to `Examples/<test name>/output.xlsx` (checked into the repo), so every
feature has a real, openable `.xlsx` demonstrating it - a browsable gallery, not just
assertions. Each scenario also gets an `Examples/<test name>/script.fsx` - see
"Regenerating a file as F# source" below - which a separate, slower `Category=Slow` test
group actually executes via `dotnet fsi` and verifies against the committed `.xlsx`.
`Assets/` holds the one test fixture too large to inline as a base64 literal like every
other binary fixture in `Tests.fs` - a real `vbaProject.bin` extracted from a workbook
actually saved by Excel, used by the macro example.
- `samples/Kookerella.FsOpenXmlDsl.Sample` — a small console app that builds a workbook, saves it,
and reads it back.
- `src/Kookerella.CsOpenXmlDsl` — an idiomatic, immutable, fluent C# wrapper over this
library, for callers who'd rather not touch F# discriminated unions/option types
directly. Deliberately narrow first pass (cell values, formulas, basic styling, `Save`/
`Load`) - see its own README for scope and an example. `tests/Kookerella.CsOpenXmlDsl.Tests`
is its own C# xUnit suite, exercising the wrapper the way a real C# caller would rather
than reusing the F# test project.
- `src/Kookerella.FsOpenXmlDsl.Mcp` — a local MCP (Model Context Protocol) server exposing
this library's read/write/code-generation capabilities as tools any MCP-compatible AI
agent can call directly - see its own README for the tool list and how to configure it.
## Quick start
```fsharp
open Kookerella.FsOpenXmlDsl
open type Kookerella.FsOpenXmlDsl.SheetDsl
let headerStyle =
{ CellStyle.Default with
Font = Some { FontStyle.Default with Bold = true }
Fill = Some { Color = Rgb(220uy, 220uy, 220uy) } }
let data =
sheet
"Sheet1"
[ row [ cell (Text "Name", style = headerStyle)
cell (Text "Amount", style = headerStyle) ]
row [ cell (Text "Widgets")
cell (Number 42.5, style = { CellStyle.Default with NumberFormat = Some TwoDecimal }) ]
Freeze(1, 0) ]
workbook [ data ] |> Workbook.save "out.xlsx"
// Reverse transform:
let roundTripped = Workbook.load "out.xlsx"
```
`CellEntry` and `SheetItem`'s row case are each a single simple DU case with optional
fields (`Col`/`Index`) rather than separate "styled" or "explicit position" cases - `None`
means "the next column/row after the previous entry" (starting at 0), `Some n` jumps there
explicitly and sequential numbering resumes right after it. You don't construct the case
directly, though: `SheetDsl.cell`/`SheetDsl.row` are members with real optional
parameters (`?col`/`?style` on `cell`, `?index` on `row`) that hide the `None`s for
the common case - plain `let` functions can't have optional parameters in F#, which is why
this one bit of the DSL is a type. `open type Kookerella.FsOpenXmlDsl.SheetDsl` (alongside `open Kookerella.FsOpenXmlDsl`) brings `cell`/`row`
into scope unqualified, same as a module. Explicit column/row jumps go through the same
two members, just with the optional argument supplied: `cell (value, col = 2)` and
`row (cells, index = 4)`. `sheet` is the one fold that interprets the resulting item
list into the canonical `Worksheet` (the same relationship `Writer` has to OOXML). If you
already have cells pre-addressed by `CellRef` rather than grouped by row, `sheetOfCells`
builds a `Worksheet` directly from a flat `Cell list` instead.
**A `Formula` cell is `Formula(expression, cachedValue: float option)` - this library never
evaluates formulas itself, so `cachedValue` is the only number that will ever exist for that
cell until something else computes one.** Real Excel recalculates on open and overwrites it,
so leaving it `None` is fine if a human always opens the result in Excel first. It's *not*
safe for a headless pipeline - e.g. generating a workbook and piping it straight into a PDF
converter, another automated reader, or anything else that never opens it in real Excel.
Whether that downstream step showsLo que la gente pregunta sobre Kookerella.FsOpenXmlDsl
¿Qué es Kookerella-Ltd/Kookerella.FsOpenXmlDsl?
+
Kookerella-Ltd/Kookerella.FsOpenXmlDsl es tools para el ecosistema de Claude AI. A typesafe F# DSL for building and reading Excel workbooks, with round-trip read/write and F# code generation. Tiene 0 estrellas en GitHub y su última actualización registrada es del 2026-08-23.
¿Cómo se instala Kookerella.FsOpenXmlDsl?
+
Puedes instalar Kookerella.FsOpenXmlDsl clonando el repositorio (https://github.com/Kookerella-Ltd/Kookerella.FsOpenXmlDsl) o siguiendo las instrucciones del README en GitHub. ClaudeWave también te ofrece bloques de instalación rápida en esta misma página.
¿Es seguro usar Kookerella-Ltd/Kookerella.FsOpenXmlDsl?
+
Nuestro agente de seguridad ha analizado Kookerella-Ltd/Kookerella.FsOpenXmlDsl y le ha asignado un Trust Score de 87/100 (tier: Trusted). Revisa el desglose completo de comprobaciones superadas y flags en esta página.
¿Quién mantiene Kookerella-Ltd/Kookerella.FsOpenXmlDsl?
+
Kookerella-Ltd/Kookerella.FsOpenXmlDsl es mantenido por Kookerella-Ltd. La última actividad registrada en GitHub es del 2026-08-23, con 0 issues abiertos.
¿Hay alternativas a Kookerella.FsOpenXmlDsl?
+
Sí. En ClaudeWave puedes explorar tools similares en /categories/tools, ordenados por popularidad o actividad reciente.
Despliega Kookerella.FsOpenXmlDsl en tu cloud
Lleva este repo a producción en minutos. Cada plataforma genera su propio entorno con variables de entorno editables.
¿Mantienes este repo? Añade un badge a tu README
Pega el badge en tu README de GitHub para mostrar que está auditado por ClaudeWave. Cada badge enlaza de vuelta a esta página y muestra el Trust Score actual.
[](https://claudewave.com/repo/kookerella-ltd-kookerella-fsopenxmldsl)<a href="https://claudewave.com/repo/kookerella-ltd-kookerella-fsopenxmldsl"><img src="https://claudewave.com/api/badge/kookerella-ltd-kookerella-fsopenxmldsl" alt="Featured on ClaudeWave: Kookerella-Ltd/Kookerella.FsOpenXmlDsl" width="320" height="64" /></a>Más Tools
A single CLAUDE.md file to improve Claude Code behavior, derived from Andrej Karpathy's observations on LLM coding pitfalls.
An AI skill that provides design intelligence for building professional UI/UX across multiple platforms.
🪨 why use many token when few token do trick — Claude Code skill that cuts 65% of tokens by talking like caveman
CLI proxy that reduces LLM token consumption by 60-90% on common dev commands. Single Rust binary, zero dependencies
The best-benchmarked open-source AI memory system. And it's free.
The fastest, litest AI Gateway. Rust core with Python SDK. Call 100+ LLM APIs in OpenAI (or native) format with cost tracking, guardrails, load balancing, and logging [Bedrock, Azure, OpenAI, Anthropic, OpenAI, VertexAI, vLLM, Nvidia NIM]