Forecasting a company’s accounts and cash flow with an AI assistant

Impromptu
AI
Finance
Teaching
Episode 1 of The Workbench: a five-year income statement, balance sheet and cash-flow forecast for a leveraged buyout — four formulas written by hand, the rest handed to an AI assistant, and a circular system that solves itself.
Author

Luca Erzegovesi

Published

July 9, 2026

Episode 1 of the AI-assisted financial analysis series. I open a half-built leveraged-buyout model, type a few numbers, write four formulas by hand, and then describe — in ordinary English — what the income statement, the balance sheet and the cash-flow statement should do. An AI assistant writes the rest. The three statements depend on each other in a circle, and the engine solves the circle without being asked. This post is the canonical write-up: the video below is the twelve-minute version, and everything here is readable on its own. New readers may want the launch manifesto first; readers who want to know what is actually running should see Impromptu under the hood.


The bench, in one minute

Three things sit on the bench in this episode, and it is worth naming them before we start.

The Workbench is this site: field notes from an ongoing experiment in building small, transparent tools for teaching finance and for probing how AI actually works. The blog is the permanent home; the videos are demonstrations.

Impromptu is the modeling engine on screen. It is a multidimensional spreadsheet in the tradition of Lotus Improv — a tradition that lives on today in Quantrix Modeler, the tool of our Financial Planning Lab at Trento. In a multidimensional spreadsheet you do not write =B7*C7 and drag it down a column. You write Gross Profit = Sales + Raw Materials + Direct Labor Costs, once, over a whole named array, and it applies to every year at once. The formula says what it means. Impromptu is a research prototype, not a product and not a replacement for the tools we teach with; it exists because some questions can only be answered with an instrument you can take apart. Its architecture — a Julia computation server, an Elm browser client, a formula language that compiles to Julia — is the subject of a separate note.

Claude Code is the AI assistant, and the important word is wired. It is not looking at screenshots of the model and guessing. It is connected to the same live engine through MCP (the Model Context Protocol), a standard way for an AI’s host application to reach external tools. So Claude can list the datasets, read the existing formulas, write new ones, trigger a recalculation and read the results back — while I watch every step on screen. When Claude writes a formula, that formula lands in the model the way mine does, in the same language, and I can read it afterwards.

Technical terms are named where they first appear and collected in the glossary at the end. The complete formula set is in Appendix A, so you can rebuild the model yourself in the tool of your choice.

The company is a small manufacturer, bought in a leveraged buyout at the end of 2022 for 196,000 (thousands, throughout), financed with 90,000 of bank debt and 106,000 of sponsor equity. We have 2022 actuals and we want the next four years: what the accounts look like, and where the cash goes.

1. A model is a graph of small matrices

The first surprise for a spreadsheet user is that there is no sheet. There is a list of datasets in the left-hand tree, and each dataset is a small matrix with named axes.

Figure 1: The starter model. On the left, the datasets: assumptions and rate inputs, the sales forecast engine, the debt schedule, and the three empty statements. On the right, SalesCOGS — a matrix whose axes are the six quantity/price line items and the five years.

Each axis is a dimension, and its labels are coordinates. The SalesCOGS dataset in Figure 1 has three dimensions: qtyItem (six coordinates — market size, market share, company sales, average price, and two unit costs), year (2022 through 2026), and scenario (just base today; that axis is where what-if cases will live).

Here is where it diverges sharply from Excel. The line items of the income statement are not rows that happen to contain formulas. They are coordinates of a dimension called ISitem, and the dataset holds one formula per coordinate. Gross Profit is a name the engine knows, not cell B7. Impromptu calls a dimension used this way a coord-formula dimension, and it is the Improv idea in one sentence: the structure of the statement is data, and the formulas attach to that structure by name.

Because the numbers and their labels are the same object, you can re-pivot freely. Drag year out of the columns and into the page tray and you are looking at one year at a time — same model, same formulas, nothing retyped.

