Rufineer v0.43.0
Account
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 (its fx line, or the one input quoted in it) or at the one at: names. A cost paid in yuan is capex panels = convert(panels_cny).
  • Forward cover: cny = fx(spot: inputs.cny_per_usd, forward: inputs.cny_forward, hedged: 100 %) | during construction is the rate that converts what is hedged at the forward rate (or spot plus forward points:) and the rest at spot; convert takes 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_refund and vat_facility in the model block, and vat capitalised or vat none after 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 (also tax_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_rate is 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 off leaves 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, its inputs blocks first, then module ops, and one sheet in the workbook; reports.rfn holds the statements, dashboard and sensitivities, and checks.rfn your checks. A module that grows can be a folder: debt/senior.rfn and debt/reserves.rfn each write module debt { … }, one module and one sheet, in the order of sheets [ops, debt/senior, debt/reserves]. The first layout (inputs/ beside calculations/, and outputs/) 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 .zip of a model's folder, and download its files any time (Get started). The rfn command line and the VS Code extension are retired, with rfn 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 0 in the model block, | decimals 2 on 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 quarter and | sum by month, with | at quarter end and | at month end for balances, beside by year and by half; reports by quarter or by month for 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 units block (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: oz and g are units of mass with kg and t, so a gold price in USD/oz times 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: use lines for uses other than capex, classes of shares … up to a commitment and one = rest, a loan's size: 70 % of costs or of uses (solved), signed: base_case, upfront_fee:, commitment_fee: and interest_during_construction: paid, and the order in one place, the model's drawdown: who pays before financial close, then pro_rata on uses (the default), pro_rata on costs, equity_first, debt_first or in_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 funding writes 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: is straight_line, accelerated (by a schedule: [50 %, 25 %, 25 %], the share written off each year) or none (kept at cost, like land); allowance: a tax life or schedule; from: when it starts. The depreciation component takes schedule: 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 offers size:, rate:, repay: … (the required ones first, the ones already written left out), after repay: the ways it can be repaid, after interest_during_construction: paid or rolled_up, and the same in a capex's depreciation: {…} 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 dashboard writes 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, a curl or PowerShell script, Homebrew or go install), and the Rufineer extension for VS Code. Models don't change: the same folders of .rfn files compile to the same workbooks.
  • rfn is 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, and rfn 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 .xlsm with its macros (or a plain .xlsx), built on Rufineer's server, from the preview, from VS Code or with rfn export. Everything else is free (Pricing). Licences, Machine IDs, offline keys and the 14-day trial are gone; an account signs in from rfn login or 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 is rfn. Rename a model's .fin files 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, a reserve) 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 conventions prints them.
  • Loans draw share: or size: of the construction costs, are paid in the order written, have interest during construction capitalised, and by: shareholders makes a shareholder loan; a reserve sits in the waterfall where it is written.
  • Model settings tax, discount, reports and conventions off; any derived line, statement or the dashboard can be replaced by your own.
  • rfn new writes 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: loan takes cash: (paid only as far as the cash goes, with arrears), capitalise: (interest rolled up), repay: sweep and refinance:.
  • Statements by half-year (| sum by half, | at half end), and + module to 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 fmt breaks 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 fmt breaks 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) (and avg, min, max), with at: for another group; sum(table).
  • prev(x, 12): twelve periods back, counting columns.
  • year(d), month(d), date(y, m, d) and round(x, 2).
  • A switch that starts on another case: scenarios design "EPC bid" start bid_b { … }; a label after an input's value.
  • npv of 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_case gives a column per scenario case, picked by the switch; by [one, two, cpi] names columns read with lookup(…, 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, and by_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; tolerance may 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 5y to 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 repaid equal, annuity, bullet or sculpted(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, and llcr(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) ^ 4 lost 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 construction after 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; section inside 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 bag and kg units; 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 @note can follow | grow …; rfn fmt lines up the cases of a scenarios block.

v0.21.2 27 September 2026

  • Fix: the tutorial tests no longer fail on a Mac because of the .DS_Store files 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 rfn and 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:) replaces period, and base_case(…) replaces | base case. The old forms still compile, with a warning.
  • | during and totals take a condition: | during operations.year <= 5, sum(noi, during: operations.year == 2).
  • ramp(from:, over:), after(date) and before(date).
  • converged checks 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, room or key, bed; a night is a day.
  • A number without a unit can't be added to money: revenue + 500 and revenue + inputs.storeys are errors.
  • mirr, multiple and effective: the modified IRR dated like XIRR, the equity multiple, and a yearly rate compounded over the period.
  • funding can 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: depreciation writes 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) and lag(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 .rfn files 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 build writes an .xlsm with 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-macros writes a plain .xlsx and the macros beside it as solve.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.
  • funding sources can have limits (up to) and an order (then), with one rest source last.
  • A date plus a duration is a date: operations.start + 12.5y.
  • Solar units: kWp, MWp, MWac. spread without a profile spreads evenly.

v0.13.0 26 September 2026

  • Tolerances are written with the word tolerance instead 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 solve line 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 month used to set the step of the whole timeline, and a second step quietly replaced the first.
  • The tutorial shows the data workbook as rfn data writes 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 rfn on 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, like veh/y. It now picks the rfn of 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 .vsix is written by a small Ruby script instead of Microsoft's vsce.
  • The documentation site is built with Ruby (rake docs). Code in the guide no longer shows &quot; 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 which rfn it 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 rfn for Linux only; on macOS and Windows the editor ran rfn 0.8.0 (so veh showed as an error). Every platform now gets the same rfn, and packaging checks it.
  • The extension shows which rfn it 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/or showed 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 written IF(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_fiji is 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 in veh/y, tolls in GBP/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_model writes model.rfn and three folders that read left to right: inputs/ (every number), calculations/ (one module per file, one sheet each) and outputs/ (statements, dashboard, sensitivities, checks), plus data/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. --minimal writes the folders and one small module.
  • rfn generate module <name> adds inputs/<name>.rfn and calculations/<name>.rfn and puts the sheet in sheets. In VS Code: Rufineer: Add a module…
  • rfn build writes to build/, 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 for sum, avg and max.
  • irr(flows) and npv(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, … * operations for | during operations.
  • Code lenses show unit, timing and uses: USD · per quarter · used in 3 places. Click one to list the places.
  • rfn explain still 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/rfn builds 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. rfn is 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 new writes, 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), modules on a ruler, automatic aggregation by unit, | spread even, | hold and | average for crossings, and step day.
  • Events. event x = first(…), earned(cash, rate) for flips and hurdles, | at event, | every N of line.
  • Bands and tiers. bands for sliding scales and R-factors, tiered for slice-by-slice rates.
  • Balances. .available for recovering up to a cap.
  • Deal structures. Partnership split … among with cash, income and credits; capital_account; bond with yield, duration, WAL and make-whole; refinance; lease; equity_bridge_loan; effective_interest; hedge.
  • Forward values. pv_ahead for 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 with where, grants as funding sources, probability-weighted results, vdb, bonus and unit-of-production depreciation, and balloon, bullet and custom repayment 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 modules for s in stages with one sheet per stage.
  • Step changes. step month for 12m, then quarter and step month until operations.start, then half. Closes the v0.3 open question on mixed steps.
  • Stub periods. operations.share for 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.
  • when blocks, function and excel "…". Switched features, inlined helpers and an audited escape hatch.
  • New functions. pvalue, level, real, ppp; beta and normal spend profiles; | every 10y, | actuals.
  • Syntax. Components are called like functions (senior = term_loan(…)); funding reads first … then …; scenarios can extends another; columns by any list; a unit can be an option; sheets one for 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_count in the model block (act/365, act/360, 30/360, months), with a per-line | day_count override.
  • Stale results. results tables are stamped with a model fingerprint and checked automatically.
  • Reconcile. Occurrence index for repeated labels ([2]) and a row fallback.
  • Names. Settled: bare names inside a module, qualified names across modules.
  • Tooling. rfn explain added; rfn data also 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, with rows and columns naming what the model reads.
  • Column width per phase (step) and detail rulers (detail month, monthly modules) 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.

  1. Name. Rufineer and .rfn are placeholders.
  2. Risk analysis. under now builds parallel cases, which covers P50/P90/P99 side by side. Monte Carlo needs hundreds of cases: should that stay a macro-driven results run, or be out of scope?
  3. How far under reaches. 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?
  4. Escape hatch in packages. Should shared packages be allowed to contain excel "…" lines, or only models?
  5. by function and 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?
  6. 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?