Institutional-grade underwriting and deal-workflow toolkit for real estate private equity acquisitions. Covers sourcing through closing across multifamily, office, industrial, retail, hospitality, datacenter, and energy infrastructure asset classes, with a paired asset-management library vendored as a git submodule.
Outputs follow Wall Street modeling conventions: multi-tier IRR-hurdle waterfalls, three-basis ROC (untrended / trended / exit-FTM), institutional Excel formatting, and a docx Investment Committee memo generator.
| Asset class | Engine | Example |
|---|---|---|
| Multifamily | scripts/underwriting/pro_forma.py |
examples/marina-apartments.yaml |
| Office / Industrial / Retail | scripts/underwriting/commercial/ (lease-by-lease) |
examples/example-office.yaml, example-industrial.yaml, example-retail.yaml |
| Hospitality | scripts/underwriting/hospitality/ (USALI) |
examples/example-hotel.yaml |
| Datacenter — wholesale | scripts/underwriting/datacenter/wholesale_pro_forma.py |
examples/example-dc-wholesale.yaml |
| Datacenter — colocation | scripts/underwriting/datacenter/colo_pro_forma.py |
examples/example-dc-colo.yaml |
| Infrastructure (solar / wind / BESS) | scripts/underwriting/infrastructure/pro_forma.py |
examples/example-solar-ppa.yaml, example-wind.yaml, example-bess.yaml |
Every engine emits an institutional Excel workbook (executive summary + per-engine detail tabs) and feeds the cross-engine IC memo generator (scripts/underwriting/ic_memo.py).
The datacenter package additionally ships a negotiation playbook (datacenter/negotiation.py) with structured acquisition and lease-tactic catalogs that surface in the IC memo.
The infrastructure engine handles any blend of three revenue streams — contracted PPA (
Requires Python 3.11+. CI runs the test suite on 3.11 / 3.12 / 3.13. Newer versions (3.14) work locally but aren't pinned in CI yet.
git clone --recurse-submodules https://github.com/rubyh218/re-pe-acquisition.git
cd re-pe-acquisition
pip install -r requirements.txt
cp .env.example .env # add ANTHROPIC_API_KEY only if using OM extractionIf you already cloned without --recurse-submodules:
git submodule update --init --recursiveThe submodule at vendor/asset-management/ provides shared helpers (returns, waterfall, debt_metrics, excel_style, docx_style) used by every engine. scripts/__init__.py adds the vendored scripts/ directory to sys.path.
All engines and tools take a YAML deal file.
# Multifamily
python -m scripts.underwriting examples/marina-apartments.yaml -o outputs/marina.xlsx
# Commercial (office / industrial / retail)
python -m scripts.underwriting.commercial examples/example-office.yaml
# Hospitality
python -m scripts.underwriting.hospitality examples/example-hotel.yaml
# Datacenter (dispatches wholesale vs. colo from YAML shape)
python -m scripts.underwriting.datacenter examples/example-dc-wholesale.yaml
python -m scripts.underwriting.datacenter examples/example-dc-colo.yaml
# Energy infrastructure (solar / wind / BESS)
python -m scripts.underwriting.infrastructure examples/example-solar-ppa.yaml
python -m scripts.underwriting.infrastructure examples/example-wind.yaml
python -m scripts.underwriting.infrastructure examples/example-bess.yamlThe IC memo generator auto-dispatches by property.asset_class (with fallback inference from the YAML shape):
python -m scripts.underwriting.ic_memo examples/example-dc-colo.yaml -o outputs/colo-ic-memo.docxSections: cover page, transaction summary, sources & uses, capital structure, pro forma, returns, sensitivities, risk register. Datacenter memos add a tenancy/cabinet-mix section (2a) and a negotiation playbook (section 9). Infrastructure memos add a generation profile + revenue-stream roster + contracted-share-by-year section (2a) and a tax-credit summary.
Convert an Offering Memorandum PDF to a draft deal.yaml using Claude (Sonnet 4.6, native PDF, cached system prompt). The extractor dispatches on --type to the matching engine schema:
python -m scripts.underwriting.extract path/to/om.pdf --type multifamily
python -m scripts.underwriting.extract path/to/om.pdf --type commercial -o draft.yaml
python -m scripts.underwriting.extract path/to/om.pdf --type hospitality
python -m scripts.underwriting.extract path/to/om.pdf --type datacenter_wholesale
python -m scripts.underwriting.extract path/to/om.pdf --type datacenter_colo
python -m scripts.underwriting.extract path/to/om.pdf --type infrastructureEach type uses the corresponding Pydantic Deal schema (multifamily → Deal, commercial → CommercialDeal, hospitality → HotelDeal, etc.). The JSON Schema is generated from the model itself so the extractor stays in sync with the engine when fields change.
If extraction validation fails the tool writes a PARTIAL YAML with TODO markers — the analyst fills the gaps before running an engine. Requires ANTHROPIC_API_KEY in .env.
asset_classes/ Per-class underwriting notes (office, retail, ...)
examples/ Sample deal YAMLs (one per asset class) + reference Excel outputs
inbox/ Drop zone for analyst inputs (CoStar exports, OMs) — gitignored
outputs/ Generated workbooks + IC memos — gitignored
scripts/underwriting/
models.py Pydantic v2 Deal schema (frozen, extra=forbid)
pro_forma.py Multifamily cash flow engine
commercial/ Office / industrial / retail (lease-by-lease)
hospitality/ USALI hotel engine
datacenter/ Wholesale + colo engines + negotiation playbook
infrastructure/ Energy generation engine (PPA / availability / merchant + ITC/PTC)
debt_sizing.py Solves min of LTV / DSCR / DY constraints
waterfall_acq.py Single-tier acquisition waterfall
waterfall_multi.py Multi-tier IRR-hurdle waterfall
metrics.py IRR, MOIC, three-basis ROC
sensitivity.py 2-axis tables
excel_summary.py Shared executive summary tab (engine-agnostic)
excel_writer.py Multifamily Excel builder
om_extractor.py OM PDF -> Deal (Claude Sonnet 4.6)
extract.py OM extraction CLI
ic_memo.py Cross-engine IC memo docx generator
vendor/asset-management/ Git submodule — shared scripts (returns, waterfall, ...)
workflows/ Stage-gated workflow notes (01-sourcing -> 08-handoff)
SKILL.md Claude Code skill manifest (paired tooling)
python -m unittest discover -s tests -v
# or just:
make test87 tests covering ROC math, debt sizing + amortization invariants, the multi-tier waterfall (hand-derived expected values), pydantic schema validation, one end-to-end fixture per asset-class engine, the OM extractor's deal-type dispatch and example round-trips, and the STR comp-set parser. Tests pin the headline numbers each example YAML produces; intentional engine changes need the relevant assertion updated in the PR.
CI runs the suite on every push and pull request against Python 3.11,
3.12, and 3.13 (see .github/workflows/test.yml).
Common dev tasks via Make:
make help # list targets
make setup # create runtime dirs + install deps + init submodule
make test # run the test suite
make smoke # run all five engines against bundled example YAMLs- Returns: levered IRR, MOIC, TVPI, three-basis ROC.
- Waterfall: multi-tier American with IRR hurdles. LP/GP re-attribution by
gp_coinvest_pct. - Debt sizing: most-binding of 65% LTV / 1.25x DSCR / 8% debt yield (defaults; override per deal).
- Hold: 5 years default. Exit cap = entry cap + 25 bps unless specified.
- Currency: USD, no abbreviations in models (write
1000000, not1MM). - Excel formatting: institutional only (no Unicode box chars; cp1252-safe CLI output).
CoStar has no public API, so the toolkit uses a hybrid approach:
- CoStar (sanctioned manual exports): rent comps, sales comps, supply pipeline. Drop XLSX/PDF into
inbox/costar/{type}/; adapters parse and cache. - Free APIs: Census ACS (demographics), BLS QCEW/LAUS (employment), HUD (FMR), FRED (rates/macro).
- STR (hospitality): API subscription TBD. Manual CSV fallback shipped: drop a monthly comp-set CSV in
inbox/str/<property>-compset.csvand runpython -m scripts.market_data.str_manual --csv <path>for RGI / ARI / MPI + T-3/T-6/T-12 windows. Format documented inasset_classes/hospitality.md; reference file inexamples/example-str-compset.csv.
CoStar scraping is a TOS violation — never do it.
MIT — see LICENSE.