Figure 2: The same dataset, re-pivoted: year has been dragged into the page tray at the top, so the grid now shows a single year and the years become a selector. No formula was touched.

The datasets on screen are of two kinds. Four are already wired and we will not touch them: Assumpt (every input assumption, in collapsible groups), Rates (tax rate 35%, cost of debt 6%), SalesCOGS (a driver-led forecast — market size grows 5% a year, our share holds at 10%, average price grows 4%), and FinDebt (a debt schedule we are about to fill in). Three are empty skeletons, and building them is the work of the episode: IS, BS and SCF — the income statement, the balance sheet, the statement of cash flows.

The skeletons have all their structure — every dimension, every line-item coordinate, every group. What they do not have is a single formula. That is deliberate: on camera we fill a skeleton, we do not draw one.

2. A little by hand

Before delegating anything, I want to show that the tool is learnable — that a person can sit down and drive it. So I type some numbers and write four formulas, each chosen to teach one move.

The numbers first. The debt in this deal is pre-determined, so I type the five outstanding balances straight into FinDebt: 90,000 at the close, rising to 100,000 in 2024, then amortizing slightly to 99,000. And in Assumpt I fill the five working-capital drivers — the ones a credit analyst would recognize on sight: 60 days of receivables, 30 days of raw materials, 45 days of finished goods, 15 days of wages payable, 45 days of other payables.

M1 — last year’s value, and another dataset

Interest is last year’s debt times the cost of debt. In the formula editor I type Interest =, then click the Outstanding debt cell rather than typing its name. The editor writes the reference for me. Then I add the positional operator by hand:

Interest = Outstanding debt[year:prev] * Rates.cost of debt
Figure 3: Composing the interest formula. year is marked as a recursive dimension, so the editor offers first, prev, rest inside the brackets — the vocabulary of a roll-forward. Tab accepts.

Two ideas arrive together. [year:prev] means the value of this line in the previous year — you get that vocabulary by marking year as a recursive dimension, and it is how every roll-forward in this model is written. And Rates.cost of debt reaches into a different dataset by name. The model is a graph of small matrices that read each other, not one enormous sheet.

The moment I confirm, the whole row computes — 5,400 in 2023, 5,700, 6,000, 5,880 — because the debt is already there. One formula, five years.

Figure 4: Interest, computed for every year the moment the formula is applied. 2022 is blank because there is no previous year to look back to; the income statement takes its 2022 interest from the actuals instead.

M2 — a formula written by name

Now the income statement, and the pure Improv move:

Gross Profit = Sales + Raw Materials + Direct Labor Costs

I never touch a cell reference. I click the line-item headers, and because those line items are coordinates, the formula is a sentence about the statement. It applies across all five years at once.

And it shows blank — because Sales, Raw Materials and Direct Labor Costs do not exist yet. Hold that thought.

One convention worth stating, because every subtotal in this model depends on it: costs are carried as negative numbers. Raw Materials in 2022 is −16,000, not 16,000. This means every subtotal is a plain sum — no minus signs to remember, no sign errors buried three levels down.

M3 and M4 — a working-capital driver, and a subtotal

Two lines on the balance sheet. Receivables are the classic days-based driver, and again the reference crosses datasets:

accounts receivable = (Assumpt.AR days * IS.Sales) / 365

Then the subtotal. The balance-sheet line items are organized into a collapsible hierarchyAssets contains a NWC group containing receivables, inventories and payables. Impromptu can add up a group by name:

Net working capital = sum_group(NWC)

That is 12,328.8 + 1,315.1 + 3,649.3 − 1,237.0 − 3,180.8 = 12,875.3 in 2022, and it stays correct if I ever add a line to the group. Collapse NWC in the grid and you see a single subtotal row.

The balance sheet also carries two value layers over the same axes — Impromptu calls them arrays. value is the balance, and delta is the year-on-year change, defined once for the whole dataset:

delta = value - value[year:prev]

The cash-flow statement is going to want those changes. This is the second thing a multidimensional spreadsheet gives you that a grid of cells does not: a dataset is a stack of typed layers, not a single sheet of numbers.

