<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mark</title>
    <description>The latest articles on DEV Community by Mark (@ifmelate).</description>
    <link>https://dev.to/ifmelate</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1091567%2F5f941475-2297-4287-b6f0-b2a4b63c1b3a.jpeg</url>
      <title>DEV Community: Mark</title>
      <link>https://dev.to/ifmelate</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ifmelate"/>
    <language>en</language>
    <item>
      <title>I didn't write this Excel formula engine. Here is why I trust it anyway</title>
      <dc:creator>Mark</dc:creator>
      <pubDate>Wed, 21 Oct 2026 15:28:57 +0000</pubDate>
      <link>https://dev.to/ifmelate/i-didnt-write-this-excel-formula-engine-here-is-why-i-trust-it-anyway-9p3</link>
      <guid>https://dev.to/ifmelate/i-didnt-write-this-excel-formula-engine-here-is-why-i-trust-it-anyway-9p3</guid>
      <description>&lt;p&gt;&lt;em&gt;SharpCell.Grid running in the browser. Try it with your own .xlsx: &lt;a href="https://ifmelate.github.io/SharpCell.Grid/demo/" rel="noopener noreferrer"&gt;live demo&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: SharpCell's code was written by Claude Code, with me directing it. This article was drafted with Claude too, and edited by me. Which is kind of the point of the article. Originally published on &lt;a href="https://medium.com/@ifmelate/net-i-didnt-write-this-excel-formula-engine-here-is-why-i-trust-it-anyway-fc5603cde220" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As we know, sooner or later every .NET project gets an .xlsx with formulas in it. A pricing model from the finance team, a template the customer fills in, a file that is, honestly, the real specification of the business logic. Reading the cells is easy. Calculating them is where the fun starts: change one input, and every formula that depends on it has to be recalculated, and the result has to be what Excel shows. Otherwise the numbers in your app and in the user's Excel quietly drift apart.&lt;/p&gt;

