DCF valuation engine

SkillAI & models

Runs an intrinsic (discounted cash flow) valuation from value drivers — builds the year-by-year forecast with fading growth, margins and reinvestment, closes it with a terminal value, adjusts for failure risk, walks the bridge from operating assets to equity value per share, and runs sensitivity grids. Also reverse-engineers the market price into the growth or margin it already assumes. Use when valuing a company intrinsically, building a DCF or FCFF/FCFE model, computing terminal value or value per share, running valuation sensitivity, or asking what the market is pricing in.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the DCF valuation engine skill

What this skill tells your AI

The instructions your AI receives, as published by lyndonkl/claude in skills/dcf-valuation-engine/SKILL.md and read by ahel’s review.

A discounted cash flow valuation is four judgments and a lot of arithmetic. The judgments are how fast revenue grows, what margin it eventually earns, how much capital that growth costs, and how risky the whole thing is. The arithmetic is here, so you can spend your effort on the four numbers that actually decide the answer.

The engine never invents a driver. Every growth rate, margin and reinvestment assumption arrives as an input you chose and can defend.

The script

resources/dcf.py — pure standard library, no installation needed. JSON on stdin (or --in FILE), JSON out.

python3 resources/dcf.py value --example        # show the input shape
python3 resources/dcf.py value --in drivers.json
python3 resources/dcf.py selftest               # verify the engine
SubcommandPurpose
valuedrivers → forecast, terminal value, equity bridge, value per share
sensitivityre-run across a grid of one or two drivers
impliedsolve for the driver that makes the DCF equal the market price

The input

Three ways to state a driver, so a fading assumption stays one line:

  • a number — constant every year: "tax_rate": 0.25
  • a list — one entry per year: "revenue_growth": [0.4, 0.3, 0.2, 0.1, 0.05]
  • a glide — {"start": 0.40, "end": 0.03, "converge_by": 8} moves linearly from start to end by year 8, then holds

A glide is usually what you want for growth, margin and cost of capital. Real companies converge toward their industry; a company growing 40% in year 1 and 40% in year 10 is almost always a modelling error rather than a forecast.

{
  "base_revenue": 10000, "base_ebit": 800, "base_invested_capital": 6000,
  "forecast_years": 10,
  "revenue_growth": {"start": 0.25, "end": 0.03, "converge_by": 10},
  "operating_margin": {"start": 0.08, "end": 0.15, "converge_by": 7},
  "sales_to_capital": 2.0,
  "tax_rate": {"start": 0.15, "end": 0.25, "converge_by": 10},
  "cost_of_capital": {"start": 0.09, "end": 0.075, "converge_by": 10},
  "terminal": {"growth_rate": 0.025, "cost_of_capital": 0.075, "return_on_capital": 0.10},
  "bridge": {"debt": 3000, "cash": 1200, "minority_interests": 0,
             "non_operating_assets": 0, "employee_options_value": 0,
             "shares_outstanding": 500, "current_price": 42.00},
  "currency": "USD"
}

Set currency to the same currency as the cost of capital. The consistency validator checks this and it is the single most common silent error in DCF work.

How the engine computes each year

Revenue grows at the stated rate. Operating income is revenue times the margin. Tax applies to operating income, with any loss carryforward absorbing income first. Then the part people skip:

reinvestment = (this year's revenue − last year's revenue) / sales-to-capital
FCFF = after-tax operating income − reinvestment

Growth is not free. The sales-to-capital ratio says how many dollars of revenue each dollar of capital buys, so it converts a growth assumption into the investment that growth requires. A model that grows revenue without reinvesting is manufacturing value out of nothing, and it is the most common way a DCF ends up too high.

Set net_operating_loss_carryforward when the company has accumulated losses. The engine shelters income until the carryforward is used up.

Terminal value

Beyond the forecast horizon the company becomes a perpetuity:

terminal value = terminal FCFF / (terminal cost of capital − terminal growth)