Four formulas, maybe three minutes. That is the whole manual lesson, and everything else in this model is the same four ideas repeated.

3. Handing the modeling to Claude

The income statement has thirteen line items and one formula. I could type the other twelve. What I do instead is describe what the statement should do:

The IS dataset has all its line-item coordinates; I have already inserted a formula for one line (Gross Profit); it’s recursive on year, base scenario. Complete the income statement, 2022→2026. 2022 is actuals — the … t0 figures in Assumpt. From 2023 on, drive it off the forecast: revenue = units × price from SalesCOGS; raw-material and direct-labour costs = the same volumes × the unit costs; sales-&-marketing and administrative = their Assumpt percentage of sales. Then EBITDA, depreciation (from the balance sheet’s Depreciation line), EBIT, interest (from FinDebt), pre-tax income, tax at the Rates tax rate, net income. Keep costs negative so every subtotal is a plain sum.

Note what this prompt is not. It is not twenty dictated formulas. It is the description a finance lecturer would give a class — the functional content of an income statement, in the order the statement runs — plus the two conventions that are local to this model (costs negative; 2022 comes from the actuals).

Figure 5: Before: the income statement is a complete skeleton with not one formula in it. Every line item exists as a coordinate; every cell reads zero. Claude, in the right-hand pane, is reading the model’s structure through MCP.

Claude inspects the model first — the datasets, the dimensions, which coordinates exist, what the one existing formula looks like so it can match the style — and then writes the statement.

Figure 6: After. Sales rise from 75,000 to 106,648; EBITDA from 19,100 to 31,877. The Gross Profit line I wrote by hand three minutes ago has filled itself in, because its inputs now exist. In the right pane Claude checks its own work against the 2022 actuals and flags the two lines that are still zero.

Two things happen here that are worth slowing down for.

The first is the payoff of the coordinate idea. I wrote Gross Profit when Sales was nothing but a label. Now Sales has a formula, and my line lights up. I never went back to it. The formula was always a statement about the structure; it simply had nothing to read.

The second is a thread we have to pull. The income statement is complete, and it is not yet true. Look at Depreciation in Figure 6: −4,580 in 2022 (an actual), and zero thereafter. It is zero because I asked for depreciation to come from the balance sheet’s Depreciation line — and there is no balance sheet. So 2023 EBIT reads 23,054 when it should read 17,433, and net income reads 11,475 when it will settle at 7,821.

That is not a bug. That is the first strand of a circular system, hanging loose. Claude noticed it unprompted and said so — it named the two “expected partials” and predicted exactly which lines would move once the balance sheet arrived.

4. The rest of the balance sheet, and the cash flow

The next ask is the bulk of the model, and it goes out in one prompt: finish the operating side of the balance sheet (no financing yet), and build the whole cash-flow statement.

The balance sheet’s operating side is two ideas. The remaining working-capital lines follow the same days-basis as the receivables I wrote by hand — inventories driven by materials and labour cost, payables by labour and admin, and by materials and marketing. And the fixed assets are a roll-forward:

Capital expenditures[year:rest] = Assumpt.capex pct of sales change * (IS.Sales - IS.Sales[year:prev])
Depreciation[year:rest]         = -(Assumpt.avg depreciation on NFA) * (Net fixed assets[year:prev] + Capital expenditures)
Net fixed assets[year:rest]     = Net fixed assets[year:prev] + Capital expenditures + Depreciation

Read the middle line closely, because it is the loop closing. The rate is not the statutory one a tax code applies to an asset’s gross cost; it is an average rate applied to the net asset base — last year’s net fixed assets plus this year’s capex. That base depends on capex; capex depends on the increase in sales; sales are in the income statement; and the income statement subtracts this very depreciation. We are now going around in a circle, on purpose.