&lt;p&gt;The usual options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run real Excel on the server through Interop&lt;/li&gt;
&lt;li&gt;Rewrite the formulas in C# by hand&lt;/li&gt;
&lt;li&gt;Use a free library: &lt;strong&gt;ClosedXML&lt;/strong&gt; (MIT) and &lt;strong&gt;NPOI&lt;/strong&gt; both evaluate formulas&lt;/li&gt;
&lt;li&gt;Buy a commercial one, like &lt;strong&gt;EPPlus&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Drawbacks of each
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interop&lt;/strong&gt; needs Excel on the server, and Microsoft itself does not recommend or support server-side Office automation. Next.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual rewrite&lt;/strong&gt; works until the finance team changes the file. They will change the file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free libraries&lt;/strong&gt; may be all you need for simple workbooks. Check their function lists against your files first. I wanted dynamic arrays, LAMBDA, structured references and, most of all, a published measurement of how often the results match Excel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EPPlus&lt;/strong&gt; has all of that: 470+ functions, dynamic arrays, LAMBDA. Since version 5, commercial use needs a license, $569 per developer per year for a small team at the time of writing. Fair price for a good product. Still, a formula engine feels like something .NET should have for free, the way it has JSON.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I built one. More precisely, I directed Claude Code to build it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing SharpCell
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/ifmelate/SharpCell" rel="noopener noreferrer"&gt;SharpCell&lt;/a&gt;&lt;/strong&gt; is a free, MIT-licensed Excel formula engine for .NET 8 and later. Parser, dependency graph, recalculation, dynamic arrays, LET/LAMBDA, tables with structured references like &lt;em&gt;Sales[Units]&lt;/em&gt;. It reads .xlsx files, recalculates them and saves them back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of SharpCell:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Free, MIT, no license keys&lt;/li&gt;
&lt;li&gt;Results measured against real Excel (see below)&lt;/li&gt;
&lt;li&gt;490 functions, including dynamic arrays, LET, LAMBDA, MAP, BYROW, GROUPBY, PIVOTBY&lt;/li&gt;
&lt;li&gt;Custom functions in C#, for workbooks that call a VBA function or an add-in&lt;/li&gt;
&lt;li&gt;No third-party dependencies, AOT-compatible and trimmable, targets .NET 8 and .NET 10&lt;/li&gt;
&lt;li&gt;For servers: load a template once and &lt;em&gt;Clone()&lt;/em&gt; it per request&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting up SharpCell
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install the package
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package SharpCell.Xlsx   &lt;span class="c"&gt;# reads and saves .xlsx; brings SharpCell with it&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Load the workbook and recalculate it
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;SharpCell&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;SharpCell.Xlsx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Read the workbook: sheets, values, formulas and any results Excel saved with them.&lt;/span&gt;
&lt;span class="n"&gt;Workbook&lt;/span&gt; &lt;span class="n"&gt;workbook&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;XlsxReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Worksheet&lt;/span&gt; &lt;span class="n"&gt;budget&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;workbook&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Budget"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Calculate every formula now instead of relying on saved results.&lt;/span&gt;
&lt;span class="n"&gt;workbook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Recalculate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Or skip the file and build the workbook in code
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;workbook&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Workbook&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;Worksheet&lt;/span&gt; &lt;span class="n"&gt;sheet&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;workbook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sheet1"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"A1"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"A2"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Formula&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"=A1*3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;workbook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Recalculate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;CellValue&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"A2"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// 6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Let's now try more custom scenarios:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The workbook calls a function that doesn't exist.&lt;/strong&gt; The file was built with some add-in or a VBA function, and on the server it's just &lt;em&gt;#NAME?&lt;/em&gt;. Write that function in C#:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;workbook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"VAT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;CellValue&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// converted as Excel converts: "100" is 100&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                  &lt;span class="c1"&gt;// pass #VALUE! and other errors on&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsNumber&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;FunctionOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;MinArguments&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MaxArguments&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ScalarParameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"A1"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"A2"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;250&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"B1"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Formula&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"=VAT(A1)"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;// 20&lt;/span&gt;
&lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"C1"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Formula&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"=VAT(A1:A2)"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// a scalar parameter given a range: spills 20 and 50&lt;/span&gt;
&lt;span class="n"&gt;workbook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Recalculate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give it a range where it expects one value, and it runs once per element and spills, like a built-in function. It can even go where a LAMBDA is expected: &lt;em&gt;MAP(A1:A9, VAT)&lt;/em&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tables.&lt;/strong&gt; Structured references work in tables from files and from code. &lt;em&gt;SUBTOTAL&lt;/em&gt; and &lt;em&gt;AGGREGATE&lt;/em&gt; skip hidden rows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Saving.&lt;/strong&gt; The file is saved with your changes and recalculated values. New files can be created from objects or a &lt;em&gt;DataTable&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  So how do I trust code I didn't write?
&lt;/h2&gt;

&lt;p&gt;Here is the problem with letting an agent build something like this. If the agent writes the code and also writes the tests, it grades its own homework. Its tests encode its own idea of how Excel works, so a wrong idea passes every test.&lt;/p&gt;

