Browse the docs
Current: v0.39.0
Changelog
What changed in each draft, and what is still undecided.
Releases
v0.39.0 · Lender-grade: currencies, hedging, VAT, tax, the Navigator 16 October 2026
convert(x): an amount in another currency in the model's, each period at that period's rate, at the model's rate for that currency (itsfxline, or the one input quoted in it) or at the oneat:names. A cost paid in yuan iscapex panels = convert(panels_cny).- Forward cover:
cny = fx(spot: inputs.cny_per_usd, forward: inputs.cny_forward, hedged: 100 %) | during constructionis the rate that converts what is hedged at the forward rate (or spot plus forwardpoints:) and the rest at spot;converttakes it first. - Interest rate swaps:
base = swap(floating: inputs.sofr, fixed: inputs.swap_rate, hedged: 75 %, spread: 0.1 %/y), the base rate a loan pays its margin over, with the share swapped as an input or a profile. - VAT:
vat,vat_refundandvat_facilityin the model block, andvat capitalisedorvat noneafter a capex. Rufineer writes a VAT sheet (the VAT on each capex, the refunds, the receivable, the facility), puts the VAT in the uses of funds, the facility in the sources, the capitalised VAT in the assets' cost, the refunds in the cash flow (not in CFADS) and the facility's interest in the income statement, with checks that the VAT is refunded and the facility repaid. - A tax regime:
tax { rate … holiday … holiday_rate … loss_expiry … loss_limit … interest_cap … minimum … withholding … }in the model block: a tax holiday or a reduced rate, losses that lapse and a limit on what they set off (alsotax_losses(profit:, expire:, limit:)), interest deductible up to a share of EBITDA with the rest carried forward, a minimum tax on revenue, and tax withheld on dividends in the equity cash flow.tax inputs.tax_rateis as before. - The Navigator: every exported workbook has a Navigator sheet after the Dashboard, a link to every sheet, input group and section, and a Navigate button at the top of every sheet that comes back to it. It is a link, not a macro, so it works in the
.xlsx, the.xlsm, and Excel on Windows, the Mac and the web.navigator offleaves it out. - A new example, Kariba Solar 50 MWp (New model ▸ Examples): a lender's model with costs in three currencies bought forward, a swapped loan, VAT with a VAT facility and a tax holiday.
valid_until 2026-12-15 "…": a model sent out for review can stamp the exported workbook with an amber Valid until … banner on every sheet, with an optional message. It is a visible label only — it changes no cell and runs no macro, and nothing happens to the file past the date. Off unless set. (Rufineer will not build a workbook that destroys or hides a recipient's data on a date.)- All of it in the Go compiler only; models that don't use it compile to the same workbook as before.
v0.38.0 · One file per module 14 October 2026
- One file per module: a module's inputs and its calculations are one file,
ops.rfn, itsinputsblocks first, thenmodule ops, and one sheet in the workbook;reports.rfnholds the statements, dashboard and sensitivities, andchecks.rfnyour checks. A module that grows can be a folder:debt/senior.rfnanddebt/reserves.rfneach writemodule debt { … }, one module and one sheet, in the order ofsheets [ops, debt/senior, debt/reserves]. The first layout (inputs/besidecalculations/, andoutputs/) still compiles; Use one file per module… in the menu (☰) moves a model's files, and the workbook doesn't change (the test suite checks the same sheets and numbers for 115 models). New models, the generators and the tutorials use it.
v0.37.0 · Rufineer is a web app 14 October 2026
- Rufineer is a web app. Sign in on this website and model in your browser, at /app: nothing to install. The compiler and the calculations run in the page, so the model recompiles and solves as you type. Models are kept with your account: start one from a template or a tutorial's finished model, import a
.zipof a model's folder, and download its files any time (Get started). Therfncommand line and the VS Code extension are retired, withrfn preview,rfn login, the installers and API tokens; the app's console runs the same commands on the model's files (The console). Export to Excel (Pro) downloads the workbook from the app. - Decimal places:
decimals 0in the model block,| decimals 2on a module's, an inputs block's or a statement's title (its sheet), or on a line, an input or a statement's row; the nearest one counts. The preview and the exported workbook show the same places. In the Go compiler only. - Statements by quarter and by month:
| sum by quarterand| sum by month, with| at quarter endand| at month endfor balances, beside by year and by half;reports by quarterorby monthfor the statements Rufineer writes. The sheet shows the day each column ends; the preview titles them Q3 2028 and Jul 2027. A timeline whose periods are longer than the statement's columns is an error that says what to sum by instead. In the Go compiler only. - Your own units: declare the things a model counts and the measures it uses in a
unitsblock (bottle,case_12 = 12 bottle,lb = 0.45359237 kg,bp = 0.01 %), and use them as any other unit: the conversions are written into the formulas. The editor colours them, hover says what each is, F12 goes to its declaration. - Troy ounces and grams:
ozandgare units of mass withkgandt, so a gold price inUSD/oztimes kilograms is money, the ×32.1507 written into the formula.workdays(from:, to:)counts the days Monday to Friday between two dates (NETWORKDAYS), highlighted and completed in the editor too. - Sources and uses by declaration:
uselines for uses other than capex, classes ofshares … up toa commitment and one= rest, a loan'ssize: 70 % of costsorof uses(solved),signed: base_case,upfront_fee:,commitment_fee:andinterest_during_construction: paid, and the order in one place, the model'sdrawdown: who pays before financial close, thenpro_rata on uses(the default),pro_rata on costs,equity_first,debt_firstorin_order [ … ]with sources side by side, and the equity's own order. Rufineer writes each draw as a line on the Sources and uses sheet, with its checks.conventions fundingwrites only that sheet, for a model that writes its own statements. A model with none of the new words is written exactly as before. In both compilers, Rust and Ruby. - Every tutorial declares its funding, and each shows the other way too: Tutorials 2, 3 and 4 and By hand their funding written by hand, Tutorials 1 and 5 the loans' draws written out. The test suite solves both ways of each and checks every case gives the same results.
- Depreciation on each capex, in a record on its line:
capex epc = spread(inputs.epc, over: construction, depreciation: {life: 25y, method: straight_line}).method:isstraight_line,accelerated(by aschedule: [50 %, 25 %, 25 %], the share written off each year) ornone(kept at cost, like land);allowance:a tax life or schedule;from:when it starts. Thedepreciationcomponent takesschedule:too, each amount written off by its own age. In both compilers, Rust and Ruby. - A loan's
financing_costs: capitalised | amortised | expensed: its fees and its interest while building in the assets' cost (the default), the fees written off over the loan's life as a finance cost (IFRS 9) with what is left on the balance sheet, or both a finance cost as they are charged. - Goal Seek in the model:
bid_toll = seek(inputs.toll, returns.equity_irr == inputs.target_irr) "Bid toll". The Solve macro changes the input until the target is met, settling the loops at each try, in the base case (the sensitivity cases keep the value it found); the line shows the value and the gap, and a check fails until it is closed. The preview and Export to Excel find the same value, so the exported workbook opens with the target met. In both compilers, Rust and Ruby. - Completion of a call's arguments: inside
loan(it offerssize:,rate:,repay:… (the required ones first, the ones already written left out), afterrepay:the ways it can be repaid, afterinterest_during_construction:paidorrolled_up, and the same in a capex'sdepreciation: {…}record. Parameter hints show the call's arguments and what the one being written means. - The Sources and uses sheet shows one class of shares that pays the rest as the share capital, one row (it showed the class and Share capital, the same numbers twice). The Language page explains interest during construction: rolled up or paid, what each writes, and the gearing.
- A model with no phase before
operations(a business that already runs, as in Tutorial 4) can declare its funding: the uses are paid for in the first period of operations, and financial close is that period. - The website: Pricing (free, and Pro for the export); what the automatic checks prove and what still needs a modeller's review; what the 698- and 741-workbook libraries were used for. The design rules moved to the Language page and the feature list to the Guide.
- Values in titles:
section "… for {inputs.allowance_life} years"shows the input in the title, and the workbook keeps it live with a formula. In both compilers, Rust and Ruby. - The preview: the audit outlines the cells a value reads, as Excel's F2 does; zoom with ⌘+ ⌘− ⌘0.
rfn generate dashboardwrites a first dashboard from the model's own lines (the returns, the debt cover, the funding, a chart of revenue and of the DSCR);rfn generate case [input]adds a sensitivity case that moves an input by 10%. The preview's Overview and Sensitivities offer them as Create dashboard and Add sensitivity case.- Workbooks: the Unit column is as wide as the sheet's longest unit, so no unit is cut off. In both writers, Rust and Ruby.
- The preview: a narrow preview puts the tabs that don't fit under More; units are never cut off in the preview's sheets and inputs.
v0.36.0 · Rufineer moves to the command line and VS Code 13 October 2026
- The desktop app is replaced by two things you install like any developer tool:
rfn, one command for macOS, Windows and Linux (npm i -g rufineer, acurlor PowerShell script, Homebrew orgo install), and the Rufineer extension for VS Code. Models don't change: the same folders of.rfnfiles compile to the same workbooks. rfnis the compiler, the formatter and the authoring commands (new,generate,check,fmt,explain,conventions,data), written in Go and checked against the Rust compiler model by model, value by value. New:rfn lsp, the language server, andrfn preview, the preview in your browser, live as you save (The rfn command).- VS Code: problems as you type in the Problems panel, hover for a line's formula in names and its unit, Go to Definition (F12), Find All References (⇧F12), completion of names and each function's arguments, Format Document and format on save, the outline, and the preview beside the editor: Overview, Inputs, Sheets, Sensitivities, Checks, Problems, Conventions, the audit of any value and the Console, as in the app.
- Pro, a monthly subscription, is Export to Excel: the solved, lender-grade
.xlsmwith its macros (or a plain.xlsx), built on Rufineer's server, from the preview, from VS Code or withrfn export. Everything else is free (Pricing). Licences, Machine IDs, offline keys and the 14-day trial are gone; an account signs in fromrfn loginor VS Code. - The guide and every tutorial are rewritten for VS Code and
rfn; the models, the files and the results are the same.
v0.36.0 · the desktop app 3 October 2026
- FinLang is now Rufineer (Ruby and Rust, financial engineering). Model files are
.rfn; the command line isrfn. Rename a model's.finfiles to.rfn: nothing inside them changes. - Rufineer is a desktop app for macOS, Windows and Linux, written in Rust. New model, the editor, a preview that compiles and solves as you type, the audit panel, Generate and the Console, the data workbook, and Export to Excel (solved, with its macros).
- Licences: one person, one computer, a year at a time, checked offline. Create an account for a 14-day trial, then get a key for your Machine ID on your account page.
- The guide and the tutorials are written for the app; every step is replayed by the test suite, as before.
- A new mark, and the website's palette in the app.
v0.35.0 1 October 2026
- Conventions: a line says what it is (
revenue,cost,capex … life, a loan, areserve) and Rufineer writes sources and uses, fixed assets, tax, the income statement, the cash flow and its waterfall, the balance sheet, the returns, the statements by year and the checks.rfn conventionsprints them. - Loans draw
share:orsize:of the construction costs, are paid in the order written, have interest during construction capitalised, andby: shareholdersmakes a shareholder loan; areservesits in the waterfall where it is written. - Model settings
tax,discount,reportsandconventions off; any derived line, statement or the dashboard can be replaced by your own. rfn newwrites a plant with kinds that builds with its statements;rfn generate revenue|cost|capex|loan|reserve <name>adds a line and its inputs where it belongs.- Tutorial 1 and Tutorial 5 are written with kinds; the old Tutorial 1 is By hand.
v0.34.0 30 September 2026
- Tutorial 5: a hydro plant with a PPA of 20 or 25 years, costs in rand, a refinancing, mezzanine and shareholder loans, and a lenders' report by half-year.
- A phase's length can depend on a scenario:
operations ppa(short: 20y, long: 25y). The columns fit the longest case. - Junior debt and refinancing:
loantakescash:(paid only as far as the cash goes, with arrears),capitalise:(interest rolled up),repay: sweepandrefinance:. - Statements by half-year (
| sum by half,| at half end), and+ moduleto roll up a whole module. - Several currencies: the help for a currency mismatch names the exchange rate to use.
- A line that reads a failed line or loan is no longer reported as an error of its own.
v0.33.0 29 September 2026
rfn fmtbreaks every line over 100 characters where it can: formulas before a| during,then/else,and/or,+/−or*//(pieces under the=), labels onto a line of their own, arguments after a comma, checks under their condition. A break is kept only if the model stays the same.- Labels line up only where every line stays within 100 characters.
v0.32.1 29 September 2026
rfn fmtbreaks a line over 100 characters with a[…]list of names (by [pv, cables, …],sheets […]) over lines, as many names to a line as fit, the]on a line of its own.sheets [ … ]in the model block can go on over several lines.
v0.32.0 29 September 2026
- An Input tables sheet: each table has its keys across (Year 2026, 2027 … or Month 1, 2, 3 …) and a row per column under them, from column H; the Inputs sheet keeps the single inputs.
- The Imports group's +/− buttons show (they were hidden).
v0.31.0 29 September 2026
- A table is imported as rows: one row per column, its values across under the table's keys (Month 1, 2, 3 …), not a row per value.
- The Imports group is left open; click − by Imports to fold it away.
v0.30.1 29 September 2026
- The Imports at the top of each sheet are an Excel group, folded away: click + by Imports (or the 2 button) to show them.
- A whole number typed as an input is imported as typed: 2026, not 2,026.00.
v0.30.0 29 September 2026
- Totals by group:
sum(x, by: tax_year)(andavg,min,max), withat:for another group;sum(table). prev(x, 12): twelve periods back, counting columns.year(d),month(d),date(y, m, d)andround(x, 2).- A switch that starts on another case:
scenarios design "EPC bid" start bid_b { … }; a label after an input's value. npvof energy for a levelised cost; the running total of a flag is a count; thousands of a currency (kUSD) are formatted as money.
v0.29.0 29 September 2026
- Tables with columns side by side:
by yield_casegives a column per scenario case, picked by the switch;by [one, two, cpi]names columns read withlookup(…, column: cpi).
v0.28.2 29 September 2026
- Tables on the Inputs sheet are titled by their data workbook sheet, with one row of column titles (Year | %) and then just years and values; years are numbers, not text.
- Whole numbers typed without a unit show as typed: 2020, not 2,020.00.
v0.28.1 29 September 2026
- Dashboard charts keep their dates apart: line charts on a date axis labelled every year or two, and column charts of amounts one column per financial year (a Chart data table under the charts adds them up).
v0.28.0 29 September 2026
lookup(table, n)for curves typed by year, andby_age(amounts, rates)for MACRS-style schedules by vintage.- A solve that is one number is one cell, so a solved debt size can go on the Dashboard or be a funding limit.
- Funding limits may change over time;
tolerancemay follow a solve's label; flags added up are a count.
v0.27.0 28 September 2026
- Spare columns: the sheets run 10 years past the last phase (
spare 5yto choose), so a phase can be made longer on the Inputs sheet without running out of columns. - The spare columns are outside the model: phase flags,
after, windows and depreciation are 0 there, and totals, minimums, MIRR and checks stop at the end of the last phase. A check fails if the timeline runs past the last column.
v0.26.0 28 September 2026
loan(…): a loan repaidequal,annuity,bulletorsculpted(cfads:, dscr:), with interest and principal on dates of their own (interest_every: 3m, principal_every: 6m).dscr(cfads:, loan:)on the loan's test dates, andllcr(cfads:, loan:), the loan life cover ratio.examples/loans: four loans, one per method, and a senior loan sized so that sculpting repays it exactly.- Fix:
(1 + r * 3m) ^ 4lost the /12 of the months.
v0.25.2 27 September 2026
- Fix: Tutorial 2's average DSCR counted periods after the tenor, where a loan repaid to the last cent in Excel leaves a few millionths; it only counts the tenor now (1.78x).
v0.25.1 27 September 2026
- Fix: the editor no longer marks a tutorial step's files, or a loose .rfn file, with "no model block found"; they are checked for syntax only. The planned-language examples aren't checked in the editor.
v0.25.0 27 September 2026
- Funding: a Sources of funds block with their total (
capex.sources), then Drawn to date, instead of each source's running total under it. | during constructionafter a funding source limits when it pays.- Tutorial 2: development costs are part of the uses of funds, and the construction sheet reads uses, then sources, each with its total.
v0.24.1 27 September 2026
- Fix: vehicles, tonnes, area and other physical amounts showed up to four decimals; they are whole numbers now, and goods get a Total.
v0.24.0 27 September 2026
- Scenarios: a drop-down switch per set at the top of the Inputs sheet, with the inputs that differ right under it, one column per case.
- Every sheet shows the cases in use at the top, each a link to its switch.
- The sensitivity case is a drop-down too: the base case, or a case by its title.
v0.23.0 27 September 2026
- A new look for the workbook: a grey title bar, large section titles with room between them, and sub-headers on every sheet. No red.
section "Revenue"in a module puts a sub-header over the lines after it.- The Inputs sheet groups each file's blocks under its module's title, with each block as a sub-header;
sectioninside a block adds a smaller one.
v0.22.0 27 September 2026
- Tutorial 4: a cement works with a new kiln. Sales by the bag and by the tonne, a quarry, a kiln and a mill, make or import, coal scenarios, a balance sheet, payback and a DCF valuation.
- The
bagandkgunits; a price per bag times tonnes says what is missing. payback(flows): how long until the running total of a cash flow turns positive.- An
@notecan follow| grow …;rfn fmtlines up the cases of ascenariosblock.
v0.21.2 27 September 2026
- Fix: the tutorial tests no longer fail on a Mac because of the
.DS_Storefiles Finder makes.
v0.21.1 27 September 2026
- Fix: on Ruby 4 every command printed a warning about
tsort; Rufineer no longer uses it.
v0.21.0 27 September 2026
- Scenarios: alternatives for some inputs, one column per case on the Inputs sheet,
capex = design(bid_a: 16 mUSD, bid_b: 15.2 mUSD), with a selector for the case in use. - A sensitivity case can pick a scenario,
case "Bidder B" { design = bid_b }, so one run of the macro compares every case.
v0.20.1 27 September 2026
- The standalone
rfnand licence files of 0.20.0 are removed for now: Rufineer is installed as a gem, as before.
v0.19.0 27 September 2026
- A smaller language: one page of Language, 44 keywords, and a library of functions. The full design moved to The planned language.
window(from:, for:)replacesperiod, andbase_case(…)replaces| base case. The old forms still compile, with a warning.| duringand totals take a condition:| during operations.year <= 5,sum(noi, during: operations.year == 2).ramp(from:, over:),after(date)andbefore(date).convergedchecks are no longer needed.
v0.18.0 27 September 2026
- Tutorial 3: an apartment development, from the land to the sale, with a construction loan and a joint venture.
- Real estate units:
sqm,sqft,ha,acre, and counted things:unit,lot,space,roomorkey,bed; anightis a day. - A number without a unit can't be added to money:
revenue + 500andrevenue + inputs.storeysare errors. mirr,multipleandeffective: the modified IRR dated like XIRR, the equity multiple, and a yearly rate compounded over the period.fundingcan start with one source:first equity up to ….- Fix: formatting broke a call whose arguments go on to the next line.
v0.17.2 27 September 2026
- A new docs site: a home page and an About page, a dark theme, a sidebar that follows each page, numbered tutorial steps and code blocks you can copy.
- Company, deal and place names in the examples are fictional.
v0.17.1 27 September 2026
- Fix:
depreciationwrites off each amount over its own life from when it is placed in service. Capex added after depreciation had started (a replacement, a second phase) used to speed up the write-off of the older cost. The tutorials were not affected. trailing(x, 12m): the last 12 months of a line, this period included, for backward-looking covenant tests.
v0.17.0 26 September 2026
- The two tutorials follow project finance practice throughout. Tutorial 2's preference coupons compound on their arrears and are capitalised during construction; dividends are paid only out of profits; the accounts carry deferred tax; the DSRA looks six months ahead, is topped up before the shareholder loan and earns interest; the loan keeps its base-case size in the lenders' cases. Tutorial 1 depreciates to exactly zero, measures the project IRR with the project's own tax and indexes its 2027 prices from financial close.
ahead(x, 6m)andlag(x, 6m): look ahead or lag by a length of time, whatever the length of the periods.plant = depreciation(cost:, life:, from:): straight-line depreciation with a book value that stops at zero.| base case: a debt size (or any calculation) that sensitivity cases keep at its base-case value; the Solve macro stores it.- The profile check adds up the profile as laid out along its phase.
v0.16.0 26 September 2026
- A formatter:
rfn fmt, Format Document in VS Code, and format on save for.rfnfiles by default. It lines names, units,=, modifiers, labels and notes up in columns and fixes indentation and spacing, and changes nothing else.
v0.15.0 26 September 2026
rfn buildwrites an.xlsmwith the Solve and Run sensitivities macros inside and buttons for them on the Dashboard: open it, enable macros, press Solve. Nothing to import.rfn build --exclude-macroswrites a plain.xlsxand the macros beside it assolve.bas, for places that block macros.
v0.14.0 26 September 2026
- Tutorial 2: a 40 MWac solar plant selling to a gold mine, from an empty folder, with VAT and a VAT bridge, a funding cascade through preference shares, a tax holiday and an equity waterfall by instrument.
fundingsources can have limits (up to) and an order (then), with onerestsource last.- A date plus a duration is a date:
operations.start + 12.5y. - Solar units:
kWp,MWp,MWac.spreadwithout a profile spreads evenly.
v0.13.0 26 September 2026
- Tolerances are written with the word
toleranceinstead of±:check "Balance sheet balances" a == b tolerance 1 USD. A file that still has±gets an error saying what to write.
v0.12.0 26 September 2026
- Every
solveline gets a check by itself, … solved (run the Solve macro), so the master check fails until the Solve macro has been run. You no longer need to write… converged; do so only to set a different tolerance.
v0.11.0 26 September 2026
- The tutorial and the starter model charge interest on the loan's opening balance, with no drawdown-timing input. For more precision during construction, give it a monthly step.
- Fix: a loop through a total over time (interest during construction → total cost → depreciation → tax → repayments → next period's balance) was missed, and the workbook had a circular reference. The compiler now reports it and suggests a
solve.
v0.10.1 26 September 2026
- A phase that doesn't fit a half-yearly step says "isn't a whole number of half-years".
v0.10.0 26 September 2026
- A step per phase.
development 6m step month,construction 18m step quarter,operations 20y step half: the columns change width at each phase boundary. See Timeline. - Fix:
construction 18m step monthused to set the step of the whole timeline, and a secondstepquietly replaced the first. - The tutorial shows the data workbook as
rfn datawrites it and after the profile is typed in.
v0.9.3 26 September 2026
- Rufineer is closed-source commercial software: the licence is now proprietary (all rights reserved) instead of MIT. Nothing else changes.
v0.9.2 26 September 2026
- A tutorial: a 40 MW wind farm built from an empty folder in twelve steps. Its files and the output of every command are replayed by the test suite, so the page always matches the compiler.
- Fix: in 0.9.0 and 0.9.1 a sensitivity case that changed an input without
| grow(capex, a capacity factor, an interest rate) changed nothing, because the model still read the Inputs row instead of the active case. Only escalated inputs, such as a tariff, worked. Rebuild any model with sensitivities.
v0.9.1 26 September 2026
- Fix: the VS Code extension ran the first
rfnon the PATH even when it was an old one (such as a Go build left in~/go/bin), so the editor underlined newer parts of the language, likeveh/y. It now picks therfnof its own version wherever it is, and only falls back to another version (with a warning) if there is none. - Building the extension from source downloads about a quarter as much: the
.vsixis written by a small Ruby script instead of Microsoft'svsce. - The documentation site is built with Ruby (
rake docs). Code in the guide no longer shows"where it means".
v0.9.0 26 September 2026
- Rufineer is written in Ruby. The compiler, the language server (
rfn lsp) and the command-line tool are one Ruby gem (gem install rufineer-0.9.0.gem). The Go compiler is frozen at 0.8.3. - The VS Code extension runs the gem's
rfn, so the terminal and the editor always use the same compiler. It no longer carries compilers of its own; it says whichrfnit runs and warns if that isn't its version. - The language server does what the Go one did: errors as you type, hover with each line's formula in names, go to definition, references, completion, the outline and code lenses.
v0.8.3 26 September 2026
- Fix: the VS Code extension 0.8.1 and 0.8.2 bundled the new
rfnfor Linux only; on macOS and Windows the editor ranrfn0.8.0 (sovehshowed as an error). Every platform now gets the samerfn, and packaging checks it. - The extension shows which
rfnit runs, and its version, in the Rufineer output, and warns if it isn't the extension's version.
v0.8.2 25 September 2026
- Fix: a yes/no line written as a comparison or with
and/orshowed TRUE or FALSE. Excel's SUM leaves those out of a range and SUMIFS never matches TRUE, so in Excel such a line could count as zero: the Express Fiji model showed #DIV/0!. Every yes/no line is now writtenIF(condition, 1, 0), and the test suite rejects any formula that gives TRUE or FALSE.
v0.8.1 25 September 2026
- A toll-road example.
examples/express_fijiis a 40-year highway concession rebuilt from a project finance modelling test: toll revenue by vehicle class, three solve loops (arrangement fee, commitment fee, interest during construction), equity first then debt, level annual instalments, a balance sheet every year, cover ratios and nine sensitivities. It answers the test's question (the heavy-vehicle toll for a 23% equity IRR) and reconciles to the original workbook to the pound. veh(vehicles) is a unit: traffic inveh/y, tolls inGBP/veh.- Fix: a total over time of a line that is a single value (such as the year fraction when every period is a whole year under 30/360) gave 0. A sum is now the value times the number of periods; an average, minimum or maximum is the value.
v0.8.0 25 September 2026
- A project layout.
rfn new my_modelwritesmodel.rfnand three folders that read left to right:inputs/(every number),calculations/(one module per file, one sheet each) andoutputs/(statements, dashboard, sensitivities, checks), plusdata/tables.xlsx. See Project layout. - The new project is a complete, generic model that builds at once: construction, a sculpted loan, tax, statements that balance, returns, a dashboard, sensitivities and checks.
--minimalwrites the folders and one small module. rfn generate module <name>addsinputs/<name>.rfnandcalculations/<name>.rfnand puts the sheet insheets. In VS Code: Rufineer: Add a module…rfn buildwrites tobuild/, so the project holds only sources.- Every command, and the editor, works from any folder inside the project.
v0.7.0 25 September 2026
- Lender-grade models. The compiler now builds what a bank's model reviewer looks for: see Lender-grade models and the hotel example.
next(x), the next period's value, for reserves sized on future debt service. A loop that looks both back and ahead is reported as circular.- Totals over a window:
min(dscr, during: repaying), and the same forsum,avgandmax. irr(flows)andnpv(rate, flows, at: date): Excel's XIRR and XNPV on the period-end dates.- Statements
| at year end(or| at year start), per statement or per row;section "…"rows; rows that add up earlier rows. Balance sheets and cash flow statements follow. dashboard { … }: key results and charts on the Dashboard.sensitivities { … }: cases that multiply or shift inputs, each solved in full by the new RunSensitivities macro and tabulated on a Sensitivities sheet.- Built in the Go and Ruby compilers together: the same workbook, cell for cell.
v0.6.1 25 September 2026
- No more Excel cells in the editor. Someone reading a model shouldn't have to care that revenue is in H23. The hover now shows a line's formula written with the model's own names, including what the compiler added:
energy * inputs.tariff * 1000,… * year_frac,… * operationsfor| during operations. - Code lenses show unit, timing and uses:
USD · per quarter · used in 3 places. Click one to list the places. rfn explainstill shows the sheet, cell and Excel formula, for auditing the workbook. In VS Code it moved out of the right-click menu into the command palette.
v0.6.0 25 September 2026
- The compiler is now written in Go. Every stage was ported and commented to be read in order, one package per step. It builds the same workbook as before: the golden file is unchanged and the two versions agree on every one of 25,981 cells after recalculation. See what the compiler builds today.
- Simpler builds.
go install ./cmd/rfnbuilds the tool; one machine builds the binaries for macOS, Windows and Linux. - The language itself is unchanged.
v0.5.1 24 September 2026
- The compiler exists.
rfnis written in Rust and builds the working core of the language into a FAST-standard workbook: timeline, inputs, tables from the data workbook, lines with unit checking,balance,period,funding,tax_losses,solve, statements and checks. See what the compiler builds today. - VS Code extension. Errors as you type, hover with the Excel cell and formula, go to definition, references, completion, outline and code lenses, from a language server (
rfn lsp). See editor support. - The guide's model is the real one. Your first model now shows the files
rfn newwrites, which the compiler builds and a LibreOffice test recalculates. Four fixes came out of compiling it: interest on half of each period's draw (so IDC really is circular), DSCR only while the loan is outstanding, depreciation over the asset life, and taxable profit only during operations. - One repository. Compiler crates, examples, the extension and this site live together; the examples on these pages are files in
examples/. - Decided: editor support comes with the compiler, not after it.
v0.5 24 September 2026
- Tested against the More Models library. 232 workbooks (2,838 sheets) sampled from 741, up to two per folder, across 12 sectors and 20 structuring topics. The Coverage page lists what each family needs and where Rufineer handles it.
- Rulers. Named time rulers (
ruler finance half ends May, Nov), modulesona ruler, automatic aggregation by unit,| spread even,| holdand| averagefor crossings, andstep day. - Events.
event x = first(…),earned(cash, rate)for flips and hurdles,| at event,| every N of line. - Bands and tiers.
bandsfor sliding scales and R-factors,tieredfor slice-by-slice rates. - Balances.
.availablefor recovering up to a cap. - Deal structures. Partnership
split … amongwith cash, income and credits;capital_account;bondwith yield, duration, WAL and make-whole;refinance;lease;equity_bridge_loan;effective_interest;hedge. - Forward values.
pv_aheadfor LLCR, PLCR, borrowing bases and terminal values;| sampled every 6m. - Targets and loops.
seek … so that …;solve … | by paste | by function | by algebra. - Smaller additions.
| lag,overlap(window),interpolate,sumproduct,weighted_avg, loop filters withwhere, grants as funding sources, probability-weightedresults,vdb,bonusand unit-of-production depreciation, andballoon,bulletandcustomrepayment profiles. - Five more examples from the library.
v0.4 24 September 2026
- Two more examples. Coral Bay Solar (Mexico, peso debt, dual-case sizing, three reporting terms) and Oriole (Mozambique, three phases with storage, tranches, a carried partner).
- Edge cases page. 25 recipes, each tied to the model where it came up.
- Stages.
construction[s],operations[s], and modulesfor s in stageswith one sheet per stage. - Step changes.
step month for 12m, then quarterandstep month until operations.start, then half. Closes the v0.3 open question on mixed steps. - Stub periods.
operations.sharefor a phase that starts part-way through a period. under. A line computed with another scenario's inputs, built on a parallel sheet.split. Partner shares, carried interests and IRR hurdles.whenblocks,functionandexcel "…". Switched features, inlined helpers and an audited escape hatch.- New functions.
pvalue,level,real,ppp;betaandnormalspend profiles;| every 10y,| actuals. - Syntax. Components are called like functions (
senior = term_loan(…)); funding readsfirst … then …; scenarios canextendsanother;columns byany list; a unit can be an option;sheets onefor single-sheet models.
v0.3 24 September 2026
- Inputs on a sheet.
inputs "Plant" sheet "Plant" { capacity_ac: MWac … }declares names and units in Rufineer and reads the values from the data workbook. Closes the v0.2 question on single values. - Day count.
day_countin the model block (act/365,act/360,30/360,months), with a per-line| day_countoverride. - Stale results.
resultstables are stamped with a model fingerprint and checked automatically. - Reconcile. Occurrence index for repeated labels (
[2]) and arowfallback. - Names. Settled: bare names inside a module, qualified names across modules.
- Tooling.
rfn explainadded;rfn dataalso writes sheets for sheet-bound inputs. - Docs. Split into a multi-page site with a first-model guide, a command-line reference and a standard library reference.
v0.2 24 September 2026
- Six real workbooks rebuilt as worked examples: Kestrel, the wind training model, the Mbira toll road, border post and combined models, and the aluminium cable plant.
- One data workbook per model (
data "…xlsx"), one sheet per table, withrowsandcolumnsnaming what the model reads. - Column width per phase (
step) and detail rulers (detail month,monthlymodules) with automatic timeline aggregation. - Currencies and
fx;funding;waterfall;results;snapshot;package;portfolio;reconcile.
v0.1 24 September 2026
- First draft: design principles, timeline and phase flags, units with time conversion, lines and modifiers, balances, groups, statements,
solve, scenarios, checks, components, styling and the Excel mapping.
Open decisions
Decisions still to make before v1.0.
- Name. Rufineer and
.rfnare placeholders. - Risk analysis.
undernow builds parallel cases, which covers P50/P90/P99 side by side. Monte Carlo needs hundreds of cases: should that stay a macro-drivenresultsrun, or be out of scope? - How far
underreaches. Each parallel case copies the lines it depends on. A case that depends on the whole model doubles the workbook. Warn above a size, or refuse? - Escape hatch in packages. Should shared packages be allowed to contain
excel "…"lines, or only models? by functionand the FAST rules. A VBA function keeps the model live but hides the iteration from Excel's formula view. Should it be allowed in lender models, or only in developer and bid models?- Hourly data. 8,760-hour price and generation profiles are reduced to monthly or yearly factors with
sumproduct. Should Rufineer have an hour-of-year dimension instead, for battery dispatch?