The cash flow is the indirect method, built from the income statement, the balance sheet’s delta layer, and the debt schedule. Start from EBIT, tax it as if the firm had no debt, add back depreciation (a non-cash charge), subtract the cash absorbed by working capital and by capex. That is FCFF, the free cash flow to the firm — 9,660 in 2023. Then add net borrowing and subtract the after-tax interest the debt actually costs, and you have FCFE, the free cash flow to equity: 11,150 in 2023.

And then a modeling decision that deserves to be said out loud, because it is the reason this model closes without a solver:

Dividends[year:rest]                = ifelse(FCFE>0, -FCFE, 0)
Sale or Purchase of Stock[year:rest] = ifelse(FCFE<0, -FCFE, 0)
NCF[year:rest]                       = FCFE + Dividends + Sale or Purchase of Stock

Every year’s free cash flow to equity is fully absorbed. If it is positive it goes out as a dividend; if it is negative the sponsor covers it with a stock issue. So net cash flow is zero, every year, and cash sits exactly where it started: 16,500. The Excess cash and Bank overdraft lines are wired and ready, but in this base case they never move.

This is a choice, not a law of accounting. A real LBO model would sweep cash against the debt and you would watch the balance grow. Here I want the cleanest possible demonstration of a circular system converging, so I fix the cash policy and let the equity account absorb everything. Relax the absorption rule and the imbalance would reappear as excess cash or an overdraft — which is what those two lines are for, in a later episode.

At this point the balance sheet has assets and no equity. It does not balance, and Claude says so.

5. Closing the circular loop

One more ask: make it balance.

There are three moves. Pull cash and the financing flows over from the cash-flow statement. Set the opening equity to the sponsor’s cheque — the purchase price net of the debt drawn:

Sale or Purchase of Stock[year:first] = Assumpt.equity purchase price - Financial debt

That is 196,000 − 90,000 = 106,000. Then roll stockholders’ equity forward the way equity actually rolls forward — opening balance, plus net income, minus dividends, plus any stock issued:

Stockholders Equity[year:first] = Sale or Purchase of Stock
Stockholders Equity[year:rest]  = Stockholders Equity[year:prev] + Net Income + Dividends + Sale or Purchase of Stock

For 2023 that reads 106,000 + 7,821 − 11,150 = 102,672. The company is profitable and its equity falls, because it pays out more than it earns. That is the LBO in one line.

And finally the plug. At the close, the sponsor paid 196,000 for a business whose identifiable net operating assets are worth 62,875 and which holds 16,500 of cash. The difference has to live somewhere on the balance sheet, and its name is goodwill:

Goodwill[year:first] = (Financial debt + Bank overdraft + Stockholders Equity) - (Total net operating assets + Excess cash)
Goodwill[year:rest]  = Goodwill[year:prev]

which comes to 196,000 − 62,875 − 16,500 = 116,625, carried forward unchanged. Add Total assets, Total Liabilities and Equity, and a check line — Unbalance, the difference between them — and we are done.

Now count the circles. Depreciation runs from the balance sheet into the income statement. Net income runs from the income statement into the balance sheet’s equity. The cash-flow statement reads both of them, and its dividends and stock issues run back into the equity roll-forward, while its cash lands back on the balance sheet. The three statements are a simultaneous system: none of them can be computed before the other two.

In a conventional spreadsheet this is the moment you find the enable iterative calculation checkbox, or you break the loop by hand with a lagged variable and hope nobody notices. Impromptu does neither. When the model is loaded, the engine works out the dependency order of the datasets by itself, discovers that IS, BS and SCF form a cycle group, and iterates that group to a fixed point — up to 100 passes, stopping when nothing moves by more than one part in ten billion. There is no switch to enable. There is no circular-reference warning. The circularity is a property of the accounting, so the engine treats it as a property of the accounting.

Figure 7: Unbalance reads 0.00000 for every year. Assets of 196,000 at the close grow to 206,247 by 2026. Stockholders’ equity dips — 106,000 at the close, down to 99,956 by 2024 as dividends outrun earnings, then back to 107,247 by 2026. Claude’s own commentary on the right walks through the equity roll-forward it just wrote.