&lt;p&gt;So the rule is: &lt;strong&gt;expected values never come from the agent. They come from Excel.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The test corpus is workbooks calculated by Microsoft Excel. Most of them are the test files of &lt;strong&gt;&lt;a href="https://github.com/ironcalc/IronCalc" rel="noopener noreferrer"&gt;IronCalc&lt;/a&gt;&lt;/strong&gt;, an open-source spreadsheet engine written in Rust, licensed MIT or Apache-2.0. Thanks to its authors for publishing them. They are copied unmodified, with the commit and license recorded in the repo. The rest are workbooks calculated in Excel for the web.&lt;/li&gt;
&lt;li&gt;Files saved by any app other than Excel are thrown out, because their saved values aren't Excel's.&lt;/li&gt;
&lt;li&gt;A conformance tool loads every file, recalculates every formula with SharpCell and compares it with the value Excel saved: numbers within a relative tolerance of 1e-9, errors of the same kind (&lt;em&gt;#N/A&lt;/em&gt; is not &lt;em&gt;#VALUE!&lt;/em&gt;), text exactly. The agent can change the engine as much as it wants. It can't change what Excel answered.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result: &lt;strong&gt;256 workbooks; of the 254 that contain formulas, 253 match Excel in every cell.&lt;/strong&gt; In cells it's 80,044 of 80,046, but be careful with that number: half of those cells come from a single ROMAN/ARABIC stress-test file, so the per-workbook number is the honest one. Of the 490 functions, 423 are exercised by at least one Excel-calculated case.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwjekhstary62k0dw8g5r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwjekhstary62k0dw8g5r.png" alt="The top of docs/compatibility.md" width="800" height="505"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The top of docs/compatibility.md. The full table covers all 490 functions and every test file&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The one workbook that doesn't fully match is &lt;em&gt;BESSELJ&lt;/em&gt;. SharpCell computes the exact value, while Excel's approximation is off by up to about 5E-7: &lt;em&gt;BESSELJ(10,1)&lt;/em&gt; is 0.0434722 in Excel and 0.0434727 exactly. It's the one place where you won't get Excel's number. It's also not the only deviation: 23 functions have one documented, for example the &lt;em&gt;REGEX&lt;/em&gt; functions use .NET regular expressions, not PCRE2. All of them are listed with reasons in &lt;a href="https://github.com/ifmelate/SharpCell/blob/main/docs/compatibility.md" rel="noopener noreferrer"&gt;docs/compatibility.md&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The same rule applies to bug reports: attach a small .xlsx that shows the problem and the value Excel calculates. Then the fix is checked against Excel's value, not against the agent's opinion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it's worse
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No benchmarks yet. Comparing load, recalculation and save against EPPlus and ClosedXML is the next item on the roadmap&lt;/li&gt;
&lt;li&gt;Links to other workbooks evaluate to &lt;em&gt;#NAME?&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Filter criteria are not evaluated: rows stay hidden the way the file left them&lt;/li&gt;
&lt;li&gt;No &lt;em&gt;CUBE&lt;/em&gt;, &lt;em&gt;RTD&lt;/em&gt; or &lt;em&gt;WEBSERVICE&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;No charts, pivot tables, pictures or shapes created (existing ones survive saving), no macros&lt;/li&gt;
&lt;li&gt;No &lt;em&gt;.xls&lt;/em&gt;, &lt;em&gt;.xlsb&lt;/em&gt; or encrypted files&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;Workbook&lt;/em&gt; is not thread-safe: one per thread&lt;/li&gt;
&lt;li&gt;0.x, so the API may change between minor versions until 1.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And it's maintained by one person, me (well, me and Claude), in spare time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus for those who work with agents
&lt;/h2&gt;

&lt;p&gt;The docs site has &lt;em&gt;llms.txt&lt;/em&gt; and &lt;em&gt;llms-full.txt&lt;/em&gt;, plus rules to paste into your agent's instructions, so your agent uses the actual API instead of inventing a plausible one. There is also &lt;strong&gt;SharpCell.Grid&lt;/strong&gt;, a spreadsheet control for Avalonia and WPF on the same engine. You can &lt;a href="https://ifmelate.github.io/SharpCell.Grid/demo/" rel="noopener noreferrer"&gt;try it right in the browser&lt;/a&gt;. Open your own .xlsx there, it's read on your machine and never uploaded.&lt;/p&gt;

&lt;p&gt;That's all :) The quickest way to try it is a real file from your own work: load it, call &lt;em&gt;Recalculate()&lt;/em&gt;, compare a few cells with Excel. If something doesn't match, that file is exactly the bug report I need.&lt;/p&gt;

&lt;p&gt;P.S. Links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/ifmelate/SharpCell" rel="noopener noreferrer"&gt;ifmelate/SharpCell&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs: &lt;a href="https://ifmelate.github.io/SharpCell/" rel="noopener noreferrer"&gt;ifmelate.github.io/SharpCell&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;NuGet: &lt;a href="https://www.nuget.org/packages/SharpCell.Xlsx" rel="noopener noreferrer"&gt;SharpCell.Xlsx&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live demo in the browser: &lt;a href="https://ifmelate.github.io/SharpCell.Grid/demo/" rel="noopener noreferrer"&gt;SharpCell.Grid demo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Test files: &lt;a href="https://github.com/ironcalc/IronCalc" rel="noopener noreferrer"&gt;IronCalc&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;If it saved you a license, a star on GitHub helps others find it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