Three rules the engine enforces by refusing to run:

  1. Terminal growth cannot exceed the riskfree rate. A company growing faster than the economy forever eventually becomes the economy. The riskfree rate is the practical ceiling because it already contains expected inflation plus real growth.
  2. Terminal cost of capital must exceed terminal growth, or the formula does not produce a finite number.
  3. Terminal growth must be paid for: reinvestment rate = growth / return on capital. The engine computes this rather than accepting it, and refuses a combination that would require reinvesting more than 100% of income.

Set terminal.return_on_capital deliberately. Setting it equal to the cost of capital says competition eventually arrives — the honest default. Setting it higher says this company holds a barrier to entry forever, which needs naming.

Failure risk

A going-concern DCF prices only the branch where the company survives. For a young company or a distressed one, that overstates value:

"failure": {"probability": 0.20, "proceeds_basis": "book_value",
            "book_value_of_capital": 4000, "proceeds_percent": 0.5}
value = going-concern value × (1 − p) + distress proceeds × p

Use book_value as the basis when a failed firm would be liquidated piecemeal, and going_concern when it would be sold intact at a discount.

The bridge

Operating assets are not equity. The walk:

equity value = operating assets − debt − minority interests + cash + non-operating assets
equity in common = equity value − value of employee options
value per share = equity in common / shares outstanding

Value employee options properly with option-valuation-toolkit and pass the result in. Inflating the share count instead understates the cost of options; ignoring them overstates value per share.

Do not add a control premium here and do not divide by diluted shares if you already subtracted option value — that double-counts.

Sensitivity and reverse engineering

A point estimate implies a false precision. Show a range.

python3 resources/dcf.py sensitivity --in grid.json

Point axes at any leaf with a dotted path — terminal.growth_rate, operating_margin.end, cost_of_capital — and give the values to sweep. Sweep the drivers that actually move the answer, which for most companies are the target margin and the terminal assumptions rather than near-term growth.

The implied subcommand runs the valuation backwards: given the market price, what must be true for that price to be right?

echo '{"base_case": {...}, "path": "operating_margin.end",
       "target_value_per_share": 42.00, "low": 0.01, "high": 0.40}' \
  | python3 resources/dcf.py implied

This is often the most useful output in the whole analysis. "The stock is worth $31 and trades at $42" invites an argument about your assumptions. "At $42 the market assumes this company reaches a 22% operating margin, which no firm in the industry has ever sustained" is a claim about the world, and it is checkable.

Choosing the model

This engine values the firm from operating cash flows (FCFF), discounted at the cost of capital. That is the right default for most non-financial companies, and the only sensible choice when leverage is changing.

Use something else when:

SituationUse instead
Financial service firmDividends or excess return, valuing equity directly — debt is raw material for a bank, so there is no meaningful cost of capital. Use special-situation-models
Stable leverage, equity questionFCFE discounted at the cost of equity
Mature dividend payer that pays out what it canDividend discount model
Negative earnings, no path to profit modelledRevenue-driven build with failure probability. Use special-situation-models
Deeply distressed, equity is an optionEquity as a call. Use option-valuation-toolkit

Before accepting the answer

Run the validator in valuation-consistency-checks. Then read the output for these tells:

  • Terminal value above 90% of total value. The forecast horizon is too short, or the company is genuinely all-option and a DCF is the wrong tool.
  • ROIC climbing every year with no explanation. Check that reinvestment is keeping up.
  • Value per share wildly different from price. Usually the model, not the market. Run implied and see whether the market's assumption is defensible before concluding the market is wrong.
  • Margins that never converge. Very few businesses out-earn their industry forever.

Common failures

SymptomCause
Value far too highGrowth without matching reinvestment; sales-to-capital set too high
Terminal value is most of the answerForecast horizon too short for a company still growing fast
Value changes when currency changesCash flows and discount rate in different currencies
Engine refuses to runTerminal growth above the discount rate, or reinvestment above 100% — both are real errors, not obstacles
Value per share negativeDebt exceeds operating asset value; the company may be a distress case needing the option approach
Young company looks worth billionsNo failure probability applied

Signals

GitHub stars
158
Forks
23
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
dcf-valuation-engine
Source
github.com/lyndonkl/claude