It balanced on the first attempt. I want to be precise about what that does and does not demonstrate. It does not demonstrate that an AI can do accounting by intuition. It demonstrates that when a model is built out of named things — when Net working capital is a coordinate and not cell C14 — an assistant that can read the structure has enough information to write formulas that are consistent with it. The names carry the meaning. That is the whole argument of this site, and here it is doing visible work.

6. A report the model writes about itself

The last ask is a write-up, and it is worth showing because of what a report is in Impromptu.

Figure 8: The report source. Prose interleaved with live blocks: dataset: BS, view: BS_subtotals pulls the collapsed balance sheet straight out of the model, and {...} expressions interpolate live numbers into the sentences.

A report is not an export. It is a document that lives inside the model, and its tables and charts are references to datasets and views rather than pasted copies of them. The interpolated numbers in the intro — the purchase price, the goodwill plug, 2026 EBITDA — are expressions evaluated against the live model. Change an assumption and the prose updates with the tables, because they are reading the same arrays.

Figure 9: The rendered report: an intro whose figures are computed, the income statement, the balance sheet collapsed to its subtotals, the cash-flow statement, and a chart of Sales, EBITDA and net income — all sourced from the model’s own views.

7. It’s alive

To close, the demonstration that any spreadsheet user will demand. Average sales-price growth is an assumption: 4% a year. I change it to 12% and press nothing.

Every number downstream moves. Sales rise, so receivables rise, so the capex that tracks the sales increase rises, so depreciation rises, so EBIT and net income move, so the dividend moves, so equity moves. The engine re-solves the circular system, and Unbalance still reads zero for every year.

That is the payoff of building the thing properly. A model that balances once is an artifact. A model that balances for every input you throw at it is an instrument — and that is what makes the scenario axis, sitting there with a single base coordinate, worth having.

8. What it cost

The video is edited: Claude’s thinking and tool calls are fast-forwarded, so the runtime you watch is not the runtime I lived. Here are the session’s real figures, from the assistant’s own usage panel.

Figure 10: The session’s usage panel, quoted rather than paraphrased.
  • Total cost: $6.65.
  • Wall-clock: 3 hours 21 minutes 54 seconds — a working afternoon, most of it me thinking, re-recording takes and deciding what to ask next.
  • API time: 14 minutes 57 seconds. That is the time the model actually spent working.
  • Tokens: roughly 5.0 million, of which 4.7 million were cache reads — the model re-reading a conversation and a model structure it had already been shown. Only 69.8 thousand tokens were output: the formulas, the checks, and the explanations.
  • Lines of code written: zero. Nothing about the engine was touched. Everything Claude did, it did through the model’s own interface.

Six dollars and fifteen minutes of machine time to build a three-statement forecast that balances. I report this not because it is cheap — though it is — but because the number should be reported. An AI assistant in a financial workflow has a price and a duration, and both belong in the write-up next to the results. The ratio between the wall-clock and the API time is the honest picture of what this work is: the assistant is fast, and the human deciding what to ask is the slow part.

Where this goes next

We have the flows. We do not yet have a value. Episode 2 turns this forecast into a company valuation — a continuation value, then the adjusted-present-value and weighted-average-cost-of- capital routes to an enterprise value consistent with the financing structure, the flow-to-equity check that comes free once you have FCFE, and the sponsor’s equity IRR.

New episodes go up on the YouTube channel. Everything permanent lives here.


Appendix A: the formulas, in full

The complete formula set of the finished model, dataset by dataset, in the engine’s calculation order. Rates holds only inputs and appears nowhere below. Anything not listed here is a typed input, not a formula.

A note on reading these. A bare name is a coordinate of this dataset. Dataset.name reaches into another dataset. [year:first], [year:rest] and [year:prev] are the positional operators of the recursive year dimension: the first period, all periods after the first, and the previous period. A formula with no positional qualifier applies to every year.

Assumpt — derived unit economics

The assumptions are inputs; these four lines derive the unit economics from the 2022 actuals.

market share            = company sales 000units / market size 000units
avg sales price         = Sales t0 / company sales 000units
raw material unit cost  = -Raw Materials t0 / company sales 000units
direct labor unit cost  = -Direct Labor Costs t0 / company sales 000units

SalesCOGS — the driver-led sales forecast

market size 000units[year:first]   = Assumpt.market size 000units
market size 000units[year:rest]    = market size 000units[year:prev] * (1 + Assumpt.market size g)
market share[year:first]           = Assumpt.market share
market share[year:rest]            = market share[year:prev] * (1 + Assumpt.market share g)
company sales 000units             = market size 000units * market share
avg sales price[year:first]        = Assumpt.avg sales price
avg sales price[year:rest]         = avg sales price[year:prev] * (1 + Assumpt.avg sales price g)
raw material unit cost[year:first] = Assumpt.raw material unit cost
raw material unit cost[year:rest]  = raw material unit cost[year:prev] * (1 + Assumpt.raw material unit cost g)
direct labor unit cost[year:first] = Assumpt.direct labor unit cost
direct labor unit cost[year:rest]  = direct labor unit cost[year:prev] * (1 + Assumpt.direct labor unit cost g)

FinDebt — the debt schedule

Outstanding debt is typed in by hand. One formula:

Interest = Outstanding debt[year:prev] * Rates.cost of debt

BS — the balance sheet

Two arrays over the same axes: value (the balances) and delta (the year-on-year change). The last line defines the whole delta layer at once.

accounts receivable       = (Assumpt.AR days * IS.Sales) / 365
raw materials             = (-(Assumpt.raw materials days) * IS.Raw Materials) / 365
finished goods            = (-(Assumpt.finished goods days) * (IS.Raw Materials + IS.Direct Labor Costs)) / 365
wages payable             = (Assumpt.wages payable days * (IS.Direct Labor Costs + IS.Administrative)) / 365
other accounts payable    = (Assumpt.other AP days * (IS.Raw Materials + IS.Sales and Marketing)) / 365
Net working capital       = sum_group(NWC)

Net fixed assets[year:first]    = Assumpt.initial net fixed assets
Capital expenditures[year:rest] = Assumpt.capex pct of sales change * (IS.Sales - IS.Sales[year:prev])
Depreciation[year:rest]         = -(Assumpt.avg depreciation on NFA) * (Net fixed assets[year:prev] + Capital expenditures)
Net fixed assets[year:rest]     = Net fixed assets[year:prev] + Capital expenditures + Depreciation
Total net operating assets      = Net working capital + Net fixed assets

Excess cash    = SCF.Excess cash
Bank overdraft = - SCF.less Bank overdraft
Goodwill[year:first] = (Financial debt + Bank overdraft + Stockholders Equity) - (Total net operating assets + Excess cash)
Goodwill[year:rest]  = Goodwill[year:prev]
Total assets         = Total net operating assets + Goodwill + Excess cash

Financial debt = FinDebt.Outstanding debt
Net Income     = IS.Net income
Dividends      = SCF.Dividends
Sale or Purchase of Stock[year:first] = Assumpt.equity purchase price - Financial debt
Sale or Purchase of Stock[year:rest]  = SCF.Sale or Purchase of Stock
Stockholders Equity[year:first]       = Sale or Purchase of Stock
Stockholders Equity[year:rest]        = Stockholders Equity[year:prev] + Net Income + Dividends + Sale or Purchase of Stock
Total Liabilities and Equity          = Financial debt + Bank overdraft + Stockholders Equity

Unbalance = Total assets - Total Liabilities and Equity

delta = value - value[year:prev]

SCF — the statement of cash flows

The indirect method. Everything is [year:rest]: there is no cash-flow statement for the opening year, only a cash position.

EBIT[year:rest]                          = IS.EBIT
less Taxes on EBIT[year:rest]            = -EBIT * Rates.tax rate
Unlevered Net Income[year:rest]          = EBIT + less Taxes on EBIT
plus Depreciation[year:rest]             = -(IS.Depreciation)
less Changes in NWC[year:rest]           = -(BS.delta[Net working capital])
less Capex[year:rest]                    = -(BS.Capital expenditures)
FCFF[year:rest]                          = Unlevered Net Income + plus Depreciation + less Changes in NWC + less Capex

Plus net borrowing[year:rest]            = BS.delta[Financial debt]
less After tax Findebt interest[year:rest] = -(FinDebt.Interest) * (1 - Rates.tax rate)
FCFE[year:rest]                          = FCFF + Plus net borrowing + less After tax Findebt interest

Dividends[year:rest]                     = ifelse(FCFE>0,-FCFE,0)
Sale or Purchase of Stock[year:rest]     = ifelse(FCFE<0,-FCFE,0)
NCF[year:rest]                           = FCFE + Dividends + Sale or Purchase of Stock

Net cash[year:first]   = Assumpt.initial total cash
Net cash[year:rest]    = Net cash[year:prev] + NCF
Excess cash            = ifelse(Net cash>0, Net cash, 0)
less Bank overdraft    = ifelse(Net cash<0, Net cash, 0)

NCF via Income and BS delta = (IS.Net income - (BS.delta[Net working capital] + BS.delta[Net fixed assets])) + BS.delta[Financial debt] + Dividends + Sale or Purchase of Stock

That last line is a free consistency check: it recomputes net cash flow from an entirely different direction — net income less the increase in operating assets, plus net borrowing and the financing flows — and it reads zero, like NCF itself.

IS — the income statement

Sales[year:first]                          = Assumpt.Sales t0
Sales[year:rest]                           = SalesCOGS.company sales 000units * SalesCOGS.avg sales price
Raw Materials[year:first]                  = Assumpt.Raw Materials t0
Raw Materials[year:rest]                   = -(SalesCOGS.company sales 000units) * SalesCOGS.raw material unit cost
Direct Labor Costs[year:first]             = Assumpt.Direct Labor Costs t0
Direct Labor Costs[year:rest]              = -(SalesCOGS.company sales 000units) * SalesCOGS.direct labor unit cost
Gross Profit                               = Sales + Raw Materials + Direct Labor Costs
Sales and Marketing[year:first]            = Assumpt.Sales and Marketing t0
Sales and Marketing[year:rest]             = -Sales * Assumpt.sales mktg expense on sales
Administrative[year:first]                 = Assumpt.Administrative t0
Administrative[year:rest]                  = -Sales * Assumpt.admin expense on sales
EBITDA                                     = Gross Profit + Sales and Marketing + Administrative
Depreciation[year:first]                   = Assumpt.Depreciation t0
Depreciation[year:rest]                    = BS.Depreciation
EBIT                                       = EBITDA + Depreciation
Interest on financial debt[year:first]     = Assumpt.Interest expenses t0
Interest on financial debt[year:rest]      = -FinDebt.Interest
Pre tax income                             = EBIT + Interest on financial debt
Income taxes                               = -Pre tax income * Rates.tax rate
Net income                                 = Pre tax income + Income taxes

Appendix B: Glossary

Impromptu and software

Dataset

A named matrix. Not a sheet of A1/B2 cells, but a small array with named axes. A model is a handful of datasets that read each other.

Dimension and coordinate

Every axis of a dataset is a dimension; the labels along it are coordinates. The income statement’s dimensions are ISitem (its line items), year and scenario; Gross Profit is a coordinate, and 2024 is a coordinate.

Coord-formula dimension (cfd)

A dimension whose coordinates each carry their own formula. Because the line items of a statement are coordinates, you write one formula per line, by name — Gross Profit = Sales + Raw Materials + Direct Labor Costs — and it applies across every year and scenario at once. This is the Lotus Improv idea, and it is why the formulas in this post read like accounting rather than like cell arithmetic.

Recursive dimension

A dimension, usually time, marked as ordered so that formulas can look along it. Marking year as recursive gives you the positional operators [year:first] (the opening period), [year:prev] (the previous period) and [year:rest] (every period after the first) — the vocabulary of a roll-forward.

Cross-dataset reference

A reference by name into another dataset: Rates.cost of debt, IS.Sales, BS.delta[Net working capital]. The bracket form selects one coordinate from a specific value layer. The model is a graph of small matrices rather than one giant sheet, and these references are its edges.

Array (value layer)

A dataset can hold several typed value layers over the same axes. The balance sheet carries two: value, the balances, and delta, the year-on-year change. delta = value - value[year:prev] is one formula that defines an entire layer.

DimGroups and sum_group

Coordinates fold into a collapsible hierarchy — Assets contains NWC contains accounts receivable. sum_group(NWC) aggregates a group by name, so the subtotal stays correct when a line is added to the group, and collapsing the group in the grid shows one row.

Pivot trays

The strips above the grid that hold each dimension. Drag a dimension between the row tray, the column tray and the page tray and the same numbers are re-arranged. No formula is retyped, because formulas were never written against a layout.

Cycle group

A set of datasets that depend on each other in a circle. The engine finds them, then iterates the group to a fixed point — here, at most 100 passes, stopping when no value moves by more than 10^{-10} in relative terms. IS, BS and SCF are one cycle group.

MCP (Model Context Protocol)

A standard by which an AI assistant’s host application connects to external tools and data. Here it is the bridge that lets Claude list datasets, read and write formulas, recalculate and read results back — operating the live model rather than describing one.

Finance

LBO (leveraged buyout)

The purchase of a company financed largely with borrowed money, where the acquired company’s own cash flows service the debt. Here: 196,000 of purchase price, 90,000 of it debt.

Working-capital days

A driver that expresses a balance as a number of days of the flow that produces it. accounts receivable = AR days × Sales / 365 says customers pay in 60 days. Inventories are expressed in days of the costs that build them; payables in days of the costs they finance.

Indirect cash-flow method

Deriving cash flow from accrual accounts rather than from a cash ledger: start from operating profit, add back non-cash charges like depreciation, and subtract the cash absorbed by increases in working capital and by capital expenditure. It is the method that lets a cash-flow statement fall out of an income statement and a balance sheet.

FCFF and FCFE

Free cash flow to the firm is the cash the operations generate for all providers of capital, computed as if the firm had no debt: NOPAT + depreciation − ΔNWC − capex. Free cash flow to equity is what is left for shareholders after the debt is served: FCFF + net borrowing − after-tax interest.

The goodwill plug

When a buyer pays more than the identifiable net assets are worth, the difference is capitalized as goodwill so the opening balance sheet balances. Here 196,000 paid − 62,875 of net operating assets − 16,500 of cash = 116,625 of goodwill, carried forward unchanged.

Roll-forward

Any balance defined as opening balance + additions − subtractions = closing balance. Fixed assets roll forward with capex and depreciation; equity rolls forward with net income, dividends and stock issues. In a recursive dimension a roll-forward is one line: X[year:rest] = X[year:prev] + inflow - outflow.

Average depreciation rate on the net asset base

The rate this model applies — 10% of net fixed assets (last year’s closing balance plus this year’s capex), not the statutory rate a tax code applies to an asset’s gross cost over a fixed life. It is a planning shortcut: one rate standing in for a whole schedule of assets of different ages and lives, which is what you want in a five-year forecast and not what you would file with the tax authority.

The unbalance check

A line whose formula is Total assets − Total Liabilities and Equity and whose only acceptable value is zero. A model without one is a model whose author has not checked.

FCFE absorption

The cash policy used in this model: every year’s free cash flow to equity is paid out as a dividend if positive, or covered by a stock issue if negative, so net cash flow is zero and cash never moves. It is a deliberate simplification that lets the circular system close without a solver. Relax it and the residual reappears as excess cash or a bank overdraft — the two lines sitting quietly at the bottom of the balance sheet.


Written with substantial help from Claude (Anthropic); directed, reviewed, and verified